Im ersten Teil dieser Serie haben wir Dovecot mit lokalen Linux-Benutzern eingerichtet. Dabei entsprach jede Mailbox einem echten Benutzer auf dem Linux-System. Für den Einstieg ist das sehr hilfreich, weil man SMTP, IMAP, Maildir und die Authentifizierung gut nachvollziehen kann.
Für einen produktiven Mailserver ist dieses Konzept jedoch nur bedingt geeignet. In der Praxis möchte man nicht für jede E-Mail-Adresse einen eigenen Linux-Benutzer anlegen. Stattdessen werden sogenannte virtuelle Mailboxen verwendet.
In diesem Teil stellen wir den Mailserver daher auf folgende Architektur um:
Postfix
│
▼
Dovecot LMTP
│
▼
/var/vmail
Thunderbird
│
▼
Dovecot IMAP
│
▼
MariaDB
Am Ende dieses Artikels können virtuelle E-Mail-Konten wie info@example.de verwendet werden, ohne dass dafür ein Linux-Benutzer info existiert.
Ziel des zweiten Teils
Nach diesem Artikel haben wir:
- virtuelle Mailboxen unter
/var/vmail - einen eigenen Systembenutzer
vmail - MariaDB als Benutzerverwaltung
- Dovecot SQL-Authentifizierung
- Postfix Virtual Mailbox Domains
- Zustellung über Dovecot LMTP
- Anmeldung per Thunderbird mit vollständiger E-Mail-Adresse
- Unterstützung für virtuelle Aliase
Ausgangssituation
Dieser Artikel baut auf dem ersten Teil auf. Folgende Komponenten sollten bereits vorhanden sein:
- Debian 13
- Postfix
- Dovecot
- TLS-Zertifikat von Let’s Encrypt
- funktionierender IMAP-Zugriff
- funktionierender SMTP-Versand über Submission
- Dovecot SASL für Postfix
Bisher sieht die Mailzustellung vereinfacht so aus:
Postfix
│
▼
/home/tobias/Maildir
Dovecot authentifiziert Benutzer über PAM gegen die lokalen Linux-Benutzer:
Dovecot
│
▼
PAM
│
▼
/etc/shadow
Das ändern wir nun.
Warum virtuelle Mailboxen?
Bei lokalen Linux-Benutzern müsste für jede Mailbox ein eigener Systembenutzer angelegt werden:
tobias
info
support
rechnung
Dazu gehören dann Home-Verzeichnisse, Benutzer-IDs und theoretisch auch Systemzugänge. Für einen Mailserver ist das unpraktisch und unnötig. Mit virtuellen Mailboxen existiert auf dem Linux-System nur noch ein einziger technischer Benutzer. In meinem Fall der Benutzer vmail. Alle Mailboxen liegen dann beispielsweise unter:
/var/vmail/
└── example.de
├── info
│ └── Maildir
├── support
│ └── Maildir
└── rechnung
└── Maildir
Die Benutzer selbst werden nicht mehr in /etc/passwd, sondern in einer Datenbank verwaltet.
MariaDB für virtuelle Benutzer vorbereiten
Zuerst wird eine Datenbank für den Mailserver angelegt. Dazu muss als erstes in die MariaDB-Shell gewechselt werden:
mysql
Dann:
CREATE DATABASE mailserver;
CREATE USER 'mailuser'@'localhost'
IDENTIFIED BY 'EinSehrLangesPasswort';
GRANT ALL PRIVILEGES
ON mailserver.*
TO 'mailuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;
Der Benutzer mailuser wird später von Postfix und Dovecot verwendet, um Domains, Mailboxen und Aliase abzufragen.
Tabellen für Domains, Benutzer und Aliase anlegen
Nun werden die Tabellen erstellt.
mysql mailserver
Tabelle für virtuelle Domains
CREATE TABLE virtual_domains (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY name (name)
);
Diese Tabelle enthält alle Domains, für die der Server E-Mails annehmen soll.
Beispiel:
INSERT INTO virtual_domains
(name)
VALUES
('example.de');
Prüfen:
SELECT * FROM virtual_domains;
Tabelle für virtuelle Benutzer
CREATE TABLE virtual_users (
id INT NOT NULL AUTO_INCREMENT,
domain_id INT NOT NULL,
email VARCHAR(255) NOT NULL,
password VARCHAR(255) NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY email (email)
);
Diese Tabelle enthält die eigentlichen Mailboxen.
Beispiele:
info@example.de
support@example.de
rechnung@example.de
Tabelle für virtuelle Aliase
CREATE TABLE virtual_aliases (
id INT NOT NULL AUTO_INCREMENT,
domain_id INT NOT NULL,
source VARCHAR(255) NOT NULL,
destination VARCHAR(255) NOT NULL,
PRIMARY KEY (id)
);
Aliase besitzen kein eigenes Postfach. Sie leiten E-Mails nur an eine andere Adresse weiter.
Beispiel:
support@example.de → info@example.de
Passwort-Hash für Dovecot erzeugen
Dovecot speichert Passwörter nicht im Klartext. Wir erzeugen daher einen Hash:
doveadm pw -s BLF-CRYPT
Dovecot fragt nun nach einem Passwort und gibt anschließend einen Hash aus:
{BLF-CRYPT}$2y$05$....
Diesen Hash kopieren wir.
Erste virtuelle Mailbox anlegen
Angenommen, die Domain hat die ID 1.
INSERT INTO virtual_users
(domain_id,email,password)
VALUES
(
1,
'info@example.de',
'{BLF-CRYPT}$2y$05$....'
);
Prüfen:
SELECT id,email FROM virtual_users;
Damit existiert die Mailbox bereits in der Datenbank. Auf dem Linux-System wurde dafür aber kein Benutzer info angelegt.
vmail-Systembenutzer anlegen
Alle virtuellen Mailboxen sollen einem einzigen technischen Benutzer gehören.
groupadd -g 5000 vmail
useradd \
-u 5000 \
-g vmail \
-d /var/vmail \
-m \
-s /usr/sbin/nologin \
vmail
Prüfen:
id vmail
Die Ausgabe sollte ungefähr so aussehen:
uid=5000(vmail) gid=5000(vmail) Gruppen=5000(vmail)
Das Login-Shell ist bewusst auf nologin gesetzt. Der Benutzer vmail soll sich nicht am System anmelden können.
Mailverzeichnis vorbereiten
mkdir -p /var/vmail
chown -R vmail:vmail /var/vmail
Für unsere erste Mailbox legen wir die Struktur an:
mkdir -p /var/vmail/example.de/info/Maildir/{cur,new,tmp}
chown -R vmail:vmail /var/vmail/example.de
Prüfen:
tree /var/vmail
Die Struktur sollte so aussehen:
/var/vmail
└── example.de
└── info
└── Maildir
├── cur
├── new
└── tmp
Dovecot SQL-Modul installieren
Damit Dovecot MariaDB verwenden kann, wird das SQL-Modul benötigt:
apt install dovecot-mysql
Dovecot SQL-Authentifizierung einrichten
In Dovecot 2.4 wird die SQL-Konfiguration direkt in der Auth-Datei definiert.
Datei öffnen:
nano /etc/dovecot/conf.d/auth-sql.conf.ext
Inhalt:
sql_driver = mysql
mysql 127.0.0.1 {
user = mailuser
password = EinSehrLangesPasswort
dbname = mailserver
}
passdb sql {
query = SELECT email AS user, password FROM virtual_users WHERE email = '%{user}'
default_password_scheme = BLF-CRYPT
}
userdb static {
fields {
uid = vmail
gid = vmail
home = /var/vmail/%{user | domain}/%{user | username}
}
}
Was passiert hier?
sql_driver
sql_driver = mysql
Dovecot verwendet MariaDB/MySQL als Datenquelle.
passdb sql
passdb sql {
query = SELECT email AS user, password FROM virtual_users WHERE email = '%{user}'
}
Dovecot sucht bei der Anmeldung nach der vollständigen E-Mail-Adresse. Wenn sich also info@example.de anmeldet, wird folgender Benutzer gesucht:
info@example.de
userdb static
userdb static {
fields {
uid = vmail
gid = vmail
home = /var/vmail/%{user | domain}/%{user | username}
}
}
Alle virtuellen Benutzer verwenden denselben Linux-Benutzer vmail. Für info@example.de ergibt sich daraus:
/var/vmail/example.de/info
SQL-Authentifizierung zusätzlich aktivieren
Jetzt wird SQL in Dovecot eingebunden.
Datei öffnen:
nano /etc/dovecot/conf.d/10-auth.conf
Dort befindet sich aktuell meist:
!include auth-system.conf.ext
Für den Übergang kann SQL zunächst zusätzlich aktiviert werden:
!include auth-system.conf.ext
!include auth-sql.conf.ext
Dadurch funktionieren sowohl lokale Linux-Benutzer als auch virtuelle Benutzer. Später kann auth-system.conf.ext entfernt werden, wenn ausschließlich virtuelle Mailboxen verwendet werden sollen.
Dovecot-Konfiguration prüfen
Vor dem Neustart sollte die Konfiguration geprüft werden:
dovecot -n
Wenn keine Fehler angezeigt werden:
systemctl restart dovecot
SQL-Login testen
Jetzt testen wir die Authentifizierung:
doveadm auth test info@example.de PASSWORT
Bei Erfolg erscheint:
passdb: info@example.de auth succeeded
extra fields:
user=info@example.de
Zusätzlich prüfen wir, wie Dovecot den Benutzer auflöst:
doveadm user info@example.de
Erwartet wird ungefähr:
field value
uid 5000
gid 5000
home /var/vmail/example.de/info
mail_path /var/vmail/example.de/info/Maildir
Damit weiß Dovecot:
- Benutzer existiert
- Passwort ist korrekt
- Mailbox liegt unter
/var/vmail - Besitzer ist
vmail
LMTP verstehen
Bisher konnte Postfix Mails selbst direkt in ein Maildir schreiben. Bei virtuellen Mailboxen soll aber Dovecot die Zustellung übernehmen. Dafür verwenden wir LMTP.
Der neue Weg lautet:
Internet
│
▼
Postfix
│
▼
Dovecot LMTP
│
▼
/var/vmail/example.de/info/Maildir
Der Vorteil:
- Dovecot kennt die Benutzer
- Dovecot kennt den Mailbox-Pfad
- Dovecot kann später Quotas anwenden
- Dovecot kann später Sieve-Filter ausführen
- Postfix muss nicht wissen, wie die Mailbox intern gespeichert wird
Dovecot LMTP-Socket für Postfix einrichten
Datei öffnen:
nano /etc/dovecot/conf.d/10-master.conf
Im Abschnitt service lmtp folgenden Socket einrichten:
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0600
user = postfix
group = postfix
}
}
Danach prüfen:
dovecot -n
und Dovecot neu starten:
systemctl restart dovecot
Wichtiger Hinweis zu auth_username_format
Falls in der LMTP-Konfiguration eine Zeile wie diese vorhanden ist:
auth_username_format = %{user | username | lower}
sollte sie für virtuelle Mailboxen mit vollständiger E-Mail-Adresse entfernt oder auskommentiert werden.
Warum?
Aus:
info@example.de
würde sonst nur:
info
Dovecot würde dann in der SQL-Tabelle nach info suchen, obwohl dort info@example.de gespeichert ist.
Das führt zu Fehlern wie:
User doesn't exist: info@example.de
Für virtuelle Mailboxen sollte Dovecot die vollständige Adresse verwenden.
Postfix MySQL-Unterstützung installieren
Postfix benötigt ein eigenes Modul, um MySQL-Tabellen abfragen zu können:
apt install postfix-mysql
SQL-Abfragen für Postfix erstellen
Wir legen die SQL-Dateien unter /etc/postfix/sql ab.
mkdir -p /etc/postfix/sql
Virtuelle Domains
nano /etc/postfix/sql/virtual_domains.cf
Inhalt:
user = mailuser
password = EinSehrLangesPasswort
hosts = 127.0.0.1
dbname = mailserver
query = SELECT 1 FROM virtual_domains WHERE name='%s'
Test:
postmap -q example.de mysql:/etc/postfix/sql/virtual_domains.cf
Erwartet:
1
Virtuelle Mailboxen
nano /etc/postfix/sql/virtual_mailboxes.cf
Inhalt:
user = mailuser
password = EinSehrLangesPasswort
hosts = 127.0.0.1
dbname = mailserver
query = SELECT 1 FROM virtual_users WHERE email='%s'
Test:
postmap -q info@example.de mysql:/etc/postfix/sql/virtual_mailboxes.cf
Erwartet:
1
Virtuelle Aliase
nano /etc/postfix/sql/virtual_aliases.cf
Inhalt:
user = mailuser
password = EinSehrLangesPasswort
hosts = 127.0.0.1
dbname = mailserver
query = SELECT destination FROM virtual_aliases WHERE source='%s'
Postfix auf virtuelle Domains umstellen
Jetzt konfigurieren wir Postfix so, dass die Domain nicht mehr als lokale Linux-Domain behandelt wird, sondern als virtuelle Maildomain.
postconf -e 'virtual_mailbox_domains = mysql:/etc/postfix/sql/virtual_domains.cf'
postconf -e 'virtual_mailbox_maps = mysql:/etc/postfix/sql/virtual_mailboxes.cf'
postconf -e 'virtual_alias_maps = mysql:/etc/postfix/sql/virtual_aliases.cf'
postconf -e 'virtual_transport = lmtp:unix:private/dovecot-lmtp'
Wichtig ist außerdem mydestination.
Bisher steht dort häufig:
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
Wenn example.de weiterhin in mydestination enthalten ist, behandelt Postfix die Domain als lokale Linux-Domain. Das wollen wir nicht mehr.
Daher setzen wir:
postconf -e 'mydestination = $myhostname, localhost.$mydomain, localhost'
Danach prüfen:
postfix check
und Postfix neu laden:
systemctl reload postfix
Erste Testmail an virtuelle Mailbox
Jetzt senden wir lokal eine Testmail:
echo "Test virtuelle Mailbox" | mail -s "Test LMTP" info@example.de
Log prüfen:
journalctl -u postfix -n 50 --no-pager
Bei Erfolg sollte dort etwas wie folgt stehen:
relay=mail.example.de[private/dovecot-lmtp]status=sent
Saved
Das zeigt:
Postfix → Dovecot LMTP → Maildir
Die Datei sollte nun unterhalb von /var/vmail liegen:
find /var/vmail/example.de/info/Maildir/new -type f -ls
Thunderbird einrichten
Jetzt kann die virtuelle Mailbox in Thunderbird eingerichtet werden.
Posteingang
Protokoll: IMAP
Server: mail.example.de
Port: 143
Verschlüsselung: STARTTLS
Benutzername: info@example.de
Alternativ:
Port: 993
Verschlüsselung: SSL/TLS
Postausgang
SMTP-Server: mail.example.de
Port: 587
Verschlüsselung: STARTTLS
Authentifizierung: Passwort normal
Benutzername: info@example.de
Wichtig ist, dass der Benutzername jetzt die vollständige E-Mail-Adresse ist:
info@example.de
nicht nur:
info
Virtuelle Aliase einrichten
Ein Alias leitet E-Mails an eine andere Adresse weiter.
Beispiel:
support@example.de → info@example.de
SQL:
INSERT INTO virtual_aliases
(domain_id,source,destination)
VALUES
(
1,
'support@example.de',
'info@example.de'
);
Test:
postmap -q support@example.de mysql:/etc/postfix/sql/virtual_aliases.cf
Erwartet:
info@example.de
Eine Mail an support@example.de wird nun an info@example.de zugestellt.
Lokale Linux-Authentifizierung optional deaktivieren
Während der Umstellung haben wir Dovecot so konfiguriert, dass sowohl lokale Linux-Benutzer als auch virtuelle SQL-Benutzer funktionieren:
!include auth-system.conf.ext
!include auth-sql.conf.ext
Wenn der Mailserver vollständig auf virtuelle Mailboxen umgestellt werden soll, kann die Systemauthentifizierung deaktiviert werden.
Datei öffnen:
nano /etc/dovecot/conf.d/10-auth.conf
Diese Zeile entfernen oder auskommentieren:
!include auth-system.conf.ext
Danach sollte nur noch SQL aktiv sein:
!include auth-sql.conf.ext
Dovecot neu starten:
systemctl restart dovecot
Test:
doveadm auth test info@example.de PASSWORT
Der virtuelle Benutzer muss weiterhin funktionieren. Ein lokaler Linux-Benutzer sollte sich dann nicht mehr per IMAP anmelden können.
Was ist mit home_mailbox?
In der alten Konfiguration wurde Postfix für lokale Benutzer häufig so eingestellt:
home_mailbox = Maildir/
Diese Einstellung wird für virtuelle Mailboxen nicht mehr benötigt, solange die Zustellung über virtual_transport und Dovecot LMTP erfolgt. Sie schadet für lokale Systemmails nicht zwingend, ist aber für die virtuellen Mailboxen nicht mehr der relevante Zustellweg. Der entscheidende Weg ist jetzt:
virtual_transport = lmtp:unix:private/dovecot-lmtp
Typische Fehler und Lösungen
Fehler: unsupported dictionary type: mysql
Meldung:
postmap: warning: unsupported dictionary type: mysql
postmap: fatal: unsupported dictionary type: mysql
Lösung:
apt install postfix-mysql
Fehler: User doesn’t exist
Meldung im Postfix-Log:
User doesn't exist: info@example.de
Mögliche Ursachen:
- Benutzer fehlt in
virtual_users - SQL-Abfrage findet den Benutzer nicht
- Dovecot verändert den Benutzernamen durch
auth_username_format - Dovecot sucht nur nach
infostatt nachinfo@example.de
Prüfen:
doveadm auth test info@example.de PASSWORT
doveadm user info@example.de
Fehler in Postfix SQL-Dateien
Die Queries sollten einzeilig geschrieben werden.
Richtig:
query = SELECT 1 FROM virtual_users WHERE email='%s'
Problematisch sind mehrzeilige Queries mit Backslash, wenn sie nicht korrekt verarbeitet werden.
Mail landet noch lokal
Wenn eine Mail an info@example.de nicht über LMTP, sondern lokal zugestellt wird, ist meist mydestination falsch.
Prüfen:
postconf mydestination
Die virtuelle Domain darf dort nicht mehr enthalten sein.
Richtig:
mydestination = $myhostname, localhost.$mydomain, localhost
Aktuelle Architektur
Nach der Umstellung sieht unser Mailserver so aus:
Eingehende Mail
│
▼
Postfix
│
▼
SQL-Prüfung:
virtual_domains
virtual_mailboxes
virtual_aliases
│
▼
Dovecot LMTP
│
▼
/var/vmail/example.de/info/Maildir
Der Abruf durch den Client erfolgt so:
Thunderbird
│
▼
Dovecot IMAP
│
▼
SQL-Login:
virtual_users
│
▼
/var/vmail/example.de/info/Maildir
Der Versand durch den Client erfolgt so:
Thunderbird
│
▼
Postfix Submission
│
▼
Dovecot SASL
│
▼
SQL-Login:
virtual_users
Damit verwenden IMAP und SMTP dieselbe Benutzerverwaltung.
Fazit
Mit der Umstellung auf virtuelle Mailboxen haben wir den Mailserver deutlich professioneller aufgebaut. Statt für jede E-Mail-Adresse einen Linux-Benutzer anzulegen, verwalten wir die Mailboxen nun in MariaDB. Dovecot übernimmt die Authentifizierung, stellt die Postfächer per IMAP bereit und nimmt eingehende Nachrichten über LMTP von Postfix entgegen.
Damit haben wir jetzt eine moderne Grundlage für einen eigenen Mailserver:
- Postfix für SMTP
- Dovecot für IMAP, Authentifizierung und LMTP
- MariaDB für Benutzer, Domains und Aliase
/var/vmailals zentraler Speicherort- vollständige E-Mail-Adressen als Login
- virtuelle Mailboxen ohne Linux-Benutzer
Im nächsten Teil können wir den Server weiter absichern und internet-tauglicher machen. Dazu gehören insbesondere:
- SPF
- DKIM
- DMARC
- Rspamd
- Fail2Ban
- Rate-Limits
- Backups der Mailboxen und Datenbank
