Configura la consegna diretta delle email in entrata per siti self-hosted con Mail-Receiver

Come si disabilita esattamente il supporto DMARC?

Ad esempio, aggiungere INCLUDE_DMARC: false alla sezione env di mail-receiver.yml non sembra funzionare. Questo sembra causare il mancato avvio dei demoni opendkim e opendmarc (portando a un avviso nei log), ma il controllo SPF viene ancora eseguito.

Modificato per aggiungere:
Penso di essere riuscito a disabilitare i controlli SPF aggiungendo anche la seguente riga POSTCONF_ alla sezione env:

env:
  ...
  INCLUDE_DMARC: false
  POSTCONF_smtpd_recipient_restrictions: check_policy_service unix:private/policy
  ...

Ho ottenuto questo esaminando il commit che ha introdotto i controlli DMARC, e vedendo cosa dovrebbe succedere quando INCLUDE_DMARC è falso.

So pochissimo su come vengono costruite le immagini docker, ma ho l’impressione che il flag INCLUDE_DMARC sia qualcosa che deve essere impostato da qualcun altro, da qualche altra parte, in un altro momento — non qualcosa che può essere fatto in mail-receiver.yml.

2 Mi Piace

Ho riscontrato la necessità di aprire la porta 443 su ufw — altrimenti ricevo API Request Preparation Failed nei logs. Ho pensato che fosse meglio menzionarlo perché le istruzioni di installazione standard menzionano l’abilitazione di ufw.

La porta 25 è menzionata in mail-receiver.yml e sembra bypassare ufw.

1 Mi Piace

La repository di GitHub dovrebbe essere nell’OP?

3 Mi Piace

Utenti di mail-receiver, consultate Remove smtp_should_reject & discourse-smtp-fast-rejection

Rimuoveremo completamente il rifiuto rapido (fast-rejection) poiché la funzionalità originale era difettosa e causava problemi agli utenti, in particolare questo tipo di cosa:

e influisce anche sulla posta inoltrata poiché il test pre-consegna controllava envelope-from e envelope-to, mentre Discourse utilizza solo i valori nelle intestazioni.

1 Mi Piace

Ho appena inviato questa PR per rimuovere le virgolette non necessarie attorno al valore di DISCOURSE_BASE_URL nel file di esempio mail-receiver.yml. Le virgolette stavano causando problemi alla mia configurazione. Rimuoverle consente il completamento con successo di questo documento.

Puoi spiegare come? La presenza/assenza di virgolette attorno a questo valore non produce alcuna differenza:

[2] pry(main)=> YAML::load("env:\n  DISCOURSE_BASE_URL: 'https://discourse.example.com'")
=> {"env"=>{"DISCOURSE_BASE_URL"=>"https://discourse.example.com"}}

[3] pry(main)=> YAML::load("env:\n  DISCOURSE_BASE_URL: https://discourse.example.com")
=> {"env"=>{"DISCOURSE_BASE_URL"=>"https://discourse.example.com"}}

Quando ho seguito i log da quel container e gli ho inviato messaggi, ho visto un sacco di errori che menzionavano qualcosa come discourse.example.com non fa parte dei record MX o simili. Ho rimosso le virgolette, ricostruito il container e ha iniziato a funzionare :person_shrugging:

Anche la sequenza degli eventi potrebbe essere importante:

  1. Ho configurato e avviato il container mail-receiver
  2. Alcuni giorni dopo ho impostato i record DNS MX
  3. Ho verificato che i record MX fossero impostati correttamente e poi ho iniziato a testare. Non funzionava
  4. Ho rimosso le virgolette, ricostruito il container, ha iniziato a funzionare

Quindi non sono sicuro se la risoluzione fosse correlata alla rimozione delle virgolette, o alla ricostruzione del container dopo la creazione dei record MX.

Nel peggiore dei casi, la PR rende il file yml coerente :slight_smile:

1 Mi Piace

Sembra che ci sia l’assunto che il destinatario della posta sarà sempre lo stesso dominio del forum di base. Quando questo non è il caso, come si configura TLS?

Per esempio:
forum => forum.domain.tld
mail-receiver => mail.domain.tld

In mail-receiver.yml, il TLS punta ai certificati del forum di base. C’è un modo per far sì che mail-receiver ottenga i propri certificati?

Non conosco la risposta diretta, anche se sospetto che richiederebbe opzioni aggiuntive nello yml per apportare modifiche nel container durante la compilazione.

Maggiori informazioni a riguardo seguiranno, ma mi chiedo quale sia il motivo per cui si desidera eseguirlo su un dominio diverso. Il mail-receiver è fortemente personalizzato e, senza modifiche, funziona esclusivamente per ricevere email per un’istanza Discourse abbinata, quindi è generalmente ragionevole farlo operare sullo stesso dominio di tale istanza.


Se dai un’occhiata ad alcuni dei template da includere nel tuo yml di Discourse, alcuni dei quali saranno già utilizzati, dovresti essere in grado di ottenere alcuni suggerimenti su come eseguire comandi e modificare file tramite lo yml (durante la compilazione del container).

web.onion.template.yml contiene alcuni esempi su come sostituire stringhe all’interno dei file e web.letsencrypt.ssl.template.yml è quello che aggiunge Let’s Encrypt al container principale di Discourse.

Non so quanto di questo dipenda dalle cose nell’immagine base, quindi potenzialmente potrebbe essere più semplice far sì che il container principale di Discourse ottenga un secondo certificato, quindi cambiare i percorsi del certificato/chiave in mail-receiver.yml di conseguenza.

Fai attenzione a questo tipo di modifiche se adotti questo approccio, assicurandoti di sapere esattamente quale effetto avrà la modifica. Una modifica errata nelle impostazioni di Let’s Encrypt potrebbe portare a un mancato rinnovo dei certificati, ad esempio, cosa che potresti notare solo dopo circa 3 mesi, quando i visitatori inizieranno a ricevere errori di certificato scaduto.

Caso d’uso di CloudFlare

Queste istruzioni sono per forum Discourse self-hosted che utilizzano il Proxy di Cloudflare.

Quando si utilizza il Proxy di Cloudflare, ciò impedisce a tutto il traffico SMTP (Porta 25) di raggiungere mai il server. Ciò richiede di impostare un sottodominio diverso affinché il mail-receiver funzioni.

Ad esempio, se il tuo dominio è forums.domain.tld, dovrai creare un nuovo sottodominio, come mail.domain.tld.

Con Cloudflare, sono necessari i passaggi aggiuntivi seguenti.

  1. Creare il record A per il nuovo sottodominio. Utilizzerà lo stesso indirizzo IP di forums.domain.tld.
  2. Creare il record MX per il nuovo sottodominio come fornito nelle istruzioni principali.

Segui gli insiemi di istruzioni principali con questa piccola modifica. Funzionerà perfettamente con la sicurezza TLS disattivata.

Se desideri eseguire la sicurezza TLS, ciò richiederà un lavoro aggiuntivo.

Panoramica dell’impostazione TLS

Queste istruzioni installeranno Certbot e un plugin Certbot di CloudFlare. I comandi otterranno i certificati LetsEncrypt in Standalone tramite il processo di certificazione DNS. Una volta che i certificati sono disponibili, vengono copiati nell’area condivisa del mail-receiver affinché il container li utilizzi. Dobbiamo utilizzare il modello DNS, poiché Discourse ha già la porta 80.

Sfida DNS

Invece di dimostrare la proprietà del dominio tramite HTTP, certbot la dimostra creando un record TXT nel tuo DNS. Poiché il tuo DNS è Cloudflare, questo può essere completamente automatizzato con un token API di Cloudflare: nessuna porta 80, nessun arresto del server web necessario.

Come funziona

Certbot → Crea il record TXT _acme-challenge.mail.lotuselan.net in Cloudflare
Let's Encrypt → Cerca quel record TXT → Convalida → Emette il certificato
Certbot → Elimina il record TXT

Tutto questo viene fatto sul server di base, non all’interno del container di discourse.

Configurazione

1 — Installa cerbot e il plugin certbot di Cloudflare:

bash

apt install certbot python3-certbot-dns-cloudflare -y

2 — Crea un token API di Cloudflare:

  1. Vai su Cloudflare → My Profile → API Tokens → Create Token
  2. Utilizza il modello “Edit zone DNS”
  3. Autorizzazioni: Zone → DNS → Edit
  4. Risorse di zona: Include → Specific zone → lotuselan.net
  5. Restrizioni IP: imposta solo per consentire l’accesso dall’indirizzo IP del tuo server
  6. Copia il token

3 — Salva il token in un file di credenziali:

bash

mkdir -p /etc/letsencrypt/cloudflare
nano /etc/letsencrypt/cloudflare/credentials.ini

Incolla:

dns_cloudflare_api_token = IL_TUO_TOKEN_API_CLOUDFLARE

Blocca il file:

bash

chmod 600 /etc/letsencrypt/cloudflare/credentials.ini

4 — Richiedi il certificato:

Aggiorna il seguente comando con la tua email di amministratore e il nome di dominio.

bash

certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials /etc/letsencrypt/cloudflare/credentials.ini \
  --non-interactive \
  --agree-tos \
  --email tuaindirizzoemail@dominio.tld \
  -d mail.domain.tld

Nei risultati, dovrebbe esserci un’istruzione che dice:

Certbot has set up a scheduled task to automatically renew this certificate in the background.

Certbot imposterà un cron per controllare la scadenza del certificato due volte al giorno. Rinnova i certificati quando sono entro 30 giorni dalla scadenza. Puoi verificarlo tramite:

# Controlla se il timer systemd è attivo (sulla maggior parte dei moderni sistemi Ubuntu)
systemctl status certbot.timer

# Oppure controlla se è stata aggiunta un'attività cron
cat /etc/cron.d/certbot

Ora hai i certificati TLS sul server per il nuovo nome di dominio del mail-receiver. Non sono in una posizione utilizzabile.

5 — Imposta uno script di distribuzione per spostare i file
Poiché certbot si rinnova automaticamente, devi solo gestire la tua script per le parti specifiche di Discourse — copiare i certificati rinnovati e ricostruire il mail-receiver. Puoi semplificare notevolmente lo script utilizzando l’hook di distribuzione integrato di certbot, che viene eseguito automaticamente dopo un rinnovo riuscito.

Crea un file di hook di distribuzione:

bash

nano /etc/letsencrypt/renewal-hooks/deploy/mail-receiver-deploy.sh
chmod +x /etc/letsencrypt/renewal-hooks/deploy/mail-receiver-deploy.sh

Incolla questo:

bash

#!/bin/bash
DOMAIN="mail.domain.tld"
DISCOURSE_DIR="/var/discourse"
CERT_SRC="/etc/letsencrypt/live/${DOMAIN}"
CERT_DEST_1="${DISCOURSE_DIR}/shared/mail-receiver/letsencrypt/${DOMAIN}"
CERT_DEST_2="${DISCOURSE_DIR}/shared/mail-receiver/letsencrypt/${DOMAIN}_ecc"
ADMIN_EMAIL="indirizzo email admin"
LOG_FILE="/var/log/mail-cert-renewal.log"

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}

log "=== Triggered hook di distribuzione Certbot per ${DOMAIN} ==="

# Copia certificati (usa -L per risolvere i collegamenti simbolici)
for DEST in "$CERT_DEST_1" "$CERT_DEST_2"; do
    mkdir -p "$DEST"
    cp -L "${CERT_SRC}/fullchain.pem" "${DEST}/fullchain.pem"
    cp -L "${CERT_SRC}/privkey.pem"   "${DEST}/privkey.pem"
    cp -L "${CERT_SRC}/cert.pem"      "${DEST}/cert.pem"
    cp -L "${CERT_SRC}/chain.pem"     "${DEST}/chain.pem"
    chmod 644 "${DEST}/fullchain.pem" "${DEST}/cert.pem" "${DEST}/chain.pem"
    chmod 600 "${DEST}/privkey.pem"
    log "Certificati copiati in ${DEST}"
done

# Ricostruisci mail-receiver
cd "$DISCOURSE_DIR" || { echo "Impossibile eseguire cd in ${DISCOURSE_DIR}" | mail -s "[FALLIMENTO] Il deploy hook del certificato mail non è riuscito" "$ADMIN_EMAIL"; exit 1; }
log "Ricostruzione di mail-receiver..."
if ./launcher rebuild mail-receiver >> "$LOG_FILE" 2>&1; then
    log "mail-receiver ricostruito con successo"
else
    log "ERRORE: ricostruzione fallita"
    echo "La ricostruzione di mail-receiver è fallita dopo il rinnovo del certificato. Controlla ${LOG_FILE}" | \
        mail -s "[FALLIMENTO] Il deploy hook del certificato mail non è riuscito" "$ADMIN_EMAIL"
    exit 1
fi

log "=== Deploy hook completato con successo ==="

Nessuna attività cron manuale necessaria — certbot orchestra l’intero processo. L’hook di distribuzione si attiva solo quando avviene effettivamente un rinnovo, quindi il tuo mail-receiver non subirà ricostruzioni non necessarie nei giorni in cui certbot controlla ma non rinnova.

Per testare l’hook di rinnovo, esegui quanto segue:

bash

bash /etc/letsencrypt/renewal-hooks/deploy/mail-receiver-deploy.sh

Se tutto è stato configurato correttamente, questo:
→ copia i certificati nelle directory di Discourse
→ ricostruisce mail-receiver
→ registra tutto

6 — Imposta TLS in mail-receiver.yml

Il problema principale qui sembra essere che il record A per forum.domain.tld è mascherato dal proxy, invece di voler esplicitamente il server di posta su un dominio separato.

Durante la negoziazione TLS, il nome comune del certificato viene confrontato con il nome host del record MX, ovvero il nome host a cui il client (che potrebbe essere un altro server di posta) sta tentando di connettersi, piuttosto che con il record A a cui fa riferimento. Ciò significa che è possibile creare il record A di mail.domain.tld impostato su DNS Mode Only, quindi creare un record MX per forum.domain.tld che faccia riferimento a mail.domain.tld e non sono necessari ulteriori passaggi speciali in questa configurazione.

Sì, puoi usare solo la modalità DNS per il record A del tuo forum principale. Usando questo approccio perdi le capacità di proxy globale inverso di CloudFlare. (Questa non era un’opzione per la mia installazione di Discourse.)

Questo è il motivo per cui la prima riga definisce questa soluzione per i siti che utilizzano il Proxy CloudFlare.

Mi riferivo al record A di mail.domain.tld impostato su Solo modalità DNS anziché al record A di forum.domain.tld, tuttavia mi sono reso conto di aver frainteso come i client SMTP autenticano i certificati TLS.

Il comportamento che stavo osservando era un artefatto del metodo opportunistico predefinito che non convalida il nome host, quindi la mia affermazione che convalidasse il nome host del record MX anziché la destinazione del record MX era errata. Funzionerebbe nella maggior parte dei casi, ma non se DANE o MTA-STS vengono utilizzati per imporre l’autenticazione dell’identità TLS.

Avere il record A proxied e il record MX Solo DNS non funziona. La documentazione di CloudFlare afferma che qualsiasi dominio che ha il record A proxato blocca tutto il traffico SMTP.

L’ho verificato con diversi cicli di test. Nel momento in cui si de-proxy il record A, i dati SMTP fluiscono. Si attiva il Proxy, i dati SMTP non fluiscono mai. (I test sono stati eseguiti utilizzando TELNET sulla porta 25.)

Quindi, se si desidera:

  • Che il forum Discourse utilizzi i servizi Proxy di CloudFlare
  • Che il Ricevitore di Posta SMTP accetti la posta

È necessario disporre di domini diversi per la posta in entrata.

Se si desidera TLS per il Ricevitore di Posta SMTP:

  • È necessario configurare un LetsEncrypt tramite Verifica DNS

Le istruzioni sembrano scoraggianti, ma la stesura delle istruzioni ha richiesto più tempo dell’effettiva implementazione della soluzione.

Non era quello che intendevo, in particolare quello che stavo suggerendo erano tre record DNS:
A: forum.domain.tld → indirizzo IP dell’host (proxy abilitato)
A: mail.domain.tld → indirizzo IP dell’host (Modalità DNS Solo)
MX: forum.domain.tldmail.domain.tld

Tuttavia, come accennato, in seguito mi sono reso conto che ciò funzionerebbe solo nella modalità TLS opportunistica predefinita, non funzionerà se si desidera (qualcuno) abilitare anche DANE o MTA-STS per imporre l’autenticazione dell’identità (assicurarsi che si stia tentando di connettersi al server corretto piuttosto che solo crittografare il traffico).

Sembrano molto buone, facili da seguire e fanno tutto al di fuori del container, quindi non c’è rischio che si rompa potenzialmente con gli aggiornamenti di Discourse. Apprezzo in particolare l’uso di un hook di rinnovo di certbot con cui non avevo familiarità prima.

1 Mi Piace

Nota che questo espone l’indirizzo IP del tuo forum e rende possibile per le persone aggirare i meccanismi di protezione di Cloudflare come la protezione DDoS e il WAF. È meglio eseguire il ricevitore di posta (mail-receiver) su un server separato.

La mia prima intenzione era di eseguire mail-receiver su un server diverso per questo motivo. Ogni volta che ho provato ad eseguire l’applicazione launcher per avviare il mail-receiver, ha voluto installare l’intero sistema discourse. C’è un modo semplice per avviare ed eseguire solo mail-receiver su un server docker autonomo?

Non ho molta familiarità con l’app launcher poiché gestiamo la nostra infrastruttura, ma la mia idea sarebbe di non utilizzare l’app launcher e avviarla come qualsiasi altro container. Le variabili d’ambiente necessarie si trovano nel readme.

@Simon_Manning & @RGJ - La documentazione di Cloudflare è stata aggiornata per fornire le 3 opzioni principali e i relativi compromessi. Speriamo che questo affronti i vari problemi che avete sollevato riguardo alle prime opzioni presentate.

@kelv Potresti considerare di inserire una nota a piè di pagina nella descrizione principale della documentazione di Cloudflare. Questo farà risparmiare tempo a coloro a cui si applica. Configure direct-delivery incoming email for self-hosted sites with Mail-Receiver - #541 by LotusJeff

2 Mi Piace