Mailserver mit Dovecot, Postfix, MySQL und Spamassassin unter Ubuntu 16.04 LTS

Im Frühjahr 2014 habe ich meine erste ausführliche Anleitung zur Einrichtung eines einfachen Mailservers mit Postfix und Dovecot auf diesem Blog veröffentlicht. Viele Leser sind so erfolgreich zu ihrem privaten oder geschäftlichen Mailserver gekommen. Nachdem nun zwei Jahre vergangen sind und sich mittlerweile auch mein eigenes Setup geändert hat, will ich euch mit diesem Beitrag eine neue, aktualisierte Anleitung für einen Mailserver mit erweiterten Funktionen vorstellen.

Beachtet auch meine meine neue Mailserver-Anleitung vom August 2017: Diese wurde an einigen Stellen optimiert und setzt auf Rspamd statt Amavis/Spamassassin/Opendkim. Die neue Anleitung ist zwar auf Debian 9 “Stretch” ausgelegt, sollte größtenteils aber auch mit Ubuntu Server kompatibel sein.

Diese Anleitung wurde mehrmals im Ganzen auf einem neu installierten Ubuntu Server getestet und für funktionierend befunden. Solltest du dennoch einen Fehler finden oder einen Verbesserungsvorschlag haben, schreib‘ mir an: mailserver [ett] thomas-leister.de

Am Ende dieser Anleitung werdet ihr einen robusten Mailserver mit Spam-Abwehrmechanismen und weiteren Extras vor euch haben, den ihr so direkt verwenden und auf das Internet loslassen könnt. Außerdem liegt mir etwas daran, die grundlegende Funktionsweise des Mailsystems zu erklären, sodass ihr versteht, was Schritt für Schritt eingestellt wird. Ich betreibe selbst erst seit wenigen Jahren einen eigenen Mailserver und hätte mir zu Anfangszeiten gewünscht, zu verstehen, was ich da eigentlich konfiguriere. Wer einfach nur schnell zu einem Ergebnis kommen will, kann die Erklärungen natürlich überspringen und einfach nur Schritt für Schritt die Anweisungen befolgen. Ich rate aber trotzdem, sich mit dem Thema zumindest grundlegend auseinanderzusetzen: Wenn ein gewisses Verständnis vorhanden ist, können künftige Erweiterungen und Änderungen an der Software einfacher durchgeführt werden.

Wer lieber auf eine fertige Lösung setzt und sich die Handarbeit sparen will, sollte sich einmal Mailcow ansehen.
Manuel Müller hat einen Docker-Container für das hier vorgestellte Setup erstellt: https://muellermh.wordpress.com/2016/04/22/locker-mit-docker-heute-der-mailserver/
Die Firma ROCK5 GmbH hat ein Ansible-Playbook für dieses Setup veröffentlicht: https://github.com/ROCK5GmbH/ansible-mailserver

Der eigene Mailserver – Das ideale Wochenend-Projekt

Wenn ihr diese Anleitung an einem Samstag lest, habt ihr ja schon alles richtig gemacht ;-) … was ich damit sagen will, ist: Nehmt euch genug Zeit. Ein Mailserver ist für Ungeübte nicht “mal eben aufgesetzt” und funktioniert in manchen Fällen nicht sofort. Ich gebe mir bei meinen Ausführungen zwar viel Mühe, trotzdem können sich (Tipp-/)Fehler einschleichen, wenn ihr die Konfigurationen anpasst. Dann funktioniert euer möglicherweise Mailsystem nicht oder nur teilweise. Die Fehlersuche kann unter Umständen viel Zeit kosten, sodass ihr euch nicht vornehmen solltet, in einer Stunde schon perfekt mit dem neuen Server kommunizieren zu können. Änderungen im DNS benötigen u.U ohnehin ein paar Stunden, bis sie weltweit aktiv sind.

Übrigens: Geübte Leser können diese Anleitung in etwa 45 Minuten durcharbeiten (inkl. Erklärungen).

Funktionen

  • Senden und Empfangen von E-Mails für beliebige Domains
  • Nutzerverwaltung via MySQL-Backend
  • Festlegen einer maximalen Mailbox-Größe (“Quota”)
  • Einrichtung von Mail-Weiterleitungen / Aliasen
  • Einrichtung allgemeiner und Nutzer-spezifischer Filter- und Sortierregeln mit Sieve (+ Zugriff über kompatible Mailclients -> Managesieve)
  • Empfängerdomain-spezifische TLS-Einstellungen (z.B. nur verschlüsselt und DANE-verifiziert schicken an mailserver.tld)
  • Spamerkennung mit Spamassassin (+ MySQL) und Filterregeln von Heinlein Support
  • Spamserver-Früherkennung mit Postscreen
  • Einrichtung von “Send only”-Usern, die senden, aber nicht empfangen können (z.B. für Forensoftware, Soziale Netzwerke, OwnCloud, …)
  • DKIM-Signierung von ausgehenden E-Mails
  • Spamassassin-Training mit Dovecot-Antispam

Verwendete Software

Diese Anleitung basiert auf Software der folgenden Versionen (Versionierung nach Ubuntu Server Paketquellen):

Mit etwas älteren oder neueren Softwareversionen oder anderen Linux-Distributionen sollte diese Anleitung in den Grundzügen ähnlich nachvollziehbar sein. Probiert es einfach aus :-)

Annahmen

In dieser Anleitung kommen folgende Domains vor:

  • mysystems.tld: Übergeordnete Domain
  • mail.mysystems.tld: Subdomain, unter der der Mailserver verfügbar sein soll (FQDN des Mailsystems)
  • imap.mysystems.tld: Alias auf mail.mysystems.tld, wird von vielen Mailclient automatisch gesucht und gefunden
  • smtp.mysystems.tld: Dasselbe für den SMTP-Dienst
  • domain2.tld: Eine zweite Domain neben mysystems.tld, für die E-Mails gesendet und empfangen werden sollen
  • domain3.tld: Eine dritte Domain, für die E-Mails verarbeitet werden sollen

Diese Domains müssen in der Anleitung selbstverständlich durch eigene ersetzt werden. Auf domain2.tld und domain3.tld kann verzichtet werden, wenn der Mailserver nur für eine Domain genutzt werden soll.

Grundvoraussetzungen für einen eigenen Mailserver

  • Rootserver mit installiertem Ubuntu Server 16.04 LTS und statischer IP-Adresse (DSL-Adressbereiche werden von fremden Servern oftmals blockiert, daher empfehle ich, einen kleinen, günstigen, virtuellen Server in einem Rechenzentrum anzumieten.) Ein Singlecore-Server mit 1 GB RAM ist für private Zwecke völlig ausreichend und bezahlbar – zum Beispiel bei servercow.de (~5 € / Monat) oder active-servers.com
  • Mindestens eine eigene Domain, die mit dem Mailserver benutzt wird + Kontrolle über die DNS-Zone

Aufbau des Mailservers

Damit ihr einen Überblick habt, wie die einzelnen Komponenten des Mailsystems zusammen gehören, habe ich auch eine Übersichtsskizze erstellt:

Mailserver Schema

Genutzte Software

Welche Softwareversionen verwendet werden, wisst ihr bereits. Doch welche Software übernimmt welche Aufgaben?

Dovecot

Dovecot ist ein weit verbreiteter MDA (Mail Delivery Agent) und IMAP-Server. Er sortiert ankommende E-Mails in die Postfächer des jeweiligen Empfängers ein und stellt eine Schnittstelle zum Abrufen der Mailbox bereit (IMAP). Außerdem wird Dovecot in diesem Setup von Postfix als sog. SASL-Authentifizierungsserver genutzt: Postfix fragt Dovecot, ob ein bestimmter Benutzer berechtigt ist, sich am System anzumelden.

Aufgaben: Verwaltung der Mailbox, Bereitstellung einer Schnittstelle zum Abrufen erhaltener E-Mails, SASL-Authentifizierungsserver (überprüft Benutzeranmeldung)

Postfix

Postfix wird oft zusammen mit Dovecot eingesetzt. Der populäre MTA (Mail Transfer Agent) kümmert sich um alles, was mit dem Transport der E-Mail zu tun hat: Vom E-Mail Client zum eigenen Mailserver, und von dort aus zum jeweiligen Zielserver. Außerdem nimmt Postfix E-Mails von fremden Servern an und leitet sie an den MDA Dovecot weiter. Antispam-Software wird i.d.R. direkt in Postfix integriert, um eintreffende Spammails erst gar nicht in die Mailbox des Nutzers gelangen zu lassen.

Aufgaben: E-Mail-Transport und -Filterung

Anmerkung: Postfix ist “der eigentliche Mailserver”. E-Mails können ohne weiteres einzig und allein mit Postfix gesendet und empfangen werden. Alle weiteren Komponenten wie Dovecot, Amavis und Spamassassin machen uns das Leben allerdings einfacher ;-)

MySQL-Datenbank

Dovecot und Postfix werden so konfiguriert, dass sie eine MySQL-Datenbank als Backend (Datenbasis) nutzen. In der Datenbank werden zu nutzende Domains, Benutzer, Aliase und weitere Daten gespeichert. Durch einfaches Hinzufügen oder Entfernen von Datensätzen in oder aus Datenbanktabellen können neue Benutzer oder Aliase angelegt oder gelöscht werden. Der Vorteil eines Datenbank-Backends ist, dass sich der Mailserver damit sehr einfach verwalten lässt: So ließe sich zur Benutzerverwaltung beispielsweise eine Weboberfläche in PHP entwickeln, die die MySQL-Datenbank verändert. Die Serverkonfiguration muss dann nicht manuell geändert werden.

Aufgaben: Bereitstellung Betriebsdaten für Postfix und Dovecot

Amavis

Amavis ist ein E-Mail-Filter-Framework, welches zwischen einen MTA wie Postfix und die sog. Content-Filter (die Filterprogramme an sich) geschaltet wird. Postfix schleift alle E-Mails zunächst durch Amavis, wo sie dann nochmals durch die einzelnen Filter (z.B. Spamassassin) geschleust werden. Am Ende des Filterprozesses werden die Mails wieder an Postfix zurückzugeben. Neben der Aktivierung der Content-Filter hat Amavis auch die Aufgabe, eingehende E-Mails auf evtl. vorhandene DKIM-Signaturen zu prüfen und diese zu verifizieren. Bei erfolgreicher Verifizierung sinkt die Wahrscheinlichkeit, dass eine E-Mail als Spam erkannt wird.

Aufgaben: Vermittlung zwischen Postfix und Content-Filter, DKIM-Verifizierung

Amavisd-Milter

Amavis kann leider nicht direkt als Milter in Postfix eingebunden werden. Abhilfe schafft amavisd-milter: Es bildet eine Schnittstelle zwischen Postfix und Amavis und übersetzt das Milter-Protokoll in das Amavis-eigene AMP.PDP-Protokoll.

Aufgaben: Vermittlung zwischen Postfix und Amavis

Spamassassin

Spamassassin ist ein Content-Filter, der zusammen mit Amavis genutzt werden kann. Er erkennt und markiert Spam-Emails anhand von Filterregeln und wird durch das Razor-netzwerk unterstützt.

Aufgaben: Erkennung und Markierung von Spammails

Razor / Pyzor

Pyzor ist die Python-Implementierung eines Razor-Clients. Mit Razor kann die Erkennungsrate von Spamassassin verbessert werden.

Aufgaben: Verbesserung der Spamassassin-Erkennungrate

OpenDKIM

Zur DKIM-Signierung der ausgehenden E-Mails wird OpenDKIM verwendet. Warum ich bei der DKIM-Signierung nicht auf Amavis setze, erkläre ich unten im Beitrag unter “Fragen und Antworten”.

Aufgaben: DKIM-Signierung

Vorbereitungen

Tipp: Reinen Tisch machen

Wenn ihr den Server vorher schon für etwas anderes (oder sogar ein anderes Mail-Setup) verwendet habt, stellt sicher, dass Reste aus alten Installationen das neue Setup nicht behindern. Speziell vorherige Mailserver-Versuche sollten rückstandslos entfernt werden (inkl. der zugehörigen Konfigurationsdateien). Am besten ist natürlich – falls möglich – eine komplette Neuinstallation des Servers.

Login als Root

Bei der Installation von Ubuntu Server wird ein normaler Benutzeraccount, z.B. “thomas” eingerichtet, zu dem ihr euch via Passwort verbinden könnt. Der Root-Account ist standardmäßig nicht direkt zugänglich, sondern nur über den Umweg via “sudo”. Für diese Anleitung werden permanent Root-Rechte benötigt. Öffnet also am besten eine Root-Kommandozeile via

sudo -s

System aktualisieren

Bevor ihr neue Software-Pakete installiert, solltet ihr mittels

apt update && apt upgrade

sicherstellen, dass euer System aktuell ist. Bei der Gelegenheit bietet sich auch gleich ein Reboot an, um einen möglicherweise aktualisierten Linux-Kernel zu laden.

Hostname und Server-FQDN setzen

Euer Server bekommt zwei Namen, über die er identifiziert werden kann:

  • Lokalen Hostnamen: Für die Identifizierung des Servers innerhalb der eigenen Infrastruktur, z.B. “mail”
  • FQDN (Fully Qualified Domain Name): Für die weltweite Identifizierung im Internet, z.B. “mail.mysystems.tld”

Der FQDN muss nicht zwingend etwas mit den Domains zu tun haben, für die später E-Mails gesendet und empfangen werden sollen. Wichtig ist nur, dass euer künftiger Mailserver einen solchen Namen hat, der auch über das DNS zur Server-IP-Adresse aufgelöst werden kann (dazu gleich mehr im Abschnitt “Einrichtung des DNS”). Den lokalen Hostnamen setzt ihr wie folgt:

echo "mail" > /etc/hostname

In der Datei /etc/hosts sollten FQDN und lokaler Hostname hinterlegt sein, z.B.:

127.0.0.1 mail.mysystems.tld mail localhost.localdomain localhost  
::1       mail.mysystems.tld mail localhost.localdomain ip6-localhost

Die Ausgaben der Kommandos “hostname” und “hostname -f” sollten nach den Änderungen wie folgt aussehen:

root@mail:~# hostname
mail
root@mail:~# hostname -f
mail.mysystems.tld

Der FQDN (in diesem Beispiel “mail.mysystems.tld”) wird außerdem nach /etc/mailname geschrieben:

echo $(hostname -f) > /etc/mailname

Tipp: Unbound DNS Resolver installieren

Ein eigener, kleiner DNS-Resolver bringt durch lokales Caching nicht nur Performancevorteile mit sich, sondern auch Sicherheitsvorteile: Statt sich auf die Antworten fremder Resolver verlassen zu müssen, kann der lokale Resolver befragt werden. Der Server bietet DNSSEC-Funktionalität und sehr schnell eingerichtet:

Beitrag: Unbound installieren

Für den Zugriff auf Spamhaus-Blocklists (wie sie später in der Konfiguration verwendet werden) kann es sogar notwendig sein, seinen eigenen DNS-Resolver zu nutzen, weil z.B. Zugriffe über das Google DNS blockiert werden.

Diffie-Hellman-Parameter täglich neu generieren

Für maximal sichere TLS-Verbindungen mit Diffie-Hellman-Schlüsselaustausch wird empfohlen, die DH-Parameter täglich via Cronjob zu erneuern (Siehe auch Beitrag von mailbox.org). Dazu wird das Verzeichnis /etc/myssl erstellt …

mkdir /etc/myssl

… die Cronjob-Übersicht von root geöffnet …

crontab -e

und dieser Cronjob eingefügt:

# DH parameter re-generation
@daily FILE=`mktemp` ; openssl dhparam -out $FILE 2048 > /dev/null 2>&1 && mv -f $FILE /etc/myssl/dh2048.pem

Das Kommando zur Generierung der DH-Parameter wird dann einmalig von Hand ausgeführt, um die dh2048.pem-Datei ein erstes Mal zu generieren:

FILE=`mktemp` ; openssl dhparam -out $FILE 2048 > /dev/null 2>&1 && mv -f $FILE /etc/myssl/dh2048.pem

Einrichtung des DNS

Zu Beginn dieser Anleitung wurde für den Mailserver der FQDN “mail.mysystems.tld” festgelegt. Für diesen Domain-Namen werden nun A-Records im DNS-Zonefile der Domain “mysystems.tld” erstellt. Loggt euch bei eurem Domain-Provider ein und legt die folgenden Einträge an – der erste für die IPv4-IP-Adresse des Mailservers, die zweite für die IPv6-Adresse. (Beispiel!): Achtet im Folgenden vor allem auf den abschließenden Punkt in den Domainnamen!

mail.mysystems.tld. 86400 IN A    5.1.76.155
mail.mysystems.tld. 86400 IN AAAA 2a00:f820:417::be19:7b23

“mail.mysystems.tld” ist damit im DNS bekannt. Wenn keine IPv6-Adresse genutzt wird, kann der zweite Record entfallen. Bleiben noch “imap.mysystems.tld” und “smtp.mysystems.tld”, die als Alias-Domains für “mail.mysystems.tld” angelegt werden. Sie sind nicht unbedingt notwendig, werden von vielen Mailclient aber gesucht und sind so üblich:

imap.mysystems.tld. 86400 IN CNAME mail.mysystems.tld.
smtp.mysystems.tld. 86400 IN CNAME mail.mysystems.tld.

Mailclients können sich damit schon über imap.mysystems.tld und smtp.mysystems.tld zum Mailserver verbinden. Andere Mailserver suchen bei der E-Mail-Übermittlung allerdings nicht nach A- oder CNAME-Records, sondern nach MX-Records. Ein MX-Record zeigt, welcher Mailserver für die E-Mails zu einer Domain zuständig ist. In meinem Beispiel soll sich unser Mailserver neben den E-Mails für mysystems.tld auch um die Mails für domain2.tld und domain3.tld kümmern.

Im Zonefile der Domain “mysystems.tld” wird dazu dieser Record angelegt:

mysystems.tld. 86400 IN MX 0 mail.mysystems.tld.

In die Zonefiles der anderen Domains werden entsprechend die Records

domain2.tld. 86400 IN MX 0 mail.mysystems.tld.

und

domain3.tld. 86400 IN MX 0 mail.mysystems.tld.

angelegt.

Reverse DNS

Des weiteren muss ein sog. Reverse-DNS-Record / PTR für den FQDN des Mailservers angelegt werden. Dieser entspricht der Umkehrung eines normalen DNS-Records und ordnet einer IP-Adresse einen Hostnamen zu. Diesen Record kann nur der Inhaber des Netzes anlegen, aus dem eure IP-Adresse stammt. Möglicherweise könnt ihr so einen Reverse-DNS-Record in der Verwaltungsoberfläche eures Serveranbieters setzen, oder ihr bittet den Support, das zu tun. Der Domain-Name, der mit der IP-Adresse verknüpft werden muss, ist der FQDN eures Mailservers. In meinem Beispiel mail.mysystems.tld. Denkt daran, für alle vom Mailserver genutzten, öffentlichen IP-Adressen einen solchen Record zu erstellen. In dieser Anleitung wird eine IPv4- und eine IPv6-Adresse verwendet.

SPF-Records

Im Kampf gegen Spam und Phishing wurde das sog. Sender Policy Framework entwickelt (Siehe auch Beitrag: “Voraussetzungen für den Versand zu großen E-Mail Providern”). Obwohl es sich nur als eingeschränkt brauchbar erwiesen hat, erwarten die meisten Mailprovider gültige SPF-Records für andere Mailserver und prüfen diese. SPF-Einträge werden im Zonefile aller Domains erstellt, für die ein Mailserver E-Mails verschickt, und geben an, welche Server für eine Domain sendeberechtigt sind. Für unsere Domain mysystems.tld wird der folgende Record im Zonefile von mysystems.tld angelegt:

mysystems.tld. 3600 IN TXT v=spf1 a:mail.mysystems.tld ?all

Hiermit erhält nur der im A-Record “mail.msystems.tld” genannte Server für mysystems.tld eine Sendeberechtigung. Die Neutral-Einstellung “?all” sorgt dafür, dass E-Mails von anderen Servern trotzdem angenommen werden sollen. Damit gehen wir Problemen beim Mail-Forwarding aus dem Weg. Wir erstellen den SPF-Record also eigentlich nur, damit andere Mailserver unseren Server wegen des existierenden Records positiv bewerten – nicht, weil er seinen Nutzen entfalten soll.

In den Zonefiles der beiden Domains “domain2.tld” und “domain3.tld” wird (angepasst auf die Domain) jeweils dieser Record angelegt:

domain2.tld. 3600 IN TXT v=spf1 include:mysystems.tld ?all

Über das “include” wird der erste Record der Domain mysystems.tld eingebunden.

TLS-Zertifikate erstellen

Wer seinen eigenen Mailserver vernünftig einsetzen will, kommt um die TLS-Verschlüsselung nicht herum. Immer mehr Server lassen keine unverschlüsselten Verbindungen mehr zu. Doch spätestens seit dem Start von Let’s Encrypt gibt es auch keinen Grund mehr, kein TLS für Web- und Mailserver einzusetzen. Wie ihr euch ein TLS-Zertifikat von der kostenlosen Initiative “Let’s Encrypt” ausstellen lassen könnt, habe ich bereits in diesem Beitrag erklärt: Kostenlose TLS-Zertifikate für alle.

Der einfachste (und schnellste!) Weg zu gültigen Zertifikaten für die drei Beispiel-Domains “mail.mysystems.tld”, “imap.mysystems.tld” und “smtp.mysystems.tld” führt über die folgenden drei Kommandozeilen-Befehle:

apt install git
git clone https://github.com/certbot/certbot
cd certbot
./certbot-auto certonly --standalone --rsa-key-size 4096 -d mail.mysystems.tld -d imap.mysystems.tld -d smtp.mysystems.tld

Ein möglicherweise laufender Webserver muss für den Zertifikatsdownload abgeschaltet sein, damit Certbot Port 80 nutzen kann!

Zertifikat und privater Schlüssel werden unter /etc/letsencrypt/live/mail.mysystems.tld/ abgelegt. In eurem individuellen Fall unterscheidet sich der Pfad selbstverständlich. Die Zertifikate sind übrigens für Web- und Mailserver gleichermaßen gültig: Technisch gibt es keinen Unterschied. Achtet auch auf die Erneuerung der Zertifikate! LE-Zertifikate sind nur 90 Tage lang gültig und müssen regelmäßig erneuert werden, z.B. via Cronjob. Anleitungen dazu gibt es zu genüge ;-)

In dieser Anleitung beziehe ich mich auf Let’s Encrypt-Zertifikate, deshalb entspricht privkey.pem dem privaten Schlüssel und fullchain.pem dem Zertifikat + Intermediate-Zertifikat. Selbstverständlich funktionieren auch Zertifikate anderer Zertifikatsaussteller. Wichtig ist nur, dass das Zertifikat die drei Domains “mail.mysystems.tld”, “imap.mysystems.tld” und “smtp.mysystems.tld” beinhaltet.

MySQL Datenbank einrichten

Informationen über zu verwaltende Domains, Benutzer, Weiterleitungen und sonstige Einstellungen soll der Mailserver aus einer MySQL-Datenbank ziehen. Das hat den Vorteil, dass der Server im laufenden Betrieb flexibel angepasst werden kann, ohne die Konfigurationsdateien ändern zu müssen. Die Datenbank ermöglicht uns außerdem ein virtualisiertes Mailserver-Setup: Die Benutzer auf den Mailservern müssen nicht mehr als reale Linux-Benutzer im System registriert sein, sondern nur noch in der Datenbank eingetragen werden.

Als DBMS wird Oracles MySQL-Datenbank genutzt. Wer will, kann stattdessen natürlich auch jeden anderen MySQL-kompatiblen Datenbankserver nutzen, z.B. MariaDB. Weil sich Oracles MySQl-Datenbankserver aber im “main” Repository von Ubuntu Server 16.04 befindet und deshalb im Gegensatz zu MariaDB garantierten Langzeitsupport erhält, habe ich mich für das Original entschieden

apt install mysql-server

Während der Installation werdet ihr nach einem Passwort für den MySQL-user “root” (nicht den gleichnamigen Systembenutzer!) gefragt. Gebt ein möglichst sicheres Passwort an. Mit dem Benutzernamen “root” und diesem Passwort werdet ihr euch nachher an der MySQL-Konsole anmelden.

Nach der Installation sollte der MySQL-Server bereits gestartet worden sein. Ein “systemctl status mysql” gibt einige Informationen zum Serverbetrieb aus. Wenn MySQL nicht läuft, könnt ihr es via “systemctl start mysql” starten.

Als nächstes wird eine neue Datenbank “vmail” mit einigen Tabellen angelegt, welche alle Informationen für unser Mailsystem beinhalten sollen. Meldet euch als DB-User “root” und dem zugehörigen Passwort an der MySQL-Kommandozeile an:

mysql -u root -p

Ein SQL-Kommando endet immer mit einem Semikolon ‚ ; ‚. Mehrzeilige Befehle könnt ihr ohne weiteres einfach mit ENTER umbrechen, so wie sie im Folgenden dargestellt werden. Achtet auf die Unterscheidung zwischen “Tick” und “Backtick” – der Backtick wird mit Shift + 2x Accent-Taste erzeugt. Kopiert die SQL-Statements am besten direkt in eure Zwischenanlage, statt sie mühsam abzutippen.

Im ersten Schritt muss die neue vmail-Datenbank erzeugt werden:

create database vmail;

Ein neuer DB-User “vmail” mit dem Passwort “vmaildbpass” bekommt vollen Zugriff auf diese neue Datenbank:

grant all on vmail.* to 'vmail'@'localhost' identified by 'vmaildbpass';

Alle weiteren Kommandos zu Erstellung der Datenbank-Tabellen sollen sich auf die eben erzeugte Datenbank beziehen:

use vmail

Das Mail-Setup soll 4 verschiedene Tabellen nutzen. Kopiert die SQL-Statements einzeln und nacheinander in die MySQL-Kommandozeile und bestätigt jedes mal mit [Enter].

Domain-Tabelle

Die Domain-Tabelle enthält alle Domains, die mit dem Mailserver genutzt werden sollen.

CREATE TABLE `domains` (
    `id` int unsigned NOT NULL AUTO_INCREMENT,
    `domain` varchar(255) NOT NULL,
    PRIMARY KEY (`id`),
    UNIQUE KEY (`domain`)
) CHARSET=latin1;

Account-Tabelle

CREATE TABLE `accounts` (
    `id` int unsigned NOT NULL AUTO_INCREMENT,
    `username` varchar(64) NOT NULL,
    `domain` varchar(255) NOT NULL,
    `password` varchar(255) NOT NULL,
    `quota` int unsigned DEFAULT '0',
    `enabled` boolean DEFAULT '0',
    `sendonly` boolean DEFAULT '0',
    PRIMARY KEY (id),
    UNIQUE KEY (`username`, `domain`),
    FOREIGN KEY (`domain`) REFERENCES `domains` (`domain`)
) CHARSET=latin1;

Die Account-Tabelle enthält alle Mailserver-Accounts. Das Feld “quota” enthält die Volumenbegrenzung für die Mailbox in MB (Megabyte). Im Feld “enabled” wird über einen bool’schen Wert festgelegt, ob ein Account aktiv ist, oder nicht. So können einzelne User temporär deaktiviert werden, ohne gelöscht werden zu müssen. “sendonly” wird auf “true” gesetzt, wenn der Account nur zum Senden von E-Mails genutzt werden soll – nicht aber zum Empfang. Das kann beispielsweise für Foren- oder Blogsoftware sinnvoll sein, die mit ihrem Account nur E-Mails verschicken soll.

Alias-Tabelle

CREATE TABLE `aliases` (
    `id` int unsigned NOT NULL AUTO_INCREMENT,
    `source_username` varchar(64) NOT NULL,
    `source_domain` varchar(255) NOT NULL,
    `destination_username` varchar(64) NOT NULL,
    `destination_domain` varchar(255) NOT NULL,
    `enabled` boolean DEFAULT '0',
    PRIMARY KEY (`id`),
    UNIQUE KEY (`source_username`, `source_domain`, `destination_username`, `destination_domain`),
    FOREIGN KEY (`source_domain`) REFERENCES `domains` (`domain`)
) CHARSET=latin1;

Die Alias-Tabelle enthält alle Weiterleitungen / Aliase und ist eigentlich selbsterklärend. Zur temporären Deaktivierung von Weiterleitungsadressen gibt es wieder ein “enabled”-Feld.

TLS Policy-Tabelle

CREATE TABLE `tlspolicies` (
    `id` int unsigned NOT NULL AUTO_INCREMENT,
    `domain` varchar(255) NOT NULL,
    `policy` enum('none', 'may', 'encrypt', 'dane', 'dane-only', 'fingerprint', 'verify', 'secure') NOT NULL,
    `params` varchar(255),
    PRIMARY KEY (`id`),
    UNIQUE KEY (`domain`)
) CHARSET=latin1;

Mithilfe der TLS Policy Tabelle kann festgelegt werden, für welche Empfängerdomains bestimmte Sicherheitsbeschränkungen beim Mailtransport gelten sollen. Für einzelne Domains, z.B. “gmx.de” kann beispielsweise angegeben werden, dass diese E-Mails nur noch verschlüsselt übertragen werden dürfen. Mehr dazu später.

Die Datenbank wird mit Datensätzen befüllt, sobald die Server fertig konfiguriert sind. Bis dahin könnt ihr die MySQL-Kommandozeile mit “quit” verlassen.

vmail-Benutzer und -Verzeichnis einrichten

Alle Mailboxen werden direkt im Dateisystem des Ubuntu Servers abgelegt. Für die Zugriffe auf die Mailbox-Verzeichnisse wird ein eigener Benutzer “vmail” (“Virtual Mail”) erstellt, unter dem die Zugriffe von Dovecot und anderen Komponenten des Mailservers geschehen sollen. Einerseits wird so verhindert, dass Mailserver-Komponenten auf sensible Systemverzeichnisse Zugriff bekommen, andererseits können wir so die Mailboxen vor dem Zugriff von außen schützen. Nur vmail (und root) dürfen auf die Mailboxen zugreifen.

Das Verzeichnis /var/vmail/ soll alle Mailserver-relevanten Dateien (also Mailboxen und Filterscripts) enthalten und wird für den vmail-User als Home Directory festgelegt.

vmail-Verzeichnis erstellen:

mkdir /var/vmail

vmail-Systembenutzer erstellen:

adduser --disabled-login --disabled-password --home /var/vmail vmail

vmail Unterverzeichnisse erstellen:

mkdir /var/vmail/mailboxes
mkdir -p /var/vmail/sieve/global

/var/vmail an vmail-User übereignen und Verzeichnisrechte passend setzen:

chown -R vmail /var/vmail
chgrp -R vmail /var/vmail
chmod -R 770 /var/vmail

Dovecot installieren und konfigurieren

Nachdem die Datenbank und der vmail-User angelegt wurden, widmen wir uns nun dem Dovecot-Server. Wie bereits erwähnt, verwaltet dieser Server die Mailboxen und bekommt daher (in der Gestalt des vmail-Users) exklusiv Zugriff auf /var/vmail/. Zuerst müssen jedoch alle Serverkomponenten installiert werden:

apt install dovecot-core dovecot-imapd dovecot-lmtpd dovecot-mysql dovecot-sieve dovecot-managesieved dovecot-antispam
  • dovecot-core: Dovecot-Kern
  • dovecot-imapd: Fügt IMAP-Funktionalität hinzu
  • dovecot-lmtp: Fügt LMTP (Local Mail Transfer Protocol)-Funktionalität hinzu; LMTP wird als MTP-Protokoll zwischen Postfix und Dovecot genutzt
  • dovecot-mysql: Lässt Dovecot mit der MySQL-Datenbank zusammenarbeiten
  • dovecot-sieve: Fügt Filterfunktionalität hinzu
  • dovecot-managesieved: Stellt eine Schnittstelle zur Einrichtung der Filter via Mailclient bereit
  • dovecot-antispam: Trainiert Spamassassin über das Verschieben von E-Mails in oder aus dem Spamordner

Nach der Installation wird Dovecot automatisch gestartet. Beendet Dovecot, solange wir keine fertige Konfiguration haben:

systemctl stop dovecot

Nun geht es an die Konfiguration. Die Dovecot-Konfigurationsdateien liegen im Verzeichnis /etc/dovecot/. Dort könnt ihr schon einige Konfigurationen sehen, die bei der Installation angelegt wurden. Mit meiner letzten Mailserver-Anleitung habe ich die Erfahrung gemacht, dass es besser ist, eine eigene Konfiguration von Grund auf anzulegen, statt die Änderungen an bestehenden Dateien zu beschreiben. Deshalb wird zuerst einmal die gesamte Dovecot-Konfiguration eingestampft:

rm -r /etc/dovecot/*
cd /etc/dovecot

Für Dovecot reichen die folgenden zwei Konfigurationsdateien aus. Den Inhalt könnt ihr einfach kopieren. Stellen, die angepasst werden müssen, habe ich blau markiert.

Datei dovecot.conf

###
### Aktivierte Protokolle
#############################

protocols = imap lmtp sieve



###
### TLS Config
#######################

ssl = required
ssl_cert = </etc/letsencrypt/live/mail.mysystems.tld/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.mysystems.tld/privkey.pem
ssl_dh_parameters_length = 2048
ssl_protocols = !SSLv2 !SSLv3
ssl_cipher_list = EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA256:EECDH:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA128-SHA:AES128-SHA
ssl_prefer_server_ciphers = yes



###
### Dovecot services
################################

service imap-login {
    inet_listener imap {
        port = 143
    }
}


service managesieve-login {
    inet_listener sieve {
        port = 4190
    }
}


service lmtp {
    unix_listener /var/spool/postfix/private/dovecot-lmtp {
        mode = 0660
        group = postfix
        user = postfix
    }

    user = vmail
}


service auth {
    ### Auth socket für Postfix
    unix_listener /var/spool/postfix/private/auth {
        mode = 0660
        user = postfix
        group = postfix
    }

    ### Auth socket für LMTP-Dienst
    unix_listener auth-userdb {
        mode = 0660
        user = vmail
        group = vmail
    }
}


###
###  Protocol settings
#############################

protocol imap {
    mail_plugins = $mail_plugins quota imap_quota antispam
    mail_max_userip_connections = 20
    imap_idle_notify_interval = 29 mins
}

protocol lmtp {
    postmaster_address = postmaster@mysystems.tld
    mail_plugins = $mail_plugins sieve
}



###
### Client authentication
#############################

disable_plaintext_auth = yes
auth_mechanisms = plain login


passdb {
    driver = sql
    args = /etc/dovecot/dovecot-sql.conf
}

userdb {
    driver = sql
    args = /etc/dovecot/dovecot-sql.conf
}


###
### Mail location
#######################

mail_uid = vmail
mail_gid = vmail
mail_privileged_group = vmail


mail_home = /var/vmail/mailboxes/%d/%n
mail_location = maildir:~/mail:LAYOUT=fs



###
### Mailbox configuration
########################################

namespace inbox {
    inbox = yes

    mailbox Spam {
        auto = subscribe
        special_use = \Junk
    }

    mailbox Trash {
        auto = subscribe
        special_use = \Trash
    }

    mailbox Drafts {
        auto = subscribe
        special_use = \Drafts
    }

    mailbox Sent {
        auto = subscribe
        special_use = \Sent
    }
}



###
### Mail plugins
############################


plugin {
    sieve_before = /var/vmail/sieve/global/spam-global.sieve   
    sieve = /var/vmail/sieve/%d/%n/active-script.sieve
    sieve_dir = /var/vmail/sieve/%d/%n/scripts

    quota = maildir:User quota
    quota_exceeded_message = Benutzer %u hat das Speichervolumen überschritten. / User %u has exhausted allowed storage space.

    antispam_backend = pipe
    antispam_spam = Spam
    antispam_trash = Trash
    antispam_pipe_program = /var/vmail/spampipe.sh
    antispam_pipe_program_spam_arg = --spam
    antispam_pipe_program_notspam_arg = --ham
}

“dovecot.conf” ist die Hauptkonfigurationsdatei des Dovecot-Servers:

SSL-Konfiguration: Dovecot generiert seine eigenen Diffie-Hellman-Parameter. Mit ssl_dh_parameters_length wird die gewünschte Länge in Bits angegeben. 2048 Bit reichen aus. SSL Version 2 und 3 sind veraltet und sollen nicht mehr eingesetzt werden, deshalb werden sie abgeschaltet. Es folgt eine sog. “Cipherlist”, die die gewünschten Verschlüsselungsmodalitäten in absteigender Priorität vorgibt. Client und Server einigen sich basierend auf dieser Priorisierung auf einen gemeinsam genutzten Cipher, und nutzen die stärkste Verschlüsselung, mit der beide Seiten arbeiten können. Die Cipherlist stammt von bettercrypto.org

Dovecot Services: Im darauf folgenden Abschnitt werden die Dovecot Services konfiguriert. Dazu gehört z.B. der Dienst “imap-login”, der auf eingehende Verbindungen von E-Mail Clients auf Port 143 horcht. Auch “managesieve-login” kommuniziert mit dem Mailclient, wenn dieser eine Funktion zur Bearbeitung Server-seitiger Filterscripte mitbringt. Die anderen Dienste werden intern genutzt: Der lmtp-Dienst stellt eine Schnittstelle bereit, über die Postfix empfangene Mails an die Mailbox übergeben kann. Der “auth” Dienst wird vom LMTP-Dienst genutzt, um die Existenz von Benutzern zu überprüfen, aber auch von Postfix, um den Login am Postfix-Server zu überprüfen. Mit “mode”, “user” und “group” wird bestimmt, welcher Systemuser Zugriff auf den Dienst haben soll (Analog zu den Dateirechten – der Socket für den Dienst ist nichts anderes als eine Datei).

Protocol settings: Für die verwendeten Protokolle können zusätzliche Einstellungen gesetzt werden – u.A. auch, welche Erweiterungen im Zusammenhang mit dem Protokoll genutzt werden sollen. “quota” und “imap_quota” sind notwendig, um das maximale Volumen einer Mailbox festsetzen zu können. Beim lmtp-Protokoll kann auf diese Erweiterungen verzichtet werden: Hier wird nur die Sieve-Erweiterung zum Filtern von E-Mails benötigt.

Client Authentication: Die Zeilen

disable_plaintext_auth = yes
auth_mechanisms = plain login

scheinen sich zu widersprechen, schließlich wird die Klartext-Authentifizierung abgeschaltet. Doch tatsächlich wird sie das nur für unverschlüsselte Verbindungen. TLS-Verschlüsselte Verbindungen bleiben davon unberührt, sodass in der nächsten Zeile die “plain” Authentifizierung mit Klartext-Passwörtern wieder angeboten werden kann. Das wird aus zwei Gründen getan:

  • “Klartext” tut uns hier nicht weh – schließlich ist die Verbindung sowieso (zwingend) verschlüsselt.
  • Alle Mailclients unterstützen die Klartextauthentifizierung. Andere Loginmechanismen werden weniger gut unterstützt und sind aufwendiger.

Wir konzentrieren uns deshalb auf die klassische Klartextauthentifizierung. Wie bereits erwähnt: Da unsere Verbindung ohnehin verschlüsselt ist, ist das in diesem Fall nicht sicherheitsrelevant.

Für “passdb” und “userdb” wird jeweils der Pfad zur SQL-Datei eingestellt. Dort befindt sich jeweils eine passende SQL-Query. Die “passdb” wird befragt, wenn es um die Authentifizierung von Usern geht, die “userdb”, wenn die Existenz eines bestimmten E-Mail Kontos überprüft werden soll, oder benutzerdefinierte Einstellungen geladen werden müssen, wie z.B. das Mailbox-Kontingent (“Quota”).

Maillocation: In diesem Abschnitt wird definiert, unter welchem Systemuser Dovecot auf Dateisystem-Ebene mit E-Mails hantieren soll. Außerdem wird ein Pfad-Schema festgelegt, das bestimmt, nach welcher Struktur die Mailbox-Verzeichnisse angelegt werden sollen. %d steht für die Domain des Accounts und %u für den Benutzernamen vor dem @. Der Pfad zu einer Benutzermailbox lautet z.B.: /var/vmail/mailboxes/mysystems.tld/admin/mail/

Mailbox Configuration: In der Mailbox eines jeden Users soll sich standardmäßig ein “Spam”-Ordner befinden, in die ein passendes Sieve-Filterskript verdächtige E-Mails verschieben soll.

Mail Plugins: Hier werden die Details zu den Erweiterungen “sieve”, “quota” und “antispam” definiert. Das Script unter “sieve_before” wird für alle User (unabhängig von den eigenen Einstellungen) immer ausgeführt. Es hat die Aufgabe, von Spamassassin markierte Mails in den Spam-Ordner zu verschieben. “sieve_dir” definiert das Schema für den Ort, an dem benutzerdefinierte Scripts abgelegt werden. Das aktive Skript eines Nutzers soll jeweils über den symbolischen Link “active-script.sieve” zugänglich sein.

Im Antispam-Teil wird konfiguriert, wie welches Skript aufgerufen werden soll, wenn eine E-Mail manuell in den Spam-Ordner verschoben oder wieder herausgenommen wird. Bei jedem Verschiebevorgang wird das Script mit den passenden Parametern “–spam” oder “–ham” getriggert (mehr dazu gleich).

Datei dovecot-sql.conf

driver=mysql
connect = "host=127.0.0.1 dbname=vmail user=vmail password=vmaildbpass"
default_pass_scheme = SHA512-CRYPT

password_query = SELECT username AS user, domain, password FROM accounts WHERE username = '%n' AND domain = '%d' and enabled = true;

user_query = SELECT concat('*:storage=', quota, 'M') AS quota_rule FROM accounts WHERE username = '%n' AND domain = '%d' AND sendonly = false;

iterate_query = SELECT username, domain FROM accounts where sendonly = false;

Die Konfigurationsdatei “dovecot-sql.conf” enthält alle SQL-relevanten Einstellungen:

  • driver: Welcher Datenbank-Treiber soll genutzt werden?
  • connect: Informationen zur Datenbankverbindung
  • default_pass_scheme: Standardmäßig angenommenes Hash-Schema, wenn es in der Datenbank nicht explizit angegeben ist, z.B. mit vorangestelltem {SHA512-CRYPT}.
  • password_query: SQL Query für die Überprüfung des User-Logins. Stimmen Benutzername und Passwort überein? Existiert der Benutzer und ist er aktiviert?
  • user_query: SQL-Query zum Abholen aller Benutzer-spezifischen Einstellungen. In diesem Fall: Maximales Mailbox-Volumen (“Quota”).
  • iterate_query: SQL-Query zur Abfrage aller verfügbarer Benutzer. Benutzer, die keine Mails empfangen können (sendonly=true) sind für Dovecot nicht interessant und werden nicht mit ausgegeben.

dovecot-sql.conf enthält sensible Datenbank-Zugangsdaten und wird deshalb besonders geschützt:

chmod 770 dovecot-sql.conf

Antispam-Script für Spamassassin

Das vorher beschriebene Antispam-Script wird unter “/var/vmail/spampipe.sh” angelegt und hat folgenden, kurzen Inhalt:

#!/bin/bash
cat | sa-learn "$@" &
exit 0

Im Fall eines Verschiebevorgangs wird das Script mit der Option –ham oder –spam ausgeführt und der E-Mail der verschobenen Mail zusätzlich via Pipe übergeben. Das Spampipe.sh Skript nimmt die gepipe-te E-Mail via “cat” entgegen, übernimmt auch den jeweiligen Aufrufparameter und übergibt beides an das “sa-learn”-Tool, welches mit Spamassassin mitgeliefert wird. Das “&"-Zeichen am Ende des Kommandos sorgt dafür, dass das Training in einen Hintergrundprozess ausgelagert wird. So wird sichergestellt, dass der Verschiebevorgang im Mailclient schnell bleibt.

Nun wird das Script an den User “vmail” übereignet (Unter diesem User führt Dovecot das Script aus) und für diesen ausführbar gemacht:

chown vmail:vmail /var/vmail/spampipe.sh
chmod u+x /var/vmail/spampipe.sh

Globales Filterscript für Spam

Unter /var/vmail/sieve/global/ wird das Sieve-Filterscript spam-global.sieve erstellt, das erkannte Spammails in den Unterordner “Spam” jeder Mailbox einsortiert. Spamassassin markiert erkannte E-Mails mit einem speziellen Spam-Header, den das Script erkennt. Inhalt von spam-global.sieve:

require "fileinto";
if header :contains "X-Spam-Flag" "YES" {
  fileinto "Spam";
}

Postfix installieren und konfigurieren

Für unseren Postfix-Server benötigen wir nur zwei Pakete: Das Kernpaket “postfix” und die Komponente “postfix-mysql”, die Postfix mit der MySQL-Datenbank kommunizieren lässt.

apt install postfix postfix-mysql

Während der Installation werdet ihr nach der “Allgemeinen Art der Konfiguration” gefragt. Wählt an dieser Stelle “Keine Konfiguration” und beendet den Postfix-Server wieder:

systemctl stop postfix

Im Postfix-Konfigurationsverzeichnis /etc/postfix befinden sich trotz unserer Wahl “Keine Konfiguration” Konfigurationsdateien, die zunächst entfernt werden:

cd /etc/postfix
rm -r sasl
rm master.cf

Legt dann folgende Dateien im Verzeichnis /etc/postfix an: main.cf

##
## Netzwerkeinstellungen
##

mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
inet_interfaces = 127.0.0.1, ::1, 5.1.76.152, 2a00:f820:417::7647:b2c2
myhostname = mail.mysystems.tld


##
## Mail-Queue Einstellungen
##

maximal_queue_lifetime = 1h
bounce_queue_lifetime = 1h
maximal_backoff_time = 15m
minimal_backoff_time = 5m
queue_run_delay = 5m


##
## TLS Einstellungen
###

tls_ssl_options = NO_COMPRESSION
tls_high_cipherlist = EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA256:EECDH:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA128-SHA:AES128-SHA

### Ausgehende SMTP-Verbindungen (Postfix als Sender)

smtp_tls_security_level = dane
smtp_dns_support_level = dnssec
smtp_tls_policy_maps = mysql:/etc/postfix/sql/tls-policy.cf
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtp_tls_protocols = !SSLv2, !SSLv3
smtp_tls_ciphers = high
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt


### Eingehende SMTP-Verbindungen

smtpd_tls_security_level = may
smtpd_tls_protocols = !SSLv2, !SSLv3
smtpd_tls_ciphers = high
smtpd_tls_dh1024_param_file = /etc/myssl/dh2048.pem
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache

smtpd_tls_cert_file=/etc/letsencrypt/live/mail.mysystems.tld/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/mail.mysystems.tld/privkey.pem


##
## Lokale Mailzustellung an Dovecot
##

virtual_transport = lmtp:unix:private/dovecot-lmtp


##
## Milter: DKIM-Signaturen durch OpenDKIM-Milter
## und Mail-Filter mit Amavis (via amavisd-milter)
##

milter_default_action = accept
milter_protocol = 2
smtpd_milters = unix:/var/run/amavis/amavisd-milter.sock,
                unix:/var/run/opendkim/opendkim.sock
non_smtpd_milters = unix:/var/run/opendkim/opendkim.sock

##
## Server Restrictions für Clients, Empfänger und Relaying
## (im Bezug auf S2S-Verbindungen. Mailclient-Verbindungen werden in master.cf im Submission-Bereich konfiguriert)
##

### Bedingungen, damit Postfix als Relay arbeitet (für Clients)
smtpd_relay_restrictions =      reject_non_fqdn_recipient
                                reject_unknown_recipient_domain
                                permit_mynetworks
                                reject_unauth_destination


### Bedingungen, damit Postfix ankommende E-Mails als Empfängerserver entgegennimmt (zusätzlich zu relay-Bedingungen)
### check_recipient_access prüft, ob ein account sendonly ist
smtpd_recipient_restrictions = check_recipient_access mysql:/etc/postfix/sql/recipient-access.cf


### Bedingungen, die SMTP-Clients erfüllen müssen (sendende Server)
smtpd_client_restrictions =     permit_mynetworks
                                check_client_access hash:/etc/postfix/without_ptr
                                reject_unknown_client_hostname


### Wenn fremde Server eine Verbindung herstellen, müssen sie einen gültigen Hostnamen im HELO haben.
smtpd_helo_required = yes
smtpd_helo_restrictions =   permit_mynetworks
                            reject_invalid_helo_hostname
                            reject_non_fqdn_helo_hostname
                            reject_unknown_helo_hostname

# Clients blockieren, wenn sie versuchen zu früh zu senden
smtpd_data_restrictions = reject_unauth_pipelining



##
## Postscreen Filter
##

### Postscreen Whitelist / Blocklist
postscreen_access_list =        permit_mynetworks
                                cidr:/etc/postfix/postscreen_access
postscreen_blacklist_action = drop


# Verbindungen beenden, wenn der fremde Server es zu eilig hat
postscreen_greet_action = drop


### DNS blocklists
postscreen_dnsbl_threshold = 2
postscreen_dnsbl_sites = dnsbl.sorbs.net*1, bl.spamcop.net*1, ix.dnsbl.manitu.net*2, zen.spamhaus.org*2
postscreen_dnsbl_action = drop


##
## MySQL Abfragen
##

virtual_alias_maps = mysql:/etc/postfix/sql/aliases.cf
virtual_mailbox_maps = mysql:/etc/postfix/sql/accounts.cf
virtual_mailbox_domains = mysql:/etc/postfix/sql/domains.cf
local_recipient_maps = $virtual_mailbox_maps


##
## Sonstiges
##

### Maximale Größe der gesamten Mailbox (soll von Dovecot festgelegt werden, 0 = unbegrenzt)
mailbox_size_limit = 0

### Maximale Größe eingehender E-Mails in Bytes (50 MB)
message_size_limit = 52428800

### Keine System-Benachrichtigung für Benutzer bei neuer E-Mail
biff = no

### Nutzer müssen immer volle E-Mail Adresse angeben - nicht nur Hostname
append_dot_mydomain = no

### Trenn-Zeichen für "Address Tagging"
recipient_delimiter = +

Wichtiger Hinweis für Hetzner CX- vServer Kunden:

Die CX-vServer-Modelle von Hetzner haben ihre öffentliche IP-Adresse nicht direkt an der Netzwerkschnittstelle anliegen. Wenn ihr ein “ip addr” ausführt, seht ihr statt der öffentlichen IP-Adresse eine private Adresse. Das liegt daran, dass Hetzner die öffentliche Adresse auf die private Adresse “NATet”. (Mehr dazu unter “Warum hat meine VM die IP 172.31.1.100?” – https://wiki.hetzner.de/index.php/VServer#Warum_hat_meine_VM_die_IP_172.31.1.100.3F). Verwendet in der Postfix-Konfiguration und allen übrigen Konfigurationen also nicht die öffentliche Adresse, sondern die private!

Erklärung der Konfiguration in main.cf

Netzwerkeinstellungen:

  • mynetworks: Anfragen von diesen IP-Adressen / aus diesen IP-Adressbereichen werden von Postfix gesondert behandelt (Verwendung für “mynetworks” in den Restrictions). Üblicherweise werden hier die *lokalen Adressbereiche und IP-Adressen aus dem eigenen Netz eingetragen.
  • inet_interfaces: Auf diesen IP-Adressen soll Postfix seine Ports öffnen. Die IP-Adressen müssen an den eigenen Server angepasst werden.
  • myhostname: Der Hostname des Mailservers, wie er bei der Mailverarbeitung genutzt werden soll.

Mail-Queue Einstellungen:

E-Mails in Postfix werden “gequeued”, d.h. in eine Warteschlange eingetragen, die regelmäßig abgearbeitet wird. Wenn Mails nicht zustellbar sind, verbleiben sie eine gewisse Zeit in der Queue, bis ihre Lebenszeit abgelaufen ist, und sie aus der Queue entfernt werden. Der Absender der E-Mail bekommt dann eine entsprechende Nachricht, in der er über die Unzustellbarkeit informiert wird.

  • maximal_queue_lifetime: Lebensdauer einer normalen Nachricht in der Queue. Wenn eine E-Mail innerhalb einer Stunde nicht zugestellt werden konnte, wird sie aus der Queue entfernt und der Absender benachrichtigt.
  • bounce_queue_lifetime: Lebensdauer einer Unzustellbarkeits-Benachrichtigung in der Queue.
  • maximal_backoff_time: Maximale Zeit, die verstreichen darf, bis für eine E-Mail ein neuer Zustellversuch gestartet wird.
  • minimal_backoff_time: Zeit, die mindestens verstrichen sein muss, bis ein neuer Zustellversuch gestartet wird.
  • queue_run_delay: Intervall, in dem die Queue nach nicht zustellbaren E-Mails durchsucht wird.

TLS-Einstellungen:

Kompression wird abgeschaltet und (wie bei Dovecot) eine Cipherlist vorgegeben, sodass die bestmögliche Verschlüsselung zwischen Client und Server genutzt wird. Im ersten Teilabschnitt werden die “smtp”-spezifischen TLS-Einstellungen festgelegt – d.h. die Einstellungen, die Postfix als sendenden Kommunikationspartner (Mail-Client) betreffen.

  • smtp_tls_security_level: Standard-TLS-Policy, wenn sie in der Datenbank für die Empfängerdomain nicht anders spezifiziert wurde: “dane” kontrolliert zunächst, ob für den Empfängerserver ein TLSA-Eintrag (DANE) im DNS vorliegt. Wenn das der Fall ist, wird eine verschlüsselte Verbindung erzwungen und das vorgezeigte Serverzertifikat mittels TLSA-Eintrag verifiziert. Sollte kein TLSA-Eintrag verfügbar sein, fällt Postfix in die Plicy “may” zurück und verschlüsselt nur, wenn der andere Server das unterstützt. Zertifikate werden dabei nicht validiert. Sollten vorhandene TLSA-Einträge ungültig sein, wird stattdessen die “encrypt” Policy genutzt, welche zwar zwingend Verschlüsselt, aber Zertifikate ebenfalls nicht validiert. Mehr zu den TLS-Policies folgt später.
  • smtp_dns_support_level: DNSSEC-gesicherte DNS-Lookups aktiveren und nutzen, falls möglich
  • smtpd_tls_policy_maps: Verweist auf die SQL-Queries, mit denen Empfängerdomain-spezifische TLS-Einstellungen geladen werden
  • smtp_tls_protocols: SSL v2 und v3 werden deaktiviert.

Nun zum zweiten TLS-Block: Dieser gilt für eingehende Verbindungen. Sowohl für andere Server, als auch Mailclients. Wieder werden SSL v2 und 3 deaktiviert und eine starke Cipherlist ausgewählt. Eingehende Verbindungen können verschlüsselt sein, müssen aber nicht. Zusätzlich wird die DH-Parameter-Datei geladen, für deren Generierung zuvor bereits ein Cronjob eingerichtet wurde.

“virtual_transport” übermittelt verarbeitete, eingehende E-Mails an den LMTP-Service von Dovecot, der sich dann um die Einordnung der Mail in die passende Mailbox kümmert.

Server Restrictions:

Die Blöcke unter “Server restrictions” sind besonders wichtig für die Sicherheit des Mailservers. Falsch eingestellt erlauben sie den unberechtigten Versand von E-Mails (Stichwort “Open Relay”). Der Mailserver wird dann als Spam-Schleuder missbraucht und landet sehr schnell auf einer Blacklist. Damit das nicht passiert, sollten die Restrictions (Beschränkungen) sorgfältig eingestellt und mit einem passenden Open Relay Detektor überprüft sein.

Die Restrictions werden in Leserichtung nacheinander abgearbeitet. Am Ende jeder Verarbeitung steht immer ein “permit” oder “reject”. Für das bessere Verständnis ein Beispiel:

smtpd_relay_restrictions =      reject_non_fqdn_recipient
                                reject_unknown_recipient_domain
                                permit_mynetworks
                                reject_unauth_destination

“smtpd_relay_restrictions” bestimmt die Bedingungen, unter der Postfix als Mail-Relay (“Vermittlungsstelle”) arbeitet. Unser Postfix soll nur in drei Fällen auf eingehende E-Mails reagieren:

  • Wenn ein Mailclient eine E-Mail via Postfix ins Internet schicken will
  • Wenn ein fremder Mailserver eine E-Mail an unseren Postfix schickt
  • Wenn vom Mailserver selbst aus eine Mail verschickt werden soll

Um den ersten Fall wird sich in der master.cf Datei gekümmert. Dort wird werden die Relay Restrictions im Submission-Bereich so überschrieben, dass Mailclients nicht am freien Versenden gehindert werden. Aktuell interessieren daher nur die letzten beiden Anfrage-Typen. Die erste Zeile der Restriction lautet “reject_non_fqdn_recipient”. Sollte die Empfängeradresse keine vollwertige E-Mail Adresse sein, wird die Anfrage an Postfix direkt mit einem “reject” abgewiesen. Alle anderen Checks finden dann nicht mehr statt. Das führt dazu, dass Postfix eine Weiterverarbeitung nur akzeptiert, wenn die zu verarbeitende E-Mail einen gültigen Empfänger hat. Ähnliches gilt für “reject_unknown_recipient_domain”: Wenn die Empfängerdomain keinen gültigen MX- oder A-Eintrag im DNS hat (und der Zielserver damit nicht feststeht), wird die E-Mail abgelehnt.

Die darauf folgende Zeile enthält die “Restriction” “permit_mynetworks”. Wenn der Anfragesteller lokal ist (bzw. seine IP in “mynetworks” vermerkt ist), wird er mit einem “permit” durchgewunken und die E-Mail wird weiter verarbeitet. Weitere Checks finden dann nicht statt. Sollte er nicht in mynetworks vermerkt sein, wird der letzte Check durchgeführt: “reject_unauth_destination” kann nur bestanden werden, wenn die zu verarbeitende E-Mail an eine Empfängeradresse dieses Mailsystems geht. Sollte bis zum Ende der restriction-Definition noch kein “permit” oder “reject” ausgelöst worden sein, wird automatisch ein “permit” ausgelöst und die jeweilige Aktion erlaubt.

Alle anderen Restriction-Definitionen funktionieren ähnlich: Die Kriterien werden nacheinander überprüft. Beginnt ein Kriterium mit einem “reject_”, wird bei Zutreffen ein “reject” ausgelöst, beginnt es mit einem “permit”, wird ein “permit” ausgelöst. In beiden Fällen werden die nachfolgenden Kriterien nicht mehr überprüft.

smtpd_relay_restrictions: Kriterien, die überprüft werden, wenn Anfragen am Postfix-Server eintreffen (Von fremden Mailservern oder vom eigenen Server aus, z.B. via sendmail)
smtpd_recipient_restrictions: Kriterien, die zusätzlich zu den relay_restrictions geprüft werden. Nur bei bestehen der Checks wird eine E-Mail auf dem lokalen System angenommen und an die Empfänger-Mailbox geschickt. An dieser Stelle wird über eine SQL-Abfrage nachgefragt, ob ein bestimmter Empfänger E-Mails empfangen können soll (=> Siehe Option in der Datenbank, Accounts nur zum Versenden freizuschalten).
smtpd_client-restrictions: Kriterien, auf die hin andere Server überprüft werden, wenn Kontakt zum Postfix-Server hergestellt wird. (Müssen gültigen Hostnamen und Reverse-DNS-Eintrag haben)
smtpd_helo_restrictions: Fremde Server müssen zu Beginn ihren gültigen Hostnamen nennen.
smtpd_data_restrictions: Ungeduldige Server sind oft Spammer.

Postscreen Filter:

Der Postscreen-Filter ist ein mächstiges Werkzeug, um Spammer-Server zu blockieren. Bevor ein fremder Server überhaupt eine E-Mail zustellen kann, überprüft Postscreen einige Merkmale des sendenden Servers und kann in den meisten Fällen zuverlässig zwischen gutem und bösen Server unterscheiden.

postscreen_access_list: In der Datei "/etc/postfix/postscreen_access können Ausnahmen für den Postscreen-Filter definiert werden.
DNS Blocklist: Postscreen kann anhand von Blacklists / Blocklists entscheiden, ob von einer bestimmten IP-Adresse häufig Spam ausgeht. Dazu werden die bekannten Blocklists unter "dnsbl_sites" befragt. Die zahl hinter dem Stern * ist dabei eine Gewichtung. Besonders zuverlässig arbeitende Blacklists bekommen eine höhere Gewichtung, damit der Schwellwert "dnsbl_threshold" schneller erreicht ist. Sobald der Schwellwert bei einem Server überschritten wird, wird die Verbindung abgebrochen.

Vorsicht mit der zen.spamhaus.org-Blocklist! Spamhaus lässt Anfragen aus dem Google DNS nicht zu. Installiert am besten einen eigenen DNS-Resolver, um dem Problem aus dem Weg zu gehen.

MySQL-Abfragen:

Hier sind die Pfade zu den übrigen SQL-Dateien angegeben, die Postfix benötigt, um Daten aus der Datenbank abfragen zu können.

master.cf

# ==========================================================================
# service type  private unpriv  chroot  wakeup  maxproc command + args
#               (yes)   (yes)   (no)    (never) (100)
# ==========================================================================

###
### Postscreen-Service: Prüft eingehende SMTP-Verbindungen auf Spam-Server
###
smtp      inet  n       -       n       -       1       postscreen
    -o smtpd_sasl_auth_enable=no
###
### SMTP-Daemon hinter Postscreen: Schleift E-Mails zur Filterung durch Amavis
###
smtpd     pass  -       -       n       -       -       smtpd
    -o smtpd_sasl_auth_enable=no
###
### dnsblog führt DNS-Abfragen für Blocklists durch
###
dnsblog   unix  -       -       n       -       0       dnsblog
###
### tlsproxy gibt Postscreen TLS support
###
tlsproxy  unix  -       -       n       -       0       tlsproxy
###
### Submission-Zugang für Clients: Für Mailclients gelten andere Regeln, als für andere Mailserver (siehe smtpd_ in main.cf)
###
submission inet n       -       n       -       -       smtpd
    -o syslog_name=postfix/submission
    -o smtpd_tls_security_level=encrypt
    -o smtpd_sasl_auth_enable=yes
    -o smtpd_sasl_type=dovecot
    -o smtpd_sasl_path=private/auth
    -o smtpd_sasl_security_options=noanonymous
    -o smtpd_relay_restrictions=reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_mynetworks,permit_sasl_authenticated,reject
    -o smtpd_sender_login_maps=mysql:/etc/postfix/sql/sender-login-maps.cf
    -o smtpd_sender_restrictions=permit_mynetworks,reject_non_fqdn_sender,reject_sender_login_mismatch,permit_sasl_authenticated,reject
    -o smtpd_client_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
    -o smtpd_helo_required=no
    -o smtpd_helo_restrictions=
    -o milter_macro_daemon_name=ORIGINATING
    -o cleanup_service_name=submission-header-cleanup
###
### Weitere wichtige Dienste für den Serverbetrieb
###
pickup    unix  n       -       n       60      1       pickup
cleanup   unix  n       -       n       -       0       cleanup
qmgr      unix  n       -       n       300     1       qmgr
tlsmgr    unix  -       -       n       1000?   1       tlsmgr
rewrite   unix  -       -       n       -       -       trivial-rewrite
bounce    unix  -       -       n       -       0       bounce
defer     unix  -       -       n       -       0       bounce
trace     unix  -       -       n       -       0       bounce
verify    unix  -       -       n       -       1       verify
flush     unix  n       -       n       1000?   0       flush
proxymap  unix  -       -       n       -       -       proxymap
proxywrite unix -       -       n       -       1       proxymap
smtp      unix  -       -       n       -       -       smtp
relay     unix  -       -       n       -       -       smtp
showq     unix  n       -       n       -       -       showq
error     unix  -       -       n       -       -       error
retry     unix  -       -       n       -       -       error
discard   unix  -       -       n       -       -       discard
local     unix  -       n       n       -       -       local
virtual   unix  -       n       n       -       -       virtual
lmtp      unix  -       -       n       -       -       lmtp
anvil     unix  -       -       n       -       1       anvil
scache    unix  -       -       n       -       1       scache
submission-header-cleanup unix n - n    -       0       cleanup
    -o header_checks=regexp:/etc/postfix/submission_header_cleanup

Die “master.cf” Datei will ich euch nur im Groben erklären. Wichtig zu wissen ist, dass hier die Definition und Konfiguration der verschiedenen Postfix-Dienste wie z.B. postscreen, smtpd und smtp passiert. Gut zu erkennen ist, dass über ein " -o” weitere Parameter an einen Dienst übergeben werden. So beispielsweise beim Submission-Dienst, der auf Port 587 für die SMTP-Kommunikation mit den Mailclients bereitsteht: Die hier angegebenen Einstellungen z.B. zu “smtpd_relay_restrictions” überschreiben die Einstellungen in der main.cf – allerdings nur für diesen einen spezifischen Dienst! Ein gutes Beispiel ist die Einstellung “smtpd_tls_security_level=encrypt”, die im Submission-Block steht. In der Main.cf hatten wir hier “may” definiert, um keine Server auszuschließen, die TLS nicht beherrschen. Da smtpd-Einstellungen aber sowohl für andere Server als auch für Mailclient gelten, wäre damit auch zu den Mailclients gesagt: “Ihr könnt verschlüsselte Verbindungen herstellen – müsst aber nicht”. Das wollen wir selbstverständlich nicht! Mailclients sollen eine verschlüsselte Verbindung herstellen müssen! Deshalb wird die smtpd-Einstellung speziell für den Submission-Dienst mithilfe der " -o" Option überschrieben und auf “encrypt” gesetzt.

Für besseren Datenschutz wird der “Received”-Header (+ weitere Datenschutz-relevante Header) bei eingehenden E-Mails entfernt, wenn sie über den Submission-Port eintreffen. Die meisten E-Mail-Clients senden ihren Namen und die Version mit. Zusätzlich vermerkt Postfix bei eingehenden E-Mails, von welcher IP-Adresse die E-Mail stammt. Auf diese Informationen können wir verzichten, deshalb werden sie mithilfe eines kleinen zusätzlichen Dienstes “submission-header-cleanup” (am Ende der Konfiguration) aus der E-Mail gelöscht. Im Submission-Bereich wird via “cleanup_service_name” festgelegt, dass bei eingehenden Mails auf dem Submission-Port (wird nur von Mailclients benutz) der Filter anzuwenden ist. Die Filterregeln befinden sich in der Datei /etc/postfix/submission_header_cleanup

Header Cleanup Regeln

Unter /etc/postfix/submission_header_cleanup wird eine Datei mit folgendem Inhalt angelegt:

### Entfernt Datenschutz-relevante Header aus E-Mails von MTUAs

/^Received:/            IGNORE
/^X-Originating-IP:/    IGNORE
/^X-Mailer:/            IGNORE
/^User-Agent:/          IGNORE

SQL-Konfiguration

Neben der Haupt-Konfiguration main.cf und der Service-Konfiguration master.cf werden noch ein paar Konfigurationsdateien innerhalb des Unterverzeichnisses sql/ angelegt, die die SQL-Queries für die Datenabfragen an die Datenbank enthalten:

mkdir /etc/postfix/sql && cd /etc/postfix/sql/

Erstellt dann die folgenden Konfigurationsdateien mit dem zugehörigen Inhalt:

accounts.cf

user = vmail
password = vmaildbpass
hosts = 127.0.0.1
dbname = vmail
query = select 1 as found from accounts where username = '%u' and domain = '%d' and enabled = true LIMIT 1;

aliases.cf

user = vmail
password = vmaildbpass
hosts = 127.0.0.1
dbname = vmail
query = select concat(destination_username, '@', destination_domain) as destinations from aliases where source_username = '%u' and source_domain = '%d' and enabled = true;

domains.cf

user = vmail
password = vmaildbpass
hosts = 127.0.0.1
dbname = vmail
query = SELECT domain FROM domains WHERE domain='%s'

recipient-access.cf

user = vmail
password = vmaildbpass
hosts = 127.0.0.1
dbname = vmail
query = select if(sendonly = true, 'REJECT', 'OK') AS access from accounts where username = '%u' and domain = '%d' and enabled = true LIMIT 1;

sender-login-maps.cf

user = vmail
password = vmaildbpass
hosts = 127.0.0.1
dbname = vmail
query = select concat(username, '@', domain) as 'owns' from accounts where username = '%u' AND domain = '%d' and enabled = true union select concat(destination_username, '@', destination_domain) AS 'owns' from aliases where source_username = '%u' and source_domain = '%d' and enabled = true;

tls-policy.cf

user = vmail
password = vmaildbpass
hosts = 127.0.0.1
dbname = vmail
query = SELECT policy, params FROM tlspolicies WHERE domain = '%s'

Alle SQL-Konfgurationsdateien in /etc/postfix/sql werden vor dem Zugriff durch unberechtigte User geschützt:

chmod -R 660 /etc/postfix/sql

Weitere Postfix-Konfigurationsdateien

Außerdem gibt es noch zwei weitere Dateien in /etc/postfix, die zunächst leer bleiben können:

touch /etc/postfix/without_ptr
touch /etc/postfix/postscreen_access

Die Datei “without_ptr” kann Einträge wie den folgenden beinhalten:

1.2.3.3 OK

Der Server mit dem IP 1.2.3.3 muss dann keinen gültigen PTR-Record mehr besitzen und wird trotzdem akzeptiert. Die without_ptr-Datei muss nach jeder Änderung in einer DB konvertiert und Postfix neu geladen werden:

postmap /etc/postfix/without_ptr
systemctl reload postfix

Im Moment reicht es aus, einfach nur eine leere DB zu generieren:

postmap /etc/postfix/without_ptr

Die Datei “postscreen_access” kann Ausnahme-IP-Adressen enthalten, die nicht von Postscreen überprüft werden sollen. Der Inhalt könnte beispielsweise so aussehen:

1.2.3.3 permit

Ein Server mit der IP-Adresse “1.2.3.3” wird dann nicht mehr von Postscreen kontrolliert. Hängt man statt des “permit” ein “reject” an, wird der Server mit der jeweiligen IP-Adresse auf jeden Fall von Postscreen blockiert.

Zum Schluss wird einmal

newaliases

ausgeführt, um die Alias-Datei “/etc/aliases.db” zu generieren, die Postfix standardmäßig erwartet.

DKIM-Signierung mit OpenDKIM einrichten

DKIM ist ein Signaturverfahren, das dabei hilft, den Absender einer E-Mail sicher zu authentifizieren. Dabei werden ausgehende E-Mails automatisch mit einer kryptographischen Signatur versehen, die es dem Empfänger ermöglicht, zu überprüfen, ob eine E-Mail tatsächlich von dem Absender stammt, der angegeben ist. Zum Signieren wird OpenDKIM verwendet, das zunächst installiert werden muss:

apt install opendkim opendkim-tools

OpenDKIM wird gestoppt, bis die Konfiguration abgeschlossen ist:

systemctl stop opendkim

Die Konfiguration in /etc/opendkim.conf wird gelöscht …

> /etc/opendkim.conf

… und eine eigene Konfiguration in die Datei geschrieben:

/etc/opendkim.conf

Syslog              yes
LogResults          yes
LogWhy              yes
SyslogSuccess       yes
UMask               002
Canonicalization    relaxed/relaxed

# Nur signieren, nicht verifizieren (Verifizierung übernimmt Amavis)
Mode                s

KeyTable            /etc/opendkim/keytable
SigningTable        refile:/etc/opendkim/signingtable

Im nächsten Schritt wird zur besseren Übersichtlichkeit ein neues Konfigurationsverzeichnis erstellt:

mkdir /etc/opendkim
cd /etc/opendkim

In einem Unterverzeichnis /etc/opendkim/keys soll der geheime Key für die Signaturen abgespeichert werden:

mkdir keys

Der Key wird mit dem folgenden Kommando generiert:

opendkim-genkey --selector=key1 --bits=2048 --directory=keys
  • selector: Ein frei wählbarer Name für den Signaturschlüssel. Oft wird statt “key1” die Jahreszahl der Key-Generierung gewählt, um das Alter der verwendeten Schlüssel zu erkennen.
  • bits: 2048 Bit Schlüssellänge sind heutzutage Standard. DNS-Server können längere Schlüssel oft nicht aufnehmen, daher sind 2048 Bit die beste Wahl.
  • directory: Der Key wird im Unterverzeichnis “keys” abgespeichert

Nach der Generierung sollten sich im Unterverzeichnis “keys” zwei neue Dateien befinden: “key1.private” und “key1.txt” (oder anders benannt, je nach verwendetem Selektor). Die erste Datei enthält den geheimen Schlüssel für die Signierung. Die zweite Datei enthält den öffentlichen Schlüssel in Form eines DNS-Records. Der Inhalt der key1.txt wird am besten wie folgt mit nano geöffnet:

nano -$ keys/key1.txt

… und sieht z.B. so aus:

2016._domainkey IN  TXT ( "v=DKIM1; k=rsa; "
      "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2VfV+CufdwZOeEGMr2owEtnomcsiELEOdYSpf
6WUHo0PqjVsm6ftsRu+7f45WZXyXCE/BL/FPRPL71M9CXCMNTkJgCCA061U29KT2q9dPyi8j6Kb64yDxeRq/RrSQQu
yarGnR7a/rvTjMS69FUCOeRYQfJQMRKEQ4bD/NFdEUKqaFFuDRObEY+V57yEdBEJ1oP6cyeGnj8IXKN"
      "0XfxCQOdDI16KpueA4uXLtyEpol+GBpTBr94yqt4u+RnwFSbIJhJUh4Aw/KuZzvFu4ikTbNC/EF/IwSsREd
3MhUcjXAhIbuO5XslAFvv7o06mLSWGekDslb11JoR2DjUfp9IAVJQIDAQAB" )  ; ----- DKIM key 2016 for
localhost

Für alle verwendeten Domains (mysystems.tld, domain2.tld, domain3.tld) müssen auf Basis der vorherigen Ausgabe DNS-Records im jeweiligen Zonefile der Domains angelegt werden, z.B.:

key1._domainkey.mysystems.tld. 3600 IN TXT "v=DKIM1; k=rsa; " "p=MIIBIjANBg [...] AVJQIDAQAB"
key1._domainkey.domain2.tld. 3600 IN TXT "v=DKIM1; k=rsa; " "p=MIIBIjANBg [...] AVJQIDAQAB"
key1._domainkey.domain3.tld. 3600 IN TXT "v=DKIM1; k=rsa; " "p=MIIBIjANBg [...] AVJQIDAQAB"

Mit den beiden Konfigurationseinstellungen “KeyTable” und “SigningTable” in der Konfiguration oben wird bestimmt, welche Domain mit welchem Schlüssel signiert werden soll. In der “KeyTable” werden alle verfügbaren Keys aufgeführt: (Datei /etc/opendkim/keytable erstellen:)

keytable Inhalt:

default    %:key1:/etc/opendkim/keys/key1.private

Bedeutung: Der Key namens “default” gilt für alle Domains (%) in Kombination mit dem Selektor “key1” und befindet sich in der Datei key1.private.

Das %-Zeichen führt dazu, dass bei einer Verifizierung der DKIM-Signatur durch einen fremden Mailserver das Zonefile der Absenderdomain nach einem DKIM-Record mit Public-Key durchsucht wird. (% wird bei der Verarbeitung von OpenDKIM durch die Absenderdomain ersetzt). Das heißt nichts anderes, als dass für jede Absender-Domain (mysystems.tld, domain2.tld und domain3.tld) ein DKIM-Record im DNS existieren muss. Es ist auch möglich, das %-Zeichen durch eine fixe Domain z.B. mysystems.tld zu ersetzen. Es spielt dann keine Rolle mehr, unter welche Domain ein Absender fällt: Es wird immer unter mysystems.tld nach einem passenden DKIM-Publickey gesucht. Das bedeutet weniger Aufwand, weil nur noch ein einziger DKIM-Eintrag verwaltet werden muss, und nicht mehr für jede Absenderdomain ein eigener. Allerdings ist diese Vorgehensweise umstritten und wird nicht von allen Mailprovidern unterstützt. Es ist daher besser, die Variante mit “%” zu nutzen und für jede Domain den entsprechenden DKIM-Eintrag im DNS zu hinterlegen.

Eine weitere Datei “/etc/opendkim/signingtable” wird erstellt. Sie teilt bestimmten Absendern bestimmte Schlüssel zu. In unserem Fall sollen alle E-Mails unter den eigenen Domains mit dem “default”-Schlüssel signiert werden:

signingtable Inhalt:

*@mysystems.tld default
*@domain2.tld default
*@domain3.tld default

Der erste Teil in jeder Zeile ist dabei ein regulärer Ausdruck. *@mysystems.tld führt also dazu, dass für alle Absender mit @mysystems.tld-Adresse der default-Key benutzt wird. Wenn für bestimmte Personen ein eigener Key verwendet werden soll, kann man das mit der vollständigen Angabe einer E-Mail-Adresse so spezifizieren.

Da wir zum Signieren sowieso immer denselben Key verwenden, kann der Inhalt der signingtable auch durch diese Zeile ersetzt werden:

* default

Damit werden alle ausgehenden E-Mails für alle Domains signiert. Das ist vor allem dann praktisch, wenn man sehr viele Domains mit seinem Server betreut und die OpenDKIM-Konfiguration nicht ständig aktualisieren will. Allerdings wird wirklich alles signiert, was nach draußen geht – das kann unter Umständen Probleme geben, wenn Postfix eine E-Mail im Namen eines fremden Users weiterleitet. Andererseits sind solche Weiterleitungen allein wegen SPF schon eine haarige Angelegenheit. Wenn ihr sicher gehen wollt, benutzt die ausführlichere Syntax (*@mysystems.tld…) oben. So könnt ihr für jede Domain einzeln und explizit DKIM ein- und ausschalten.

Nachdem die Konfiguration komplett ist, müssen noch Berechtigungen korrekt gesetzt werden. OpenDKIM benötigt Zugriff auf den DKIM-Schlüssel:

chown opendkim /etc/opendkim/keys/key1.private

… und Postfix wird Teil der opendkim-Gruppe, um auf den OpenDKIM-UNIX-Socket zugreifen zu können:

usermod -aG opendkim postfix

Amavis installieren und konfigurieren

Das Content Filter Framework Amavis bekommt eingehende E-Mails von Postfix via Milter (amavisd-milter) zur Überprüfung übermittelt, bevor sie vollständig angenommen und in die Queue aufgenommen werden (=> Pre-Queue-Filter).

Amavis installieren:

apt install amavisd-new libdbi-perl libdbd-mysql-perl

Amavis stoppen:

systemctl stop amavisd-new

Die Konfigurationsdatei /etc/amavis/conf.d/50-user soll folgenden Inhalt haben:

use strict;

##
## Die Kommunikation mit Amavis soll über einen Unix-Socket und über das AM.PDP-Prokoll erfolgen.
## amavisd-milter nimmt E-Mails von Postfix über die Milter-Schnittstelle bereit und übersetzt das Milter-Protokoll
## in das AM.PDP-Protokoll, da Amavis selbst kein Milter-Protokoll unterstützt.
## Postfix === Milter-Protokoll ===> Amavisd-Milter === AM.PDP-Protokoll ===> Amavis (und zurück)
##
$protocol = "AM.PDP";
$unix_socketname = "/var/run/amavis/amavisd.sock";
$inet_socket_port = undef;


##
## Policy-Bank für E-Mails von Mailclients
## E-Mails, die durch den Submission-Port für Mailclients in das Mailsystem gelangen, bekommen via Postfix-Option
## -o milter_macro_daemon_name=ORIGINATING eine "Markierung" mit "ORIGINATING". Amavis soll diese "Markierung" erkennen
## und in diesem Fall keine Untersuchung auf Spam durchführen.
## Lokale Absender (z.B. via mailx-Kommando) sind von der Spam-Untersuchung nicht betroffen, da Amavis sie automatisch als
## solche (Client 127.0.0.1) erkennt.
##

$policy_bank{'ORIGINATING'} = {
    originating => 1,
    bypass_spam_checks_maps => [1]
};


###
### Für welche Domains ist der Mailserver zuständig?
### => Datenbank befragen
###

@local_domains_maps = ( [] );

@lookup_sql_dsn = ( ['DBI:mysql:database=vmail;host=127.0.0.1;port=3306', 'vmail', 'vmaildbpass'], );

$sql_select_policy = 'SELECT "Y" as local, 1 as id FROM domains WHERE CONCAT("@",domain) IN (%k)';
$sql_select_white_black_list = undef;


##
## DKIM-Verifizierung aktivieren
## Amavis prüft DKIM-Signaturen eingehender E-Mails (falls vorhanden).
## Ist die Signatur in Ordnung, wird der Spam-Score nach unten korrigiert.
##

$enable_dkim_verification = 1;

###
### Spamassassin settings
###

### Spam-Checks aktivieren
@bypass_spam_checks_maps = (\%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re);
$sa_tag_level_deflt = -999;         # Informationen zu Spam-Score ab diesem Level (hier: immer) in den Header schreiben
$sa_tag2_level_deflt = 6.2;         # Ab diesem Level E-Mails als Spam markieren
$sa_kill_level_deflt = 6.9;         # Ab diesem Level E-Mails nicht annehmen, sondern Aktion in "final_spam_destiny" auslösen (REJECT)

$sa_spam_subject_tag = undef;       # Kein ***SPAM*** in den Betreff schreiben, falls Spam
$spam_quarantine_to = undef;        # Spam nicht in die Quarantäne verschieben
$final_spam_destiny = D_REJECT;     # Aktion, wenn kill_level erreicht wurde: E-Mail nicht annehmen und REJECT auslösen


###
### Falls Benachrichtigungsmails an User geschickt werden sollen (z.B. bei geblockter Mail)
###

$notify_method  = 'smtp:[127.0.0.1]:25';


#------------ Do not modify anything below this line -------------
1;  # ensure a defined return

Die Amavis-Konfiguration enthält Datenbank-Zugangsdaten und wird deshalb vor dem Zugriff durch nicht privilegierte Systemuser geschützt:

chmod 770 /etc/amavis/conf.d/50-user

Amavisd-Milter installieren

Amavisd-Milter ist der Vermittler zwischen Postfix und Amavisd und übersetzt das Milter-Protokoll in das AM.PDP-Protokoll. Leider enthalten die Ubuntu-Repositories nur eine veraltete Version von amavisd-milter, die mit der “ORIGINATING”-Markierung (siehe oben) nicht umgehen kann. Deshalb müssen wir Amavisd-Milter Version 1.6.1 von Hand herunterladen, kompilieren und installieren:

cd ~
wget 'https://github.com/ThomasLeister/amavisd-milter/archive/master.zip' -O amavisd-milter.zip

Zum Kompilieren werden GCC, die Library “libmilter-dev” und “make” benötigt – zum Entpacken “unzip”:

apt install gcc libmilter-dev make unzip

Entpacken, konfigurieren, kompilieren und installieren:

unzip amavisd-milter.zip
cd amavisd-milter-master
./configure
make
make install
make clean

Die Quelldateien können gelöscht werden:

cd ~
rm -r amavisd-milter-master
rm amavisd-milter.zip

Unter /usr/local/sbin/ sollte jetzt das Binary “amavisd-milter” zu sehen sein. Für die komfortablere Steuerung von amavisd-milter wird noch Init-Script für systemd unter /etc/systemd/system/amavisd-milter.service angelegt:

[Unit]
Description=Amavis Milter Interface amavisd-milter
Requires=amavisd-new.service
After=amavisd-new.service

[Service]
User=amavis
Group=amavis
PermissionsStartOnly=true
Type=forking
PIDFile=/var/run/amavis/amavisd-milter.pid

ExecStart=/usr/local/sbin/amavisd-milter -B -p /var/run/amavis/amavisd-milter.pid -w /var/lib/amavis -s /var/run/amavis/amavisd-milter.sock -S /var/run/amavis/amavisd.sock -m 2
ExecStartPost=/bin/chown postfix:postfix /var/run/amavis/amavisd-milter.sock
ExecStartPost=/bin/chmod 0660 /var/run/amavis/amavisd-milter.sock

KillMode=process

[Install]
WantedBy=multi-user.target

Skript aktivieren:

systemctl enable amavisd-milter

(Wer nicht mit Ubuntu 16.04 arbeitet, sondern z.B. mit Ubuntu 14.04, kann alternativ dieses init.d-Script nutzen, das ein Leser bereitgestellt hat: https://gist.github.com/anonymous/b1744df1533bd59ead8b5d70e2769de3) Spamassassin installieren

Spamassassin installieren:

apt install spamassassin

Spamassassin für MySQL konfigurieren

Spamassassin kann anhand von Beispielen besser auf die Erkennung von Spammails trainiert werden. Erlernte Spammails und harmlose Mails werden dazu in einer Datenbank abgespeichert. Standardmäßig nutzt Spamassassin eine BerkeleyDB in Form einer Datei, was die Performance allerdings stark einschränkt und das Teilen der vorhandenen Datenbasis erschwert. Sinnvoller ist es, die Trainingsdaten in einer MySQL-Datenbank abzuspeichern. Für diese Zwecke wird eine separate Datenbank auf dem DB-Server angelegt. Loggt euch als MySQL-root ein, legt eine neue Datenbank “spamassassin” an und gebt einem neuen User Zugriff auf diese Datenbank:

mysql -u root -p

create database spamassassin;
grant all on spamassassin.* to 'spamassassin'@'localhost' identified by 'spamasspwd';

quit;

Nun muss noch das passende Tabellenschema in die neue Datenbank geladen werden:

cat /usr/share/doc/spamassassin/sql/bayes_mysql.sql | mysql -u root -p spamassassin

(Passwort für MySQL-User root wird abgefragt)

In der Postfix-Konfigurationsdatei /etc/mail/spamassassin/local.cf wird Spamassassin auf eine MySQL-Anbindung umgestellt. Der Inhalt der Konfigurationsdatei besteht zu diesem Zeitpunkt nur aus Kommentaren, die via

> /etc/mail/spamassassin/local.cf

entfernt werden können. Gebt der Datei danach folgenden Inhalt:

bayes_store_module Mail::SpamAssassin::BayesStore::MySQL
bayes_sql_dsn DBI:mysql:spamassassin:localhost
bayes_sql_username spamassassin
bayes_sql_password spamasspwd
bayes_sql_override_username vmail

Das Datenbank-Passwort muss selbstverständlich angepasst werden. Von nun an speichert Spamassassin sämtliche Trainingsdaten in der performanten MySQL-Datenbank. Ein weiterer Vorteil liegt darin, dass verschiedene User nun unkompliziert über das sa-learn-Tool Spamassassin-Training mit Spammails durchführen können. Das nutzen wir mit Dovecot und dem Antispam-Modul bereits aus.

local.cf enthält Zugangsdaten zur Datenbank und wird deshalb besonders geschützt. Standardmäßig hat jeder Systembenutzer Lesezugriff auf die Datei. Dieser wird nun entfernt:

setfacl -m o:--- /etc/mail/spamassassin/local.cf

Die User “vmail” und “amavis” benötigen dennoch Zugriff auf die Datei, um korrekt mit Spamassassin arbeiten zu können. Ihnen wird Lesezugriff über eine ACL gewährt:

setfacl -m u:vmail:r /etc/mail/spamassassin/local.cf
setfacl -m u:amavis:r /etc/mail/spamassassin/local.cf

(u.U muss zuvor noch das Paket “acl” installiert werden: “apt install acl”)

Spamassassin Wartungsscript erstellen

Das Wartungsscript wird via Cronjob täglich ausgeführt und die Aufgabe, die offiziellen Filterregeln von Spamassasson.org und die Netzwerk-eigenen Filterregeln von mailbox.org zu aktualisieren.

Das Script wird unter /root/sa-care.sh angelegt und hat diesen Inhalt:

#!/bin/bash

sa-update --nogpg --channel spamassassin.heinlein-support.de
sa-update --channel updates.spamassassin.org

Script ausführbar machen:

chmod u+x sa-care.sh

Das Script wird in die Cronjobs von root aufgenommen:

crontab -e

# Spamassassin care
@daily /root/sa-care.sh

Führt das sa-care.sh abschließend einmal aus, um die Filterregeln zu aktualisieren:

./sa-care.sh

Razor und Pyzor installieren

Das gemeinschaftliche Razor-Netzwerk hilft, Spam über Prüfsummen zuverlässiger zu erkennen:

apt install razor pyzor

Als User “amavis” einloggen:

sudo -i -u amavis

Bei Razor registrieren und Serverliste downloaden:

razor-admin -create
razor-admin -register
pyzor discover

“amavis”-User wieder verlassen:

exit

Spamassassin wird das Razor-Netzwerk für die Spamerkennung automatisch nutzen.

Datenbank mit Datensätzen füllen

Bevor der Mailserver sinnvoll genutzt werden kann, müssen noch Domains und Benutzer im der MySQL-Datenbank registriert werden. Loggt euch wieder auf der MySQL-Kommandozeile ein:

mysql -u root -p

… und wechselt in die vmail-Datenbank:

use vmail

Neue Domain anlegen

Damit ein neuer Benutzeraccount oder ein neuer Alias angelegt werden kann, muss die zu nutzende Domain zuvor im Mailsystem bekannt gemacht werden. Postfix verarbeitet nur E-Mails an Domains, die in der “domains”-Tabelle eingetragen sind:

insert into domains (domain) values ('mysystems.tld');

Neuen E-Mail-Account anlegen

Wenn die Benutzerdomain in der Domain-Tabelle angelegt ist, kann ein neuer Benutzeraccount für den Mailserver erstellt werden:

insert into accounts (username, domain, password, quota, enabled, sendonly) values ('user1', 'mysystems.tld', '$kgid87hdenss', 2048, true, false);

$kgid87hdenss steht hier stellvertretend für einen SHA512-CRYPT String, der vor Abschicken des SQL-Statements mit dem Kommando

doveadm pw -s SHA512-CRYPT

in der Linux-Kommandozeile generiert werden kann. Statt das Passwort im Klartext in der Datenbank zu hinterlegen, wird ein starker kryptographischer Hash des Passworts hinterlegt. Das bringt den Vorteil, dass Passwörter von einem Eindringling nicht aus der DB ausgelesen werden können (Wichtiges Sicherheitsfeature!). Der Hash-String hängt nicht nur von dem verwendeten Passwort ab und verändert sich deshalb von Mal zu Mal. Wundert euch also nicht, wieso ihr jedes mal einen anderen Hash-String bekommt, obwohl ihr dasselbe Passwort nutzt ;-) Tipp: Speichert am besten nicht nur den eigentlichen Hash ab “$6$” ab, sondern nehmt den vorderen Teil ({SHA512-CRYPT} …) mit. Das hilft Dovecot, zu erkennen, welcher Hash-Typ vorliegt und kann bei der Migration von Passwort-Schemata sehr hilfreich sein!

Neuen Alias anlegen

insert into aliases (source_username, source_domain, destination_username, destination_domain, enabled) values ('alias', 'mysystems.tld', 'user1', 'mysystems.tld', true);

… legt einen Alias für den Benutzer “user1@mysystems.tld” an. E-Mails an “alias@mysystems.tld” werden dann an die Mailbox dieses Users zugestellt.

Als Zieladressen können auch E-Mail-Konten auf fremden Servern angegeben werden. Postfix leitet diese E-Mails dann weiter. Dabei kann es allerdings zu Problemen mit SPF-Records kommen – schließlich schickt Postfix unter bestimmten Umständen E-Mails unter fremden Domains, für die er laut SPF-Record nicht zuständig ist. SRS (Sender Rewriting Scheme) ist eine Lösung für dieses Problem. Von Erweiterungen, die schwerwiegende Design-Fehler einer Technik wie SPF korrigieren, halte ich allerdings nicht besonders viel, sodass ich euch empfehle, den SPF-Record (wie oben) auf einem “?all” gestellt zu lassen und auf Weiterleitungen zu fremden Servern möglichst zu verzichten. Aliase von lokalen Adressen auf andere lokale Adressen sind kein Problem.

Wenn ein E-Mail-Verteiler eingerichtet werden soll, müssen mehrere Datensätze mit derselben Quelladresse eingerichtet werden, also so:

team@domain.tld => user1@domain.tld
team@domain.tld => user2@domain.tld
team@domain.tld => user3@domain.tld

… etc

Neue TLS-Policy anlegen

Mithilfe der TLS Policy-Tabelle kann festgelegt werden, mit welchen Sicherheitsfeatures mit den Mailservern einer bestimmten Domain kommuniziert werden soll. Wenn für die Domain “thomas-leister.de” beispielsweise “dane-only” in “policy” festgelegt wird, wird die Verbindung zu Mailservern dieser Domain nur noch gültig sein, wenn sie DANE-authentifiziert und verschlüsselt ist. Mögliche Policies sind:

  • none: Keine Verschlüsselung nutzen, auch wenn der andere Mailserver das unterstützt.
  • may: Verschlüsseln, wenn der andere Server dies unterstützt, aber keine Zertifikatsprüfung (self-signed Zertifikate werden akzeptiert).
  • encrypt: Zwingend Verschlüsseln, allerdings keine Zertifikatsprüfung (self-signed Zertifikate werden akzeptiert).
  • dane: Wenn gültige TLSA-Records gefunden werden, wird zwingend verschlüsselt und das Zertifikat mittels DANE verifiziert. Falls ungültige TLSA-Records gefunden werden, wird auf “encrypt” zurückgegriffen. Falls gar keine TLSA-Records gefunden werden, wird “may” genutzt.
  • dane-only: Nur verschlüsselte Verbindungen. Gültige TLSA-Records für den Hostnamen müssen existieren (DANE)
  • verify: Nur verschlüsselte Verbindungen + Prüfung der CA. Der Hostname aus dem MX DNS-Record muss im Zertifikat enthalten sein. (Basiert auf Vertrauen in korrekte DNS-Daten)
  • secure: Nur verschlüsselte Verbindungen + Prüfung der CA. Der andere Mailserver muss (standardmäßig) einen Hostnamen haben, der “.domain.tld” oder nur “domain.tld” entspricht. Dieser Hostname muss im Zertifikat enthalten sein. Auf das DNS wird nicht zurückgegriffen (Sicherheitsvorteil gegenüber “verify). Beispiel: Eine E-Mail an user@web.de soll gesendet werden. Der MX-Mailserver von Web.de dürfte dann nur den Hostnamen “web.de” oder eine Subdomain davon als Hostnamen haben, z.B. mx.web.de. Eine Verbindung zu mx.web.net wäre nicht zulässig.

Für Domains der großen Anbieter wie gmx.de, web.de und der Telekom kann man “secure” wählen. Bei Posteo und Mailbox.org sogar “dane-only”. Für alle Provider, die keine gültigen TLS-Zertifikate einsetzen, kann “encrypt” gewählt werden. Standardeinstellung für alle anderen Mailserver ist “dane” (siehe main.cf der Postfix Config).

Das Feld “params” wird mit zusätzlichen Infos gefüllt, wenn sie für einen Policy-Typ erforderlich sind, z.B. für einen “secure” Eintrag zu GMX:

insert into tlspolicies (domain, policy, params) values ('gmx.de', 'secure', 'match=.gmx.net');

Standardmäßig überprüft Postfix bei “secure” – wie oben bereits erwähnt – ob die Empfängerdomain (gmx.de) im Zertifikat des Zielservers vorhanden ist. Bei GMX (und vielen anderen großen Anbietern) ist das allerdings nicht der Fall: Die Mailserver-Zertifikate von GMX sind nur für gmx.net + Subdomains gültig. Ließe man den Datenbank-Eintrag für GMX ohne weitere Einstellungen auf “secure” stehen, könnten an GMX keine Mails mehr übermittelt werden. Deshalb ist es wichtig, für GMX festzulegen, dass im Zertifikat nicht nach “gmx.de” sondern nach “gmx.net” gesucht werden soll. Das können wir mithilfe des Felds “params” und der “match=…” Zeichenkette tun. Wenn nach mehreren Domains gesucht werden soll, können auch mehrere angegeben werden, z.B. so: “match=.gmx.net:.gmx.ch”. Die zusätzlichen Angaben in “params” sind allerdings nicht für jeden Mailprovider notwendig. GMX ist eine Ausnahme – genauso wie z.B. Yahoo. Ob ihr in “params” einen “match”-String angeben müsst, könnt ihr z.B. über https://de.ssl-tools.net/ herausfinden. Wenn die 2-nd-Level-Domain des Mailservers von der Domain der Mailadressen abweicht, muss ein passender match-String angegeben werden.

Andere Einstellungen wie “dane-only” erfordern keine zusätzlichen Angaben in “params”:

insert into tlspolicies (domain, policy) values ('mailbox.org', 'dane-only');

In diesem Fall wird mit den Mailservern von mailbox.org nur noch DANE-gesichert und verschlüsselt kommuniziert.

Die MySQL-Kommandozeile kann mit einem “quit” wieder verlassen werden.

Hier hat jemand auf GitHub eine Liste mit verschiedenen Mailprovidern und den möglichen TLS Policies zusammengestellt: https://github.com/csware/postfix-tls-policy/blob/master/tls_policy-dane

Lukas Zorn (siehe Kommentare, Danke!) hat sich die Mühe gemacht, fertige SQL Inserts für einige Mailprovider zu erstellen. Ich habe eine Kopie als Github Gist veröffentlicht: https://gist.githubusercontent.com/ThomasLeister/c9d16205318ab3dc68b13923a6ceab93/raw/6ae2ee86d42ec280f3459d09d20f4ef800da4cab/tlspolicies.sql

Hinweis vom 30.05.2017: Die genannten Listen sind nicht mehr aktuell!

Start all the things!

Euer neuer Mailserver ist jetzt fertig konfiguriert. Zeit für einen ersten Start!

systemctl start dovecot
systemctl start amavisd-new
systemctl start amavisd-milter
systemctl start opendkim
systemctl start postfix

Kontrolliert am besten gleich die Logfiles nach auffälligen Fehlern. Ich empfehle das “tail” Tool in einer separaten Terminal-Sitzung. Neue Log-Einträge erscheinen damit sofort auf dem Bildschirm:

tail -f /var/log/syslog

Wenn ihr hier Fehler entdeckt, seht nach, ob ihr alle erforderlichen Änderungen an den Konfigurationsdateien durchgeführt habt. (Siehe auch: “Thomas, mein Mailserver funktioniert nicht!” weiter unten) Eine Verbindung zum Mailserver herstellen

Eine Verbindung könnt ihr über jeden IMAP-fähigen E-Mail-Client und den folgenden Verbindungsparametern herstellen:

  • IMAP-Server: mail.mysystems.tld | Port: 143 | STARTTLS (auch für domain2 und domain3!)
  • SMTP-Server: mail.mysystems.tld | Port: 587 | STARTTLS (auch für domain2 und domain3!)
  • (optional Managesieve: mail.mysystems.tld | Port: 4190 | STARTTLS) (auch für domain2 und domain3!)
  • Benutzername: Die volle E-Mail-Adresse
  • Passwort: Sollte bekannt sein ;-)

Spamfilter testen

Schickt einfach eine E-Mail mit dem Text

XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X

an einen Account eures neuen Mailservers. Die E-Mail sollte nicht ankommen. In den Logs sollte zu lesen sein, dass die Mail von Amavis wegen Verdachts auf Spam abgelehnt wurde.

Hat dir diese Anleitung geholfen?

Wenn ich dir mit dieser Anleitung helfen konnte, deinen Mailserver aufzusetzen, ist dir das vielleicht ein paar Euros wert. Wie du dir sicherlich vorstellen kannst, war es eine Menge Arbeit, diese Anleitung zu erproben und zu formulieren. Da freue ich mich natürlich riesig über ein wenig finanzielle Unterstützung, sodass ich beispielsweise Testserver für diese und andere Anleitungen mieten kann. Wie du mir etwas zukommen lassen kannst, erfährst du hier: Unterstützen

Herzlichen Dank! :-)

Passend zu dieser Anleitung …

Rainloop-Plugin für Aliase

Neomedes hat ein Rainloop-Plugin veröffentlicht, über das sich innerhalb der beliebten Webmail-Oberfläche neue Aliase für das eigene Konto anlegen lassen: https://github.com/Neomedes/rainloop-plugin-aliaslist-mysql


“Thomas, mein Mailserver funktioniert nicht!”

Das passiert leider hin und wieder. Diese Anleitung habe ich nach Fertigstellung zwar selbst nochmals auf einem jungfräulichen System Schritt für Schritt (und mehrmals) ausprobiert, dennoch kann es sein, dass du dich beim Konfigurieren vertippt hast oder einen Schritt versehentlich übersprungen hast. In dem Fall kannst du deinen kompletten Server einstampfen und alles neu einrichten – oder du suchst gezielt nach dem Fehler und versuchst, ihn zu beheben:

Schritt 1: Logfiles analysieren

Das Mailsystem ist ziemlich mitteilungsfreudig und loggt sämtliche Vorgänge das Syslog. Nutze “tail -f”, um die neuesten Log-Einträge zu sehen:

tail -f /var/log/syslog

Fehlermeldungen sollten auch für ungeübte relativ schnell auffindbar sein. Meistens kommt in solchen Meldungen irgendwo “error” oder “failed” vor.

Schritt 2: Fehlerquelle finden

Das ist leichter gesagt, als getan. Trotzdem können einige Fehler schnell gefunden und behoben werden. Ein

Connect failed to database

oder

table lookup problem

deutet beispielsweise stark darauf hin, dass mit der Datenbankverbindung etwas nicht stimmt. Welche Ursachen kommen dafür in Frage? Z.B.:

  • Nicht erreichbarer Datenbank-Server
  • Falscher DB-Benutzername, Passwort oder DB-Name
  • Fehlende Tabellenstrukturen
  • Nicht ausreichende Berechtigungen für den Zugriff auf die DB

Ihr glaubt gar nicht, wie viele “Hilfe, nichts geht!"-E-Mails ich schon von Lesern bekommen habe, weil Passwörter falsch in die Konfiguration übertragen wurden ;-)

Wenn du die Ursache selbst nicht finden kannst

  • … führt der Weg immer zuerst zu Google. Einfach die Fehlermeldung oder das Symptom (am besten in englischer Sprache) suchen, und das erste Stackoverflow-Ergebnis anklicken ;-) Die meisten Probleme können durch Stackoverflow-Threads oder Einträge aus Mailinglisten gefunden und behoben werden. Wenn du an dem Problem verzweifelst

  • … lohnt es sich oft, einen Kollegen oder Freund / bekannten zu Rate zu ziehen. Am besten jemanden, der sich mit Mailservern beschäftigt, und das Symptom vielleicht schon kennt. Alternativ kann man sich auch Hilfe in Foren wie forum.ubuntuusers.de oder natürlich auf Stackoverflow und anderen bekannten Plattformen holen.

“Kannst du mir nicht helfen?”

Möglicherweise. Ich möchte allerdings nicht – und ich denke das ist verständlich – täglich mit der Fehleranalyse von Mailsystemen beschäftigt sein. Schreibe mir bitte nur, wenn …

  • Selbst versucht hast, das Problem zu lösen
  • Sonst keinen Rat mehr weißt

Lieber ist es mir, wenn Hilfe in den dafür vorgesehenen Linux-Foren, z.B. auf ubuntuusers.de gesucht wird. Eine evtl. Problemlösung ist dann auch anderen Nutzern zugänglich.

Fragen und Antworten

“Danke für die Anleitung. Kann ich mich irgendwie revanchieren?”

Über ein “Dankeschön” via E-Mail freue ich mich, aber z.B. auch über eine kleine Finanzspritze für meinen Blog via Bitcoin, PayPal oder auf anderem Wege. Damit kann ich beispielsweise meine Server bezahlen. Vielleicht magst du diesen Beitrag auch weiterempfehlen? Auch dafür bin ich dankbar :-)

“Kannst du mir meinen Mailserver aufsetzen?”

Klar! Gegen einen angemessenen Obolus bin ich dazu gerne bereit. Schreibe mir dazu einfach eine E-Mail.

“Wieso noch eine Mailserver-Anleitung? Es gibt doch schon so viele!”

Tatsächlich kann man den Eindruck haben, zu jedem Linux-Blog gehöre mittlerweile ein E-Mail Tutorial. Natürlich habe ich darüber nachgedacht, ob es überhaupt sinnvoll ist, den Aufwand zu betreiben, und die tausendste Anleitung dazu zu schreiben. Aber natürlich habe ich gute Gründe: Ich bin während meiner ersten Schritte zum eigenen Mailserver fast verzweifelt: Es gibt zwar Unmengen an Mailserver-Anleitungen im Netz, und trotzdem gibt es zu viele How-Tos, die nie wirklich getestet wurden oder schon veraltet sind. Diese Anleitung wurde mehrmals auf einem frisch installierten Ubuntu Server getestet. Ich kann also bis zu einem gewissen Grad garantieren, dass euer Mailserver funktioniert, wenn ihr die Anleitung exakt durcharbeitet. Einige Artikel zum Thema finde ich auch nicht ausführlich genug. Wie Eingangs schon erklärt, geht es mir bei diesem Beitrag auch darum, ein wenig zu erklären, was hier eigentlich passiert. Und nicht zuletzt: Es gibt diese Anleitung, weil ich der Meinung bin, dass es nicht genug geben kann. Jeder Autor erklärt etwas anders, jeder stellt ein leicht verändertes Setup vor. Ich hatte Lust, mein eigenes Setup in diesem Beitrag zu erklären, weil es gut funktioniert.

“Darf ich deine Anleitung übernehmen?”

Nein. Du kannst dir sicherlich vorstellen, dass hinter meiner Anleitung viel Mühe und Arbeit steckt. Ich stelle sie nicht frei zur Verfügung und bitte darum, meinen Text nicht ohne ausdrückliche Zustimmung zu re-publizieren (auch nicht in privaten, aber öffentlich zugänglichen Blogs!). Also ein klares “Nein” zu Copy & Paste + Wiederveröffentlichung. Private, nicht-öffentliche Kopien oder Kopien für den Firmen-internen Gebrauch sind natürlich erlaubt. Es geht mir auch darum, diesen Beitrag nicht auf irgendeinem fremden Blog wiederzufinden, der womöglich sogar noch Geld mit fremden Content verdient. Verlinken ist natürlich absolut erlaubt und ausdrücklich erwünscht ;-)

“Wieso veröffentlichst du deine Anleitung auf deinem Blog und nicht in einem Wiki?”

Weil ich hier die volle Kontrolle habe. Was hier steht, ist in sich konsistent und kein Flickenteppich. In den gängigen Wikis darf dieser Beitrag natürlich gerne ergänzend verlinkt werden.

“Gibt es für dieses neue Mailserver-Setup schon einen Web-Client zur Verwaltung?”

Aktuell ist WebMUM nicht mit dieser Anleitung kompatibel. Solltet ihr das ändern wollen – nur zu. Der Code ist auf GitHub unter der MIT Lizenz frei verfügbar. Vielleicht beginne ich demnächst mit der Entwicklung eines neuen Verwaltungstools speziell für dieses Setup. Ansonsten steht es natürlich jedem frei, selbst ein solches Werkzeug zu entwickeln und vielleicht sogar frei verfügbar zu machen. Im Wesentlichen müssen nur Datensätze erstellt, bearbeitet und gelöscht werden. Das kann man z.B. auch als PHP-Anfänger gut umsetzen.

Update am 14.07.2017: Andreas Bresch hat ein Webinterface zu dieser Anleitung entwickelt: https://github.com/Andreas-Bresch/vmailManage/

Wie kann ich mit diesem Setup Catch-All Adressen realisieren?

Dazu sind ein paar Änderungen notwendig. Ich habe mich mit der Thematik noch nicht selbst befasst, aber ein Leser hatte hiermit Erfolg:

  1. source_username in aliases Tabelle als nullable (= null bei catchall) konfigurieren. In der MySQL-Kommandozeile:

    alter table aliases modify source_username varchar(64) null;

  2. Die Query in aliases.cf anpassen

    query = SELECT concat(destination_username, ‘@’, destination_domain) as destinations FROM aliases WHERE source_username ='%u' and source_domain ='%d' and enabled = true UNION ALL SELECT concat(destination_username, ‘@’, destination_domain) as destinations FROM aliases WHERE source_username is null and source_domain ='%d' and enabled = true AND not exists (SELECT id FROM aliases WHERE source_username ='%u' and source_domain ='%d' and enabled = true);

Ich habe das nicht getestet!

“Wieso benutzt du nicht einfach Amavis als Content-Filter? Wieso das umständliche Setup mit Amavis als Milter?”

Amavis kann als Content-Filter keine E-mails Pre-Queue abweisen, d.h. unerwünschte Mails werden von Postfix erst angenommen, um dann in der Queue zu landen und letztendlich nur gelöscht zu werden. Der Absender einer betroffenen E-Mail erhält keine Information darüber, dass seine E-Mail beim Empfänger nicht angekommen ist. Das ist rechtlich bedenklich, denn solche E-Mails gelten als zugestellt. Filtert der Server wichtige E-Mails fälschlicherweise weg und erleidet der Empfänger dadurch einen Schaden, haftet der Provider. Die bessere Lösung ist es daher, E-Mails direkt beim Eingang wieder abzuweisen, sodass der Absender eine entsprechende Benachrichtigung zur Unzustellbarkeit erhält. Das direkte Abweisen beim Empfang ist im Betrieb als content_filter nicht möglich, deshalb muss Amavis Pre-Queue eingebunden werden. Dazu gibt es zwei Möglichkeiten: Amavis kann als smtpd_proxy_filter in dem smtpd-Service eingebunden werden (häufig gewählte Lösung) oder als Milter (Underground-Lösung) integriert werden. Ich habe mir für die wenig dokumentierte Milter-Lösung entschieden, denn auf amavis.org wird darauf hingewiesen, dass Amavis eigentlich nicht für den Betrieb als smtpd_proxy_filter konzipiert ist und es deshalb zu Problemen kommen könnte:

“The Postfix Before-Queue Content Filter setup, also known as smtpd_proxy setup, is not a supported or recommended setup with amavisd-new, which is not a transparent SMTP proxy by design. See caveats in README_FILES/SMTPD_PROXY_README. This setup might work amavisd-new for low-traffic sites which do not use authentication, but is not recommended.” – amavis.org

Der zweite Grund für die Integration als Milter statt smtpd_proxy_filter ist, dass SMTP-Filter nicht zusammen mit Miltern genutzt werden sollten. Man sollte sich für eines entscheiden: Nur smtpd_proxy_filter oder nur Milter. Da ich OpenDKIM als Milter einsetzen will, sollte auch Amavis als Milter eingebunden werden. Ich hatte eine kurze Zeit lang Amavis als smtpd_proxy_filter integriert und OpenDKIM als Milter. Das hat dazu geführt, dass OpenDKIM eingehende E-Mails nicht mehr als solche erkennen konnte und alles nur noch “ausgehend” war. Das Ergebnis war, dass Spammails, bei denen der Absender auf meine eigene Domain gefälscht war, beim Eingang von meinem eigenen Server DKIM-Signiert wurden. Dass das nicht der Sinn von DKIM ist, brauche ich euch nicht zu erklären.

Einen dritten Grund habe ich auch: Die Integration als Milter sieht in der Postfix-Konfiguration sauberer aus: Statt eines Reinjection-Services auf Port 10025 und einiger -o Parameter werden nur wenige milter_-Zeilen in der main.cf benötigt. Die Konfiguration wird dadurch schlanker und übersichtlicher.

“Wieso nutzt du OpenDKIM, und nicht die integrierten DKIM-Funktionen von Amavis?”

OpenDKIM als funktional getrennter Dienst, der alleine für die DKIM-Signierung ausgehender E-Mails zuständig ist, gefällt mir besser. Die Konfiguration ist übersichtlicher, und sämtliche E-Mails, die den Server unter den verschiedensten Domains verlassen, können mit wenigen Einstellungen signiert werden. Dazu kommt, dass Amavis bei sehr vielen eingehenden E-Mails bereits ausgelastet sein könnte. E-Mails, die nach draußen gehen sollen, können dann nicht gleich versendet werden und der Absender erhält in seinem Mailclient eine Fehlermeldung. ich habe lange überlegt, wie und ob ich Amavis / OpenDKIM / Milter nutze, und bin letztendlich zu dem Ergebnis gekommen, dass mir dieses getrennte Setup mit Miltern am besten gefällt: Amavis filtert eingehende E-Mails – OpenDKIM signiert ausgehende Mails.

“Wieso nutzt du UNIX-Sockets statt lokaler TCP-Sockets?”

UNIX-Sockets sind wesentlich performanter und ihrem Zweck schneller zuzuordnen.

Häufige Fehler

“fatal: no SASL authentication mechanisms” / “SASL: Connect to private/auth failed: No such file or directory”

Das Problem: Postfix kann Benutzer nicht authentifizieren, weil in /var/spool/postfix/private kein “auth” Socket verfügbar ist. Eigentlich sollte Dovecot diesen Socket bereitstellen. Der Fehler ist also bei Dovecot zu suchen – nicht bei Postfix. Leider hat die Erfahrung gezeigt, dass ein Vertipper nicht zwingend in der Socket-Konfiguration

unix_listener /var/spool/postfix/private/auth {
    mode = 0660
    user = postfix
    group = postfix
}

vorhanden sein muss. Es kommt immer wieder vor, dass der Fehler irgendwo anders in der Dovecot-Konfiguration liegt. Dovecot verschweigt einem dann den Fehler und erstellt den auth-Socket für Postfix nicht. Es lohnt sich in so einem Fall, noch einmal die ganze Dovecot-Konfiguration nach Fehlern abzusuchen. “5.7.1 Service unavailable; client [1.3.3.7] blocked using zen.spamhaus.org”

Das Problem: Der Mailserver akzeptiert keine E-Mails vom Mailclient und gibt die oben genannte Fehlermeldung zurück.

Das Problem lässt sich sehr einfach lösen, indem statt SMTP-Port 25 der Submission-Port 587 für den Mailversand im Mailclient konfiguriert wird. Auf Port 25 ist eine Blacklist aktiv, welche viele IP-Adressen z.B. aus DSL-Adressbereichen enthält. Diese Einschränkung gilt für Port 587 nicht. Mailclients sollten immer port 587 für den Versand nutzen.

Mailclient verbindet sich nicht zum Server

  • Evtl. blockiert der Virenschutz die Verbindung?
  • Blockiert die Server-Firewall die Verbindung von außen?
  • Ist die richtige Serveradresse angegeben? (siehe Verbindungseinstellungen oben)

Changelog

  • 22.04.2016

    • Spamassassin Training (sa-learn) entfernt: Siehe Kommentare
  • 26.04.2016

    • Amavis / Spamassassin via smtpd_proxy_filter eingebunden, um Spammails direkt beim Empfang ablehnen zu können
    • Für DKIM-Signierung wird jetzt OpenDKIM statt Amavis eingesetzt. Amavis kann seine Worker so zu 100% der Spamabwehr widmen. Durch den Einsatz von smtpd_proxy_filter hätte Amavis bei großer Inbound-Auslastung möglicherweise keine Worker mehr für die DKIM-Signierung bereitgestellt und E-Mails hätten den Mailserver nicht mehr verlassen können. Daher werden für Spamabwehr und DKIM-Signierung nun zwei verschiedene Softwarekomponenten eingesetzt.
    • Oracle MySQL statt MariaDB: MariaDB befindet sich nicht im “main” Repository von Ubuntu 16.04 und wird daher nicht von offizieller Seite Langzeit-unterstützt – MySQL hingegen schon. Aus dem Wechsel zu MySQL ergibt sich auch, dass für Amavis zusätzlich libdbi-perl und libdbd-mysql-perl installiert werden müssen, welche vorher automatisch durch MariaDB mitgeliefert wurden.
    • Ausführung von “newaliases” nach der Postfix-Installation ausführen, um Fehler im Log zu verhindern.
  • 28.04.2016

    • “newaliases” erst nach main.cf-Konfiguration, um Fehler bei der Ausführung des Kommandos zu vermeiden.
    • Cipherlists von bettercrypto.org aktualisiert
  • 01.05.2016

    • Amavis als Milter eingebunden (amavisd-milter hinzugefügt)
    • Wildcard-Hinweis zu OpenDKIM ergänzt
    • Unnötige oder veraltete Postfix-Einstellungen entfernt
    • Dovecot iterate_query korrigiert
  • 02.05.2016

    • -o receive_override_options=no_address_mappings entfernt. Hat dazu geführt, dass Aliase nicht mehr funktioniert haben und war ein Überbleibsel, das so nicht mehr in der Config sein sollte. Sorry!
  • 04.05.2016

    • Systemd-Service für Amavisd-Milter funktioniert nun auch nach Reboots zuverlässig.
    • In Dovecot-Config:
      • mail_max_userip_connections = 20 gesetzt
      • postmaster_address in lmtp-Bereich gesetzt
  • 05.05.2016

    • Weitere mailboxes “Trash”, “Sent” und “Drafts” zur Dovecot-Config hinzugefügt
  • 09.05.2016

    • Spamassassin-Datenbank: MySQL statt BerkeleyDB für einfacheren Zugriff und bessere Performance
    • Dovecot-Antispam für Spamassassin-Training bei Verschiebevorgang
  • 14.05.2016

    • $notify_method zu Amavis-Config hinzugefügt, damit Amavis Benachrichtugungsmails senden kann
  • 15.05.2016

    • certbot statt letsencrypt-auto
    • Dovecot Logging in dovecot.log entfernt, Logs werden nur noch in syslog geschrieben
    • dovecot-sql.conf, /etc/postfix/sql und /etc/mail/spamassassin/local.cf vor Zugriff durch andere Systemuser geschützt
    • Installation von “make” zum Kompilieren von amavisd-milter hinzugefügt
  • 16.05.2016

    • Amavis-Config 50-user durch chmod geschützt
    • Git-Installation hinzugefügt
  • 28.05.2016

    • Dateirechte für /etc/mail/spamassassin/local.cf korrigiert
    • Header Cleanup zu Postfix hinzugefügt für besseren Datenschutz
  • 03.06.2016

    • Postfix: message_size_limit auf 50 MB gesetzt. Standard war 10 MB, … ist in einigen Fällen zu wenig.
    • Hinweis zu E-Mail-Verteilern über Aliase ergänzt
  • 06.06.2016

    • Postfix: mailbox_size_limit = 0 gesetzt
  • 04.07.2016

    • OpenDKIM: Hetzner akzeptiert auch längere DKIM-Schlüssel, wenn diese in einzelne Strings unterteilt werden. Abschnitt zu den DKIM-Records wurde verbessert.
  • 10.07.2016

    • SQL-Dateien in /etc/postfix/sql benötigen keine x-Flag. Berechtigung angepasst.
  • 13.07.2016

    • Init.d-Script für Amavisd-Milter als Systemd-Alternative hinzugefügt
    • Amavisd-Milter auf eigene GitHub-Seite gespiegelt. Projektseite auf Sourceforge war nicht mehr erreichbar…. schnell noch den Code gesichert ;-)
  • 08.08.2016

    • Vor der Kompilierung von amavisd-milter muss GCC installiert werden.
  • 22.08.2016

  • 31.08.2016

    • Hinweis auf fertige TLS-Policy-Liste als SQL Inserts ergänzt.
  • 03.10.2016

    • -m 2 Argument zu Amavisd-Milter Service hinzugefügt.
  • 26.11.2016

    • dovecot-sql.conf: Connection-string in Anführungszeichen gesetzt, um Passwörter mit Sonderzeichen zu ermöglichen

Anleitung zuletzt vollständig geprüft: 15.05.2016

Danksagung

Ich möchte mich für alle Vorschläge, Ideen und gemeldete Fehler bedanken, die mir von meinen Lesern bisher zugetragen worden sind. Speziell Sebastian Rager bin ich dankbar für den regen Austausch und die vielen Verbesserungsvorschläge. :-)

Kommentare aus der alten Blog-Version

Nachdem ich den Blog umgestellt habe, sind die Kommentare zu diesem Beitrag nicht mehr auf dieser Seite enthalten. Es gibt jedoch eine Archiv-Version dieser Anleitung, in der die Kommentare eingesehen werden können: https://legacy.thomas-leister.de/sicherer-mailserver-dovecot-postfix-virtuellen-benutzern-mysql-ubuntu-server-xenial/