Das ist ein eher langes Tutorial, ich hoffe aber mit den vielen Erklärungen alle Anwendungsfälle abzudecken. Das Thema ist für jeden Admin etwas das er 1x macht, dann vergisst, endlos aufschiebt oder letztendlich doch einen Dienstleister machen lässt. Ich habe leider (oder zum Glück) jeden Anwendungsfall den Postfix abdeckt zu lösen und hoffe mein Tutorial macht aus dem leidigen Thema ein erfolgreiches Wochenende!
Hier behandeln wir nur die Rolle als 📯 lokaler Postbote. Er darf als Dienst alle Namensschilder an den 📫 Briefkästen lesen und Post einwerfen, hat aber keine Schlüssel dafür. Zudem nimmt er Post zum 🏤 globalen Post-Server mit und prüft dabei Ihre Absender-Adresse.
Auch für Postfix nutze ich in diesem Beispiel wie bei Dovecot nur Debian.
apt install postfix postfix-ldap
Wählen Sie hier Satellite system
System mail name: mail.domain.tld (ihr 📯 lokaler Postbote)
SMTP Relay host: mx.domain.tld (🏤 globaler Post-Server der Ihre Mails im Internet annimmt oder weiterverteilt, das kann auch mx.krei.se sein)
Für die meisten Postfix-Begriffe brauchen Sie Kenntnis über das Mail-Glossar. Dort sind alle Konfigurationsparameter bildlich und für beide Postfix-Server-Arten erklärt, eine Einzelerklärung hier würde Sie nur verwirren, es werden aber Parameter dorthin verlinkt. Ich habe leider keine komplett deutsche Anleitung gefunden und installiere diese Server häufiger, daher wird das Glossar und Tutorials regelmässig gepflegt.
Debian hat nach der Installation mydomain standard undefiniert, myhostname fest auf die Ausgabe von hostname -f und myorigin auf /etc/mailname (System mail name aus der apt-installation).
Bitte prüfen Sie nach der Installation:
hostname -f sollte server.domain.tld ausgeben
/etc/mailname sollte mail.domain.tld ausgeben
Wir wollen in /etc/postfix/main.cf:
myhostname setzt Debian auf server.domain.tld und kann so bleiben, daran denken dass wir mit diesem auch alle Nutzer im EHLO begrüßen, also sensibel nutzen oder (evtl. systemweit) ändern. Dieser hostname muss auch für SSL passen
mydomain auf domain.tld oder undefiniert lassen
myorigin auf mail.domain.tld, /etc/mailname oder undefiniert lassen
mynetworks sollte nur 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 enthalten
mydestination erhält nur localhost
relayhost ist immer der globale 🏤 Post-Server mx.domain.tld
compatibility_level ist derzeit 3.9
Bitte prüfen Sie mit postconf | grep mydomain etc. diese Parameter auf Korrektheit.
main.cf
myhostname = mail.domain.tld
mydomain = domain.tld
# Alternativ servername.domain.tld, wird an Adressen ohne Domain angehangen
myorigin = /etc/mailname
mydestination = localhost
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
# Kann man so lassen, verrät aber den Hostnamen/Mailnamen wenn man sich nur auf die IP verbindet
smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
# Notification bei neuer Mail für lokale Nutzer
biff = no
# Damit kann man Mails an user@zweigstelle schicken und postfix hängt mydomain an. Ab Postfix 3.0 standard aus
# append_dot_mydomain = no
mailbox_size_limit = 0
# Damit kann man als user Mails unter user+suffix@ empfangen, wissen aber die SPAM-Leute ;)
recipient_delimiter = +
inet_interfaces = all
inet_protocols = all
# Das braucht man nur wenn Postfix an lokale Nutzer zustellt (local transport) was wir nie machen, das übernimmt immer Dovecot
mail_spool_directory = /var/vmail
home_mailbox = Maildir/
compatibility_level = 3.9
Wir nutzen nur virtuelle Postfächer, mydestination enthält daher nur localhost. Sie werden jetzt vielleicht denken es mache Sinn Mails an UNIX-User zuzustellen. Macht es NICHT und wird Sie maximal verwirren wenn Mails nicht 📬 einsortiert werden. Wir stellen Mails immer an mail.domain.tld zu wo Postfix und Dovecot mit LMTP schon begierig auf unsere Mails warten.
Das Equivalent zu mydestination ist die Einkaufsliste am Kühlschrank und der Zettel am Badspiegel mit der Bitte an den Gatten am Wochenende zu putzen - das liest kein Schwein und im Supermarkt bringt Ihnen die Einkaufsliste daheim exakt gar nix. Alle Server und Nutzer Ihrer Domain schicken und empfangen Mails an mail.domain.tld und haben dort Ihre 📫 Postfächer.
Schicken Sie Ihrem Gatten eine SMS mit Empfangsbestätigung, tragen Sie es im Kalender ein der dann auch während des Tatorts klingelt oder schreiben Sie eine Todo mit Caldav die auch im Supermarkt lesbar ist.
Wenn Sie allen Mail-Nutzern CAs verteilen können ist hier die Nutzung von 🏰 ED25519 denkbar, bequemer auch für BYOD ist natürlich 🛖 Letsencrypt.
main.cfsmtpd_tls_cert_file = /etc/letsencrypt/live/mail.domain.tld/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/mail.domain.tld/privkey.pem
main.cfsmtpd_tls_cert_file = /etc/ssl/certs/mail.domain.tld.crt
smtpd_tls_key_file = /etc/ssl/private/mail.domain.tld.key
smtpd_tls_CApath = /etc/ssl/certs
📝 .crt und .key sind in der Regel immer PEM-Format, eine Umbenennung, Umformung ist nicht notwendig. Auch ein FullChain im .crt was die CA mit enthält braucht man bei korrekter systemweiter Integration der ED25519-CA nicht, aber den smtpd_tls_CApath.
main.cf## SSL-Server Parameter
# TLS zulassen, aber nicht erzwingen, denn manche wollen uns lokal auch einfach per smtp Mails zukommen lassen
smtpd_tls_security_level = may
# Authentifizierung nur über TLS zulassen
smtpd_tls_auth_only = yes
# DH-Parameter
# ab Postfix 3.9 weglassen, deprecated
# smtpd_tls_dh1024_param_file = /etc/postfix/dhparam/dh4096.pem
# Logging
smtpd_tls_loglevel = 1
# Hardening.
# Hier ist ab Postfix 3.6 vieles einfacher geworden, einfach TLS 1.3 minimum setzen
smtpd_tls_mandatory_protocols = >=TLSv1.3
# Server, nicht Client legt Cipher-Reihenfolge fest
tls_preempt_cipherlist = yes
# Keine TLS-Workarounds zulassen
tls_disable_workarounds = 0xFFFFFFFFFFFFFFFF
# Sichere Cipher erzwingen
smtpd_tls_mandatory_ciphers = high
# Unsichere Cipher explizit ausschliessen braucht man für TLS 1.3 nicht mehr
# smtpd_tls_exclude_ciphers = aNULL, MD5
## SSL-Client Parameter
# 🏤 Post-Server Zertifikate verifizieren und Mails an diese niemals unverschlüsselt senden
# Da der 📯 Postbote i.d.R. nur an einen 🏤 weiterleitet und dieser immer korrektes SSL anbietet ist ein erzwingen sinnvoll.
smtp_tls_security_level = verify
# sollte so unter Debian schon Standard sein
smtp_tls_CApath = /etc/ssl/certs
# Gehärtete Voraussetzungen und Logging von smtpd übernehmen
smtp_tls_loglevel = $smtpd_tls_loglevel
smtp_tls_mandatory_protocols = $smtpd_tls_mandatory_protocols
smtp_tls_mandatory_ciphers = $smtpd_tls_mandatory_ciphers
smtp_tls_exclude_ciphers = $smtpd_tls_exclude_ciphers
Wir nutzen nur:
📫 virtual_mailbox (_domains, _maps) für die Weiterleitung an Dovecot zum Einsortieren und
📤 smtpd_sender_logins um zu schauen welcher angemeldete Nutzer mit welchen Absenderadressen versenden darf.
Die anderen Beispiele behandel ich hier nicht (mehr) weil ich das nie brauche - sorry. Ein LDAP-Lookup für das Weiterverteilen an andere Domains macht für eine Zweigstelle mit 100 Nutzern oder einen Heimserver einfach nie Sinn.
Erstellen Sie dazu einen Ordner unter /etc/postfix/ldap_lookups
mit den lookup-Dateien. Alle(!) starten mit diesen Zeilen, man kann das leider nicht als Einzeldatei extern includen (bin sonst für Hinweise dankbar!):
server_host = ldaps://ldap.domain.tld
# Standard ist off und brauchen wir nicht
#start_tls = yes
version = 3
# OpenLDAP nutzt ED25519-CAs, kein Letsencrypt. Sicherstellen, dass dieses systemweit installiert ist, dann liegt es unter Debian hier mit drin
tls_ca_cert_file = /etc/ssl/certs/ca-certificates.crt
tls_require_cert = yes
# cn=mail,ou=Dienste oder der Lookup-Nutzer der Userdaten lesen darf
bind = yes
bind_dn = cn=lookup,ou=Dienste,dc=domain,dc=tld
bind_pw = xxxxxxxxxxxxxxxxxx
search_base = dc=domain,dc=tld
# bei mehreren LDAP-Datenbanken / BaseDNs können Sie %1, %2, etc. nutzen (%1 tld, %2 domain, etc.)
# https://www.postfix.org/ldap_table.5.html --> ldap_table
# search_base = dc=2%,dc=1%
# sub ist Standard
scope = sub
Hier die Teile die dann in jede Datei zusätzlich kommen:
Dieses Lookup brauchen Sie wenn Sie user@domain.tld an den virtual_transport (Dovecot LMTP) zuweisen wollen.
Das ist die einzige Domain-Klasse den wir im lokalen Postboten behandeln um die Dinge einfach (...) zu halten.
virtual_mailbox_domains# Sucht alle mailacceptinggeneralid und filtert den Domain-Teil raus
# dadurch kennen wir alle Domains die virtuelle Postfächer haben
query_filter = (mailacceptinggeneralid=*@%s)
result_attribute = mailacceptinggeneralid
result_format = %d
Die nächsten beiden Lookups prüfen die Empfänger-Adresse und sind 1:1 so wie in Dovecot. Da Dovecot diesen Lookup immer ausführt kann man das auch weglassen (In 3b). Ich setze es trotzdem weil es sinnvoll ist Dovecot nur anzufragen wenn schon klar ist, dass der Empfänger valide ist.
virtual_mailbox_maps# Exact match
query_filter = (|(mail=%s)(mailacceptinggeneralid=%s))
result_attribute = mail
# Das Ergebnis wird von postfix ignoriert, wir prüfen nur ob die Adresse valide ist
result_format = %s
# Format für lokalen maildrop (Postfix speichert die Mail selbst ab - nutzen wir nicht)
#result_format = /var/vmail/%d/%n/Maildir/
virtual_mailbox_maps_catchall# Dieses Format prüft ob ein User als catchall (mailacceptinggeneralid=@domain.tld) vorliegt wenn der 1. Lookup nichts findet
# Catch-All
query_filter = (mailacceptinggeneralid=@%d)
result_attribute = mail
# Das Ergebnis wird von postfix beim nutzen von virtual_mailbox_domains ignoriert, wir prüfen nur ob die Adresse valide ist
result_format = %s
# Format für lokalen maildrop (Postfix speichert die Mail selbst ab - nutzen wir nicht)
#result_format = /var/vmail/%d/%n/Maildir/
Wer es vom Mail-Glossar wieder vergessen hat: Eine Domain die als
virtual_mailbox_domainsklassifiziert wird hat als transportvirtual_transport- hier wird die Adresse nur auf Validität geprüft, das Ergebnis (result_format) aber verworfen und die Mail an denvirtual_transport(Dovecot LMTP) weitergesendet.Haben Sie die Domain aber in
mydestinationgelistet wollen wir an lokale User zustellen, hier greift derlocal_transportder dann Verzeichnis, etc. wissen muss.
Nutzer holen Postfächer zwar per 📫 Dovecot, werden Mails aber immer über den 📯 lokalen Postboten versenden.
Dazu loggen diese sich immer mit user@domain.tld ein, können aber auch Mails von erlaubten Aliases verschicken.
Dazu prüft Postfix die Absender-Mail-Adresse als query und erhält den user-login zurück der damit versenden darf.
Für uns ist der user-login daher die volle Mail-Adresse. Sie könnten lokale Nutzer auch ohne @domain.tld anmelden lassen, da wir aber alle Nutzer per LDAP authentifizieren wird immer ein mail-attribut vorliegen (und das sieht auch schöner aus ;))
smtpd_sender_login_maps# Alt, unnötig weil Sie ohne die objectClass postfixUser gar nicht das Attribut mailacceptinggeneralid setzen können
#query_filter = (&(objectClass=postfixUser)(|(mailacceptinggeneralid=%s)(mail=%s)))
# Neu und einfach:
query_filter (|(mailacceptinggeneralid=%s)(mail=%s))
# Für Logins mit user@domain.tld ist das mail
result_attribute = mail
# result_attribute = uid
%s beinhaltet hier 3 Anfragen: Mail-from als
user@domain, dannuser, dann@domain. Hat ein User einen Catch-All @domain.tld als mailacceptinggeneralid kann er also auch von dieser ganzen Domain mit beliebigem Absender senden. Also beachten bevor man dem Kundendienst den Catch-All gibt, denn der kann dann auch als ceo@domain.tld versenden :D Wer das ausschliessen muss google:reject_authenticated_sender_login_mismatch(https://www.postfix.org/postconf.5.html#smtpd_sender_login_maps)
Diese Lookups stellen wir jetzt in main.cf ein:
# Lookups für lokale User wie root oder postmaster
# Diese am besten nur einmal von root auf admin@domain.tld setzen, einmal newaliases ausführen und vergessen ;)
#
# Beispiel:
#
# root@server:~/ cat /etc/aliases
# postmaster: root
# root: admin@domain.tld
# clamav: root
#
# root@server:~/ newaliases
#
#
alias_maps = hash:/etc/aliases
# Standard, legt fest welche DB mit newaliases geschrieben wird. Braucht man nur wenn man mehrer Alias-Maps hat
# alias_database = hash:/etc/aliases
# Domains die an dovecot-lmtp weiterverschickt werden
# 🦥 Wer faul ist oder nicht bei jeder Mail erneut LDAP fragen will kann hier einfach virtual_mailbox_domains = domain.tld eintragen
virtual_mailbox_domains = ldap:/etc/postfix/ldap_lookups/virtual_mailbox_domains
# Wir lassen Postfix vorfiltern ob der Empfänger korrekt ist, ansonsten lehnt notfalls auch Dovecot die Mail ab.
virtual_mailbox_maps = ldap:/etc/postfix/ldap_lookups/virtual_mailbox_maps, ldap:/etc/postfix/ldap_lookups/virtual_mailbox_maps_catchall
# Lookups welche Absender für authentifizierte Nutzer gültig sind
smtpd_sender_login_maps = ldap:/etc/postfix/ldap_lookups/smtpd_sender_login_maps
# Das ist Standard so und heisst, dass man ohne authentifizierung nur an lokale oder virtuelle Domains senden darf:
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
### Behandeln wir hier im Tutorial NICHT: ###
#virtual_alias_maps = ldap:/etc/postfix/ldap_lookups/virtual_alias_maps
# Lookups für Domains die direkt nach /home/user speichern
#virtual_alias_domains = ldap:/etc/postfix/ldap_lookups/virtual_alias_domains
#virtual_uid_maps = ldap:/etc/postfix/ldap_lookups/virtual_uid_maps
#virtual_gid_maps = ldap:/etc/postfix/ldap_lookups/virtual_gid_maps
# Das brauchen Sie nur wenn postfix selbst in /var/vmail speichern soll, ansonsten weiß das dovecot-lmtp
#virtual_uid_maps = static:5000
#virtual_gid_maps = static:5000
Postfix muss jetzt noch wissen welche transports genutzt werden. Transports sind Schnittstellen oder Programme die Mails letztendlich abspeichern.
main.cf
# Dovecot erlaubt LMTP nur für localhost und läuft auf derselben Maschine:
# IPs hier im Format: lmtp:inet:[1.2.3.4]:port angeben. [] schaltet DNS-Lookups aus.
virtual_transport = lmtp:inet:localhost:24
# Dovecot hat einen unix-lmtp-listener unter /var/spool/postfix/private/dovecot-lmtp
# auf derselben Maschine
# virtual_transport = lmtp:unix:private/dovecot-lmtp
# Dovecot erlaubt LMTP auch für andere IPs und läuft woanders:
# virtual_transport = lmtp:inet:mail.domain.tld:24
# virtual_transport = lmtp:inet:[1.2.3.4]:24
Dort fügen wir auch noch die Mailbox-Einstellungen ein wenn Postfix selbst einsortieren soll. Das ist immer hilfreich zu wissen, denn wer weiß ob Postfix nicht doch noch irgendwo eine Mail lokal zustellt ;)
mail_spool_directory = /var/vmail
# Hinweis zu mail_spool_directory, da verwirrend. Das ist nicht
# queue_directory = /var/spool/postfix
# wo Postfix Mails vorhält die noch nicht zugestellt werden konnten
# Maildir/ muss mit Slash angegeben werden, damit analog zu dovecot das Maildir-Format genutzt wird
# Wird ans Heimverzeichnis /home/user oder das Dovecot-Heimverzeichnis /var/vmail/domain.tld/user angehängt
home_mailbox = Maildir/
Postfix stellt zwar selbst keine Mails in Verzeichnisse zu, aber schaden wird es nicht wenn Sie es doch direkt machen wollen.
main.cf
smtpd_sasl_type = dovecot
# Unix-Listener
# smtpd_sasl_path = private/auth
# Inet-Listener
smtpd_sasl_path = inet:[127.0.0.1]:26
smtpd_sasl_auth_enable = yes
Irgendwo muss Ihr lokaler Postbote von Ihnen versendete Mails abgeben (verhindert so default_transport = smtp) - dafür können Sie:
einen 🏤 Dienstleister nutzen, er wird Ihnen dann Server und Zugangsdaten mitteilen.
🏤 mx.krei.se nutzen - wenn Sie von einer uns bekannten Subdomain von einer bekannten IP senden
selbst einen globalen Post-Server betreiben (das kostet etwa 5€ im Monat für einen root-Server).
Stellen Sie in jedem Fall den sog. relayhost ein (im Debian-Setup bereits gemacht wenn Satellite System gewählt wurde):
main.cf
relayhost = mx.domain.tld
Für mx.krei.se brauchen Sie nicht mehr, wir leiten anhand Ihrer IP alle Post mit @subdomain.krei.se als Absender weiter.
📝 Wenn sich ihre IP sehr häufig ändert und Sie doch einen login wollen können Sie sich aber auch auf mx.krei.se mit Ihren Subdomain-Passwort anmelden.
Wenn Sie für den Zugang beim MX einen Benutzer und Passwort brauchen, erstellen Sie diesen wie folgt:
root@server:/etc/postfix# echo "mx.domain.tld username:password" > /etc/postfix/relay_password
root@server:/etc/postfix# postmap /etc/postfix/relay_password
und setzen Sie in main.cf
# Beim Versenden per SMTP anmelden
smtp_sasl_auth_enable = yes
# dabei immer TLS nutzen
smtp_tls_security_level = encrypt
# Beschränkung aufheben, dass kein Passwort im Klartext übertragen werden darf
smtp_sasl_tls_security_level = noanonymous
# Passwörter für relayhosts
smtp_sasl_password_maps = hash:/etc/postfix/relay_password
# Brauchen Sie nur wenn Ihr Dienstleister auf Port 465 lauscht und nicht 25
# smtp_tls_wrappermode = yes
Mehr decke ich hier nicht ab.
📝 Wenn Sie gern selbst penibel sind und im Eigenbetrieb bestimmten IPs den Versand von dazugehörigen Domains ohne Login zulassen wollen - das geht mit smtpd_client_restrictions = check_client_access und smtpd_sender_restrictions = check_sender_access mit Hash-tables. Postfix lädt die Hashtables neu wenn Sie extern einen Eintrag mit postmap aktualisieren. Denkbar ist auch ldap oder direkt im Nameserver nachschauen. https://www.postfix.org/SASL_README.html
Die komplexeren Usecases machen wir lokal nicht, das steht dann alles im NOCH GRÖSSEREN globalen Post-Server Tutorial :D
Das genügt bereits für einen funktionierenden 📯 lokalen Postboten. Starten Sie postfix neu und schauen Sie in journalctl ob alles läuft.
Den Port brauchen Sie eigentlich nicht, aber manche Mail-Programme erwarten Port 25 für den Einwurf von Post und 587 um angemeldet welche zu versenden (was auch Port 25 kann).
Da das aber ein Einzeler ist:
/etc/postfix/master.cf
submission inet n - y - - smtpd
Einfach das # entfernen. Fertig!