Mail Server Nachbau
Mailserver Nachbau: Postfix + Dovecot + Rspamd (it213.int)
Überblick
Diese Anleitung baut den kompletten Mailserver-Stack nach: Postfix (SMTP) → Dovecot (IMAP/LMTP/Sieve) → Rspamd (Spam-Scoring, DKIM, Bayes-Lernen, Blacklists). Jede Datei ist komplett und copy-paste-fertig für die Domain it213.int, Host mail.it213.int.
ℹ️ Hinweis:
Alle Dateien liegen auch fertig gepackt als mailconfig-it213.tar.gz vor, inkl. deploy.sh zum automatischen Ausrollen. Diese Anleitung zeigt dieselben Dateien einzeln mit Erklärung, für den Fall dass man Schritt für Schritt nachbauen statt nur ausrollen will.
| Komponente | Aufgabe | Port(e) |
|---|---|---|
| Postfix | SMTP-Empfang/-Versand, übergibt an Rspamd (Milter) und Dovecot (LMTP) | 25, 465, 587 |
| Dovecot | IMAP-Zustellung, Mailbox-Speicherung, Sieve-Filter | 143, 993, LMTP (Unix-Socket) |
| Rspamd | Spam-Scoring, DKIM-Signing, Bayes-Klassifikation, Blacklists | 11332 (Milter), 11334 (Controller) |
| Redis | Backend für Rspamd Bayes-Statistik | 6379 |
1. Postfix installieren
- apt install postfix
Bei der Installation: "Internet Site" wählen, Mailname = it213.int.
Datei: /etc/postfix/main.cf
Komplett, so einfügen:
smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
biff = no
append_dot_mydomain = no
readme_directory = no
compatibility_level = 3.6
myhostname = mail.it213.int
mydestination = $myhostname, mail.it213.int, localhost.it213.int, it213.int, localhost
myorigin = /etc/mailname
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
inet_interfaces = all
inet_protocols = all
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
home_mailbox = Maildir/
mailbox_command =
recipient_delimiter = +
message_size_limit = 31457280
mailbox_size_limit = 0
virtual_mailbox_limit = 31457280
relayhost =
smtpd_tls_cert_file = /etc/ssl/own.crt
smtpd_tls_key_file = /etc/ssl/own.key
smtpd_tls_security_level = may
smtp_tls_CApath = /etc/ssl/certs
smtp_tls_security_level = may
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
virtual_alias_maps = hash:/etc/postfix/virtual
smtpd_milters = inet:127.0.0.1:11332
non_smtpd_milters = inet:127.0.0.1:11332
milter_default_action = accept
milter_protocol = 6
mailbox_transport = lmtp:unix:private/dovecot-lmtp
virtual_transport = lmtp:unix:private/dovecot-lmtp
⚠️ Achtung:
smtpd_tls_cert_file/_key_file zeigen hier auf /etc/ssl/own.crt/own.key – eigenes Zertifikat vorher dort ablegen (oder Let's Encrypt nutzen und Pfad anpassen). Ohne gültiges Cert startet Postfix zwar, aber TLS funktioniert nicht richtig.
⚠️ Achtung:
smtpd_relay_restrictions ist zwingend korrekt zu setzen – ohne diese Zeile oder in falscher Reihenfolge läuft der Server als offenes Relay.
Datei: /etc/postfix/master.cf
Komplett, ersetzt die Standarddatei:
#
# Postfix master process configuration file.
#
# ==========================================================================
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (no) (never) (100)
# ==========================================================================
smtp inet n - y - - smtpd
submission inet n - y - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_reject_unlisted_recipient=no
smtps inet n - y - - smtpd
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
-o smtpd_milters=inet:127.0.0.1:11332
pickup unix n - y 60 1 pickup
cleanup unix n - y - 0 cleanup
qmgr unix n - n 300 1 qmgr
tlsmgr unix - - y 1000? 1 tlsmgr
rewrite unix - - y - - trivial-rewrite
bounce unix - - y - 0 bounce
defer unix - - y - 0 bounce
trace unix - - y - 0 bounce
verify unix - - y - 1 verify
flush unix n - y 1000? 0 flush
proxymap unix - - n - - proxymap
proxywrite unix - - n - 1 proxymap
smtp unix - - y - - smtp
relay unix - - y - - smtp
-o syslog_name=postfix/$service_name
showq unix n - y - - showq
error unix - - y - - error
retry unix - - y - - error
discard unix - - y - - discard
local unix - n n - - local
virtual unix - n n - - virtual
lmtp unix - - y - - lmtp
anvil unix - - y - 1 anvil
scache unix - - y - 1 scache
postlog unix-dgram n - n - 1 postlogd
maildrop unix - n n - - pipe
flags=DRXhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
uucp unix - n n - - pipe
flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
ifmail unix - n n - - pipe
flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
bsmtp unix - n n - - pipe
flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient
scalemail-backend unix - n n - 2 pipe
flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension}
mailman unix - n n - - pipe
flags=FRX user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py ${nexthop} ${user}
ℹ️ Hinweis: {{{1}}}
Test Postfix
- postfix check
- systemctl restart postfix
- systemctl status postfix
2. Dovecot installieren
- apt install dovecot-imapd dovecot-lmtpd dovecot-sieve
Datei: /etc/dovecot/conf.d/10-master.conf
service imap-login {
inet_listener imap {
port = 143
}
inet_listener imaps {
port = 993
ssl = yes
}
}
service pop3-login {
inet_listener pop3 {
port = 110
}
inet_listener pop3s {
port = 995
ssl = yes
}
}
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0600
user = postfix
group = postfix
}
}
service imap {
}
service pop3 {
}
service auth {
unix_listener auth-userdb {
}
unix_listener /var/spool/postfix/private/auth {
mode = 0660
user = postfix
group = postfix
}
}
service auth-worker {
}
service dict {
unix_listener dict {
}
}
ℹ️ Hinweis:
Die beiden unix_listener-Blöcke unter service lmtp und service auth sind die Kopplung zu Postfix – ohne die kann Postfix weder Mails an Dovecot übergeben noch SASL-Auth durchführen. mode/user/group müssen exakt so gesetzt sein, sonst Permission-Fehler.
Datei: /etc/dovecot/conf.d/10-auth.conf
disable_plaintext_auth = no auth_username_format = %n auth_mechanisms = plain !include auth-system.conf.ext
⚠️ Achtung: {{{1}}}
Datei: /etc/dovecot/conf.d/20-lmtp.conf
protocol lmtp {
mail_plugins = $mail_plugins sieve
}
Datei: /etc/dovecot/conf.d/20-imap.conf
protocol imap {
mail_plugins = $mail_plugins imap_sieve
}
Datei: /etc/dovecot/conf.d/15-mailboxes.conf
namespace inbox {
mailbox Drafts {
auto = subscribe
special_use = \Drafts
}
mailbox Junk {
auto = subscribe
special_use = \Junk
}
mailbox Trash {
auto = subscribe
special_use = \Trash
}
mailbox Sent {
auto = subscribe
special_use = \Sent
}
mailbox "Sent Messages" {
special_use = \Sent
}
}
Test Dovecot
- doveconf -n
- systemctl restart dovecot
- openssl s_client -connect 127.0.0.1:993 -quiet
Erwartete Antwort: * OK [CAPABILITY IMAP4rev1 ...] Dovecot ready.
3. Sieve: Spam automatisch einsortieren
Datei: /var/lib/dovecot/sieve/spam-to-junk.sieve
require ["fileinto"];
if header :contains "X-Spam" "Yes" {
fileinto "INBOX.Junk";
stop;
}
- mkdir -p /var/lib/dovecot/sieve
- sievec /var/lib/dovecot/sieve/spam-to-junk.sieve
4. IMAPSieve: automatisches Bayes-Lernen
Wenn eine Mail manuell nach Junk verschoben wird (oder raus), soll Rspamd automatisch daraus lernen.
Datei: /etc/dovecot/sieve/learn-spam.sieve
require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"];
if environment :matches "imap.mailbox" "*" {
set "mailbox" "${1}";
}
if string "${mailbox}" "Trash" {
stop;
}
pipe :copy "rspamd-learn-spam.sh";
Datei: /etc/dovecot/sieve/learn-ham.sieve
require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"];
if environment :matches "imap.mailbox" "*" {
set "mailbox" "${1}";
}
if string "${mailbox}" "Junk" {
stop;
}
pipe :copy "rspamd-learn-ham.sh";
- mkdir -p /etc/dovecot/sieve
- sievec /etc/dovecot/sieve/learn-spam.sieve
- sievec /etc/dovecot/sieve/learn-ham.sieve
Datei: /etc/dovecot/sieve-pipe/rspamd-learn-spam.sh
#!/bin/bash exec /usr/bin/rspamc learn_spam
Datei: /etc/dovecot/sieve-pipe/rspamd-learn-ham.sh
#!/bin/bash exec /usr/bin/rspamc learn_ham
- mkdir -p /etc/dovecot/sieve-pipe
- chmod +x /etc/dovecot/sieve-pipe/*.sh
Datei: /etc/dovecot/conf.d/90-sieve.conf
plugin {
sieve = ~/.dovecot.sieve
sieve_before = /var/lib/dovecot/sieve/spam-to-junk.sieve
sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.environment
sieve_plugins = sieve_imapsieve sieve_extprograms
sieve_pipe_bin_dir = /etc/dovecot/sieve-pipe
imapsieve_mailbox1_name = INBOX.Junk
imapsieve_mailbox1_causes = COPY
imapsieve_mailbox1_before = file:/etc/dovecot/sieve/learn-spam.sieve
imapsieve_mailbox2_name = *
imapsieve_mailbox2_from = INBOX.Junk
imapsieve_mailbox2_causes = COPY
imapsieve_mailbox2_before = file:/etc/dovecot/sieve/learn-ham.sieve
}
⚠️ Achtung:
imapsieve_mailbox1_name/_from müssen INBOX.Junk heißen (mit Präfix), nicht nur Junk – auch wenn doveconf -n einen leeren prefix-Wert zeigt. Das ist der interne Name, den Dovecot beim Maildir++-Layout verwendet. Falscher Name ist die häufigste Ursache, dass die Regel nie feuert, ohne Fehlermeldung im Log. Zur Diagnose: journalctl -u dovecot -f
Test Lernen
Mail in Roundcube nach Junk verschieben, dann:
- rspamc stat | grep -i bayes
learned bei BAYES_SPAM muss um 1 steigen. Rückweg (Junk → Inbox) für BAYES_HAM entsprechend testen.
5. Rspamd installieren
- apt install rspamd redis-server
Datei: /etc/rspamd/local.d/redis.conf
servers = "127.0.0.1:6379";
timeout = 1s;
Datei: /etc/rspamd/local.d/classifier-bayes.conf
backend = "redis";
new_schema = true;
expire = 8640000;
autolearn {
spam_threshold = 12.0;
ham_threshold = -2.0;
check_balance = true;
}
Datei: /etc/rspamd/local.d/actions.conf
reject = 15;
greylist = 4;
add_header = 6;
ℹ️ Hinweis:
Diese Werte legen fest, ab welchem Spam-Score was passiert. greylist niedrig, add_header mittel, reject hoch – bewusst wählen, nicht auf 999 setzen, sonst ist die Aktion faktisch deaktiviert.
Datei: /etc/rspamd/local.d/worker-proxy.inc
milter = yes;
timeout = 120s;
upstream "local" {
default = yes;
self_scan = yes;
}
Datei: /etc/rspamd/local.d/milter_headers.conf
use = ["x-spamd-bar", "x-spam-level", "x-spam-status", "authentication-results"];
Datei: /etc/rspamd/override.d/worker-controller.inc
Passwort-Hash vorher erzeugen:
- rspamadm pw
password = "HASH_HIER_EINFÜGEN";
enable_password = "HASH_HIER_EINFÜGEN";
bind_socket = [
"localhost:11334",
"/run/rspamd/controller.sock mode=0660"
];
Test Rspamd
- systemctl restart rspamd
- rspamc stat
6. DKIM-Signing
Key erzeugen:
- rspamadm dkim_keygen -b 2048 -s dkim -d it213.int -k /var/lib/rspamd/dkim/it213.int.dkim.key
Die Ausgabe ist der DNS-TXT-Record für dkim._domainkey.it213.int – bei eurem DNS-Provider eintragen.
Rechte setzen:
- chown _rspamd:_rspamd /var/lib/rspamd/dkim/it213.int.dkim.key
- chmod 600 /var/lib/rspamd/dkim/it213.int.dkim.key
Datei: /etc/rspamd/local.d/dkim_signing.conf
domain {
it213.int {
selectors [
{
path = "/var/lib/rspamd/dkim/it213.int.dkim.key";
selector = "dkim";
}
]
}
}
Test DKIM
- systemctl reload rspamd
- echo -e "From: test@it213.int\nTo: test@example.com\nSubject: Test\n\nBody" | rspamc symbols
Symbol DKIM_SIGNED muss im Output erscheinen.
7. Blacklist / Whitelist
Datei: /etc/rspamd/local.d/modules.conf
multimap {
enabled = true;
}
Datei: /etc/rspamd/local.d/multimap.conf
WHITELIST_SENDER_DOMAIN {
type = "from";
filter = "email:domain";
map = "/etc/rspamd/local.d/lists/whitelist.sender.domain.map";
action = "accept";
symbol = "WHITELISTED_DOMAIN";
}
WHITELIST_SENDER_EMAIL {
type = "from";
map = "/etc/rspamd/local.d/lists/whitelist.sender.email.map";
action = "accept";
symbol = "WHITELISTED_ADDRESS";
}
BLACKLIST_SENDER_DOMAIN {
type = "from";
filter = "email:domain";
map = "/etc/rspamd/local.d/lists/blacklist.sender.domain.map";
action = "reject";
symbol = "BLACKLISTED_DOMAIN";
}
BLACKLIST_SENDER_EMAIL {
type = "header";
header = "From";
filter = "email";
map = "/etc/rspamd/local.d/lists/blacklist.sender.email.map";
action = "reject";
symbol = "BLACKLISTED_ADDRESS";
regexp = false;
}
BLOCKLIST_IP {
type = "ip";
map = "/etc/rspamd/local.d/lists/blockip.map";
prefilter = true;
action = "reject";
symbol = "BLOCKLIST_IP";
}
ALLOWLIST_IP {
type = "ip";
map = "/etc/rspamd/local.d/lists/allowip.map";
prefilter = true;
action = "accept";
symbol = "ALLOWLIST_IP";
}
Maps anlegen (eine Adresse/Domain/IP pro Zeile):
- mkdir -p /etc/rspamd/local.d/lists
- touch /etc/rspamd/local.d/lists/{whitelist.sender.domain.map,whitelist.sender.email.map,blacklist.sender.domain.map,blacklist.sender.email.map,blockip.map,allowip.map}
8. Virenscanner (ClamAV)
⚠️ Achtung:
Neuaufbau, kein dokumentierter Ist-Zustand einer laufenden Referenz. Vor Produktiveinsatz selbst durchtesten.
- apt install clamav-daemon
- systemctl enable --now clamav-daemon
- freshclam
Datei: /etc/rspamd/local.d/antivirus.conf
clamav {
action = "reject";
symbol = "CLAM_VIRUS";
type = "clamav";
servers = "/var/run/clamav/clamd.ctl";
}
Test
- curl -o /tmp/eicar.txt https://secure.eicar.org/eicar.com.txt
- rspamc symbols < /tmp/eicar.txt
Symbol CLAM_VIRUS muss erscheinen.
9. End-to-End-Verifikation
Funktion
Testbefehl
Erwartetes Ergebnis
Postfix läuft
systemctl status postfix
active (running)
Dovecot läuft
systemctl status dovecot
active (running)
TLS-Cert korrekt
openssl s_client -connect mail.it213.int:993
richtiges Cert
Rspamd scannt
rspamc stat
Scanned-Counter > 0
DKIM signiert
rspamc symbols (Testmail)
Symbol DKIM_SIGNED
Bayes lernt (Spam)
Mail nach Junk verschieben, rspamc stat
BAYES_SPAM learned +1
Bayes lernt (Ham)
Mail aus Junk raus, rspamc stat
BAYES_HAM learned +1
ClamAV aktiv
EICAR-Test
Symbol CLAM_VIRUS
Blacklist wirkt
Testmail von geblockter Domain/IP
Reject bzw. BLACKLISTED_*-Symbol
ℹ️ Hinweis:
Checkliste eignet sich auch zur Wiederholung nach Updates/Config-Änderungen, um schnell zu sehen was kaputtgegangen ist.