Rspamds DNS-Blocklisten waren wirkungslos: Spamhaus beantwortete keine Anfragen, weil sie ueber Dockers eingebautes DNS von einem als oeffentlich eingestuften Resolver kamen (DBL_BLOCKED_OPENRESOLVER im Log, fuer rDNS, Message-ID und URLs gleichermassen). ENABLE_UNBOUND=1 hat daran nichts geaendert - die Variable existiert in DMS nicht und war ein No-Op. - dns-recursor (PowerDNS Recursor 5.3.10) als eigener Service, der selbst rekursiv aufloest, in einem separaten Netz dms_dns mit fester IP, weil Dockers dns:-Option nur IPs akzeptiert - ENABLE_UNBOUND entfernt - train_bayes.sh: einmaliges Anlernen des Bayes-Klassifikators aus den vorhandenen Postfaechern (Junk -> Spam, INBOX -> Ham). Bisher feuerte kein einziges BAYES_-Symbol, weil die noetigen 200 Lernvorgaenge je Klasse fehlten. Default ist ein Trockenlauf, gelernt wird nur mit --apply. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
245 lines
9.3 KiB
YAML
245 lines
9.3 KiB
YAML
services:
|
|
|
|
mailserver:
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile
|
|
image: dms-custom:latest
|
|
container_name: mailserver
|
|
|
|
# Node-spezifischer Hostname - A-Record zeigt auf DIESEN Server.
|
|
# email-srvr.com selbst zeigt auf einen anderen Server und wird hier NICHT verwendet.
|
|
hostname: ${NODE_HOSTNAME}
|
|
|
|
ports:
|
|
- "127.0.0.1:25:25"
|
|
- "587:587"
|
|
- "465:465"
|
|
- "143:143"
|
|
- "993:993"
|
|
- "110:110"
|
|
- "995:995"
|
|
- "127.0.0.1:11334:11334"
|
|
|
|
volumes:
|
|
- ./docker-data/dms/mail-data/:/var/mail/
|
|
- ./docker-data/dms/mail-state/:/var/mail-state/
|
|
- ./docker-data/dms/mail-logs/:/var/log/mail/
|
|
- ./docker-data/dms/config/:/tmp/docker-mailserver/
|
|
# ENTFERNT: Mount von dovecot/conf.d/95-sieve-redirect.conf
|
|
# Der Host-Pfad existiert nicht, Docker hat daraufhin ein VERZEICHNIS
|
|
# unter /etc/dovecot/conf.d/95-sieve-redirect.conf angelegt (nachweisbar
|
|
# per `docker exec mailserver cat ...` -> "Is a directory"). Der Mount war
|
|
# also wirkungslos. Falls dort spaeter wirklich etwas gebraucht wird
|
|
# (z.B. sieve_redirect_envelope_from), erst die Datei auf dem Host
|
|
# anlegen, dann den Mount wieder aufnehmen.
|
|
- /etc/localtime:/etc/localtime:ro
|
|
- ./sync_dynamodb_to_sieve.py:/scripts/sync.py:ro
|
|
- ./sieve-cron:/etc/cron.d/sieve-sync:ro
|
|
|
|
# -------------------------------------------------------
|
|
# Caddy Zertifikate: gesamtes Cert-Verzeichnis mounten.
|
|
#
|
|
# Caddy legt Wildcard-Certs so ab:
|
|
# *.andreasknuth.de/
|
|
# *.andreasknuth.de.crt
|
|
# *.andreasknuth.de.key
|
|
# node1.email-srvr.com/
|
|
# node1.email-srvr.com.crt
|
|
# node1.email-srvr.com.key
|
|
#
|
|
# setup-dms-tls.sh referenziert per:
|
|
# /etc/mail/certs/*.domain/*.domain.crt|.key
|
|
# -------------------------------------------------------
|
|
# - /var/lib/docker/volumes/caddy_data/_data/caddy/certificates/acme-v02.api.letsencrypt.org-directory:/etc/mail/certs:ro
|
|
- /home/aknuth/git/email-amazon/caddy/caddy-data/caddy/certificates/acme-v02.api.letsencrypt.org-directory:/etc/mail/certs:ro
|
|
# -------------------------------------------------------
|
|
# Dovecot SNI Konfiguration (generiert von setup-dms-tls.sh)
|
|
# DMS lädt /tmp/docker-mailserver/dovecot-sni.cf automatisch.
|
|
# -------------------------------------------------------
|
|
- ./docker-data/dms/config/dovecot-sni.cf:/etc/dovecot/conf.d/99-sni.conf:ro
|
|
|
|
environment:
|
|
# -------------------------------------------------------
|
|
# SSL Default-Cert: node1.email-srvr.com
|
|
# Das ist das Fallback-Cert wenn kein SNI-Match gefunden wird
|
|
# (z.B. bei direktem IP-Connect ohne Hostname).
|
|
# Kundendomain-SNI wird über postfix-main.cf + dovecot-sni.cf gesteuert.
|
|
# -------------------------------------------------------
|
|
- SSL_TYPE=manual
|
|
- SSL_CERT_PATH=/etc/mail/certs/${NODE_HOSTNAME}/${NODE_HOSTNAME}.crt
|
|
- SSL_KEY_PATH=/etc/mail/certs/${NODE_HOSTNAME}/${NODE_HOSTNAME}.key
|
|
|
|
# SPAM / Rspamd
|
|
# OpenDKIM deaktiviert: es liegen keine Keys unter config/opendkim/, der
|
|
# Milter hat also nie etwas signiert. Ausgehende Mail wird von Amazon SES
|
|
# signiert (Easy DKIM), eingehende DKIM-Pruefung macht rspamd selbst.
|
|
# DMS warnt beim Start ausdruecklich davor, OpenDKIM parallel zu rspamd
|
|
# zu betreiben.
|
|
- ENABLE_OPENDKIM=0
|
|
- ENABLE_OPENDMARC=0
|
|
- ENABLE_POLICYD_SPF=0
|
|
- ENABLE_RSPAMD=1
|
|
- RSPAMD_GREYLISTING=0
|
|
- RSPAMD_CHECK_AUTHENTICATED=0
|
|
- RSPAMD_HFILTER=1
|
|
- MOVE_SPAM_TO_JUNK=1
|
|
- ENABLE_AMAVIS=0
|
|
- ENABLE_SPAMASSASSIN=0
|
|
- ENABLE_POSTGREY=0
|
|
- ENABLE_CLAMAV=0
|
|
|
|
# Sicherheit
|
|
- ENABLE_FAIL2BAN=1
|
|
# ENABLE_UNBOUND entfernt: die Variable existiert in DMS nicht (mehr) und
|
|
# war wirkungslos - rspamd hat ueber Dockers eingebautes DNS (127.0.0.11)
|
|
# aufgeloest und bekam von Spamhaus nur DBL_BLOCKED_OPENRESOLVER zurueck.
|
|
# Ersetzt durch den dns-recursor-Service weiter unten.
|
|
|
|
# Sonstige
|
|
- ENABLE_MANAGESIEVE=0
|
|
- ENABLE_POP3=1
|
|
- RSPAMD_LEARN=1
|
|
- ONE_DIR=1
|
|
- ENABLE_UPDATE_CHECK=0
|
|
- PERMIT_DOCKER=network
|
|
- SPOOF_PROTECTION=0
|
|
- ENABLE_SRS=0
|
|
- LOG_LEVEL=info
|
|
|
|
# Amazon SES Relay
|
|
- RELAY_HOST=email-smtp.us-east-2.amazonaws.com
|
|
# Node-spezifisch: manche Provider blockieren ausgehend 587.
|
|
# Wert pro Server in der .env setzen (z.B. RELAY_PORT=2587),
|
|
# ohne Eintrag bleibt es bei 587.
|
|
- RELAY_PORT=${RELAY_PORT:-587}
|
|
- RELAY_USER=${SES_SMTP_USER}
|
|
- RELAY_PASSWORD=${SES_SMTP_PASSWORD}
|
|
|
|
# AWS Credentials
|
|
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
|
|
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
|
|
- AWS_REGION=us-east-2
|
|
|
|
# Postfix
|
|
# POSTFIX_OVERRIDE_HOSTNAME: Was Postfix im EHLO/HELO Banner sendet.
|
|
# node1.email-srvr.com passt zum TLS-Cert und ist der echte Hostname.
|
|
- POSTFIX_OVERRIDE_HOSTNAME=${NODE_HOSTNAME}
|
|
- POSTFIX_MYNETWORKS=172.16.0.0/12 172.17.0.0/12 172.18.0.0/12 [::1]/128 [fe80::]/64
|
|
- POSTFIX_MAILBOX_SIZE_LIMIT=0
|
|
- POSTFIX_MESSAGE_SIZE_LIMIT=0
|
|
|
|
cap_add:
|
|
- NET_ADMIN
|
|
- SYS_PTRACE
|
|
restart: unless-stopped
|
|
|
|
# -------------------------------------------------------
|
|
# DNS: rspamd fragt DNS-Blocklisten (Spamhaus DBL/ZEN, SURBL) ab. Diese
|
|
# Dienste beantworten keine Anfragen, die ueber oeffentliche Resolver
|
|
# kommen - man bekommt DBL_BLOCKED_OPENRESOLVER statt eines Ergebnisses.
|
|
# Deshalb ein eigener rekursiver Resolver, siehe Service dns-recursor.
|
|
#
|
|
# ACHTUNG: Damit ersetzt der Recursor Dockers eingebautes DNS (127.0.0.11)
|
|
# fuer DIESEN Container. Der mailserver kann dann keine Container-Namen
|
|
# mehr aufloesen (roundcube-db, email-worker-ts, ...). Das ist hier
|
|
# unkritisch, weil er von sich aus nur nach aussen verbindet (SES-Relay).
|
|
# Faellt der Recursor aus, hat der mailserver kein DNS mehr - deshalb
|
|
# restart: always beim Recursor.
|
|
# -------------------------------------------------------
|
|
dns:
|
|
- 10.99.0.53
|
|
depends_on:
|
|
- dns-recursor
|
|
|
|
networks:
|
|
mail_network:
|
|
aliases:
|
|
- mailserver
|
|
- ${NODE_HOSTNAME}
|
|
dns_network:
|
|
|
|
# ---------------------------------------------------------
|
|
# Rekursiver DNS-Resolver ausschliesslich fuer den mailserver.
|
|
# Er fragt die Root-Server selbst ab, statt an einen Upstream-Resolver
|
|
# weiterzuleiten - nur so akzeptiert Spamhaus die Anfragen.
|
|
# Braucht keine Konfiguration: das Image laeuft per Default als Recursor
|
|
# und erlaubt Anfragen aus den RFC1918-Netzen (10.99.0.0/24 liegt darin).
|
|
# ---------------------------------------------------------
|
|
dns-recursor:
|
|
image: powerdns/pdns-recursor-53:5.3.10
|
|
container_name: dns-recursor
|
|
restart: always
|
|
stop_grace_period: 0s
|
|
networks:
|
|
dns_network:
|
|
ipv4_address: 10.99.0.53
|
|
|
|
roundcube:
|
|
image: roundcube/roundcubemail:latest
|
|
container_name: roundcube
|
|
depends_on:
|
|
- roundcube-db
|
|
- mailserver
|
|
environment:
|
|
- ROUNDCUBEMAIL_DEFAULT_LANGUAGE=en_US
|
|
- ROUNDCUBEMAIL_DB_TYPE=pgsql
|
|
- ROUNDCUBEMAIL_DB_HOST=roundcube-db
|
|
- ROUNDCUBEMAIL_DB_NAME=roundcube
|
|
- ROUNDCUBEMAIL_DB_USER=roundcube
|
|
- ROUNDCUBEMAIL_DB_PASSWORD=${ROUNDCUBE_DB_PASSWORD}
|
|
# Roundcube verbindet intern über den Docker-Alias
|
|
- ROUNDCUBEMAIL_DEFAULT_HOST=ssl://${NODE_HOSTNAME}
|
|
- ROUNDCUBEMAIL_DEFAULT_PORT=993
|
|
# Interner Traffic ohne TLS
|
|
- ROUNDCUBEMAIL_SMTP_SERVER=ssl://${NODE_HOSTNAME}
|
|
- ROUNDCUBEMAIL_SMTP_PORT=465
|
|
|
|
# WICHTIG: Variablen LEER lassen, damit Roundcube keine Authentifizierung versucht!
|
|
- ROUNDCUBEMAIL_SMTP_USER=
|
|
- ROUNDCUBEMAIL_SMTP_PASSWORD=
|
|
- ROUNDCUBEMAIL_PLUGINS=password,email_config
|
|
# NEU: Schaltet die strikte PHP-Zertifikatsprüfung für interne Verbindungen ab
|
|
- ROUNDCUBEMAIL_IMAP_CONN_OPTIONS={"ssl":{"verify_peer":false,"verify_peer_name":false}}
|
|
- ROUNDCUBEMAIL_SMTP_CONN_OPTIONS={"ssl":{"verify_peer":false,"verify_peer_name":false}}
|
|
ports:
|
|
- "8888:80"
|
|
volumes:
|
|
# - ./docker-data/roundcube/config:/var/www/html/config
|
|
- ./docker-data/roundcube/plugins/email_config:/var/www/html/plugins/email_config:ro
|
|
networks:
|
|
- mail_network
|
|
restart: unless-stopped
|
|
|
|
roundcube-db:
|
|
image: postgres:15
|
|
container_name: roundcube-db
|
|
environment:
|
|
- POSTGRES_DB=roundcube
|
|
- POSTGRES_USER=roundcube
|
|
- POSTGRES_PASSWORD=${ROUNDCUBE_DB_PASSWORD}
|
|
ports:
|
|
- "5555:5432"
|
|
volumes:
|
|
- ./docker-data/roundcube/db:/var/lib/postgresql/data
|
|
networks:
|
|
- mail_network
|
|
restart: unless-stopped
|
|
|
|
networks:
|
|
mail_network:
|
|
external: true
|
|
|
|
# Eigenes Netz nur fuer mailserver <-> dns-recursor.
|
|
# Bewusst NICHT im externen mail_network: dort vergibt Docker die Adressen
|
|
# dynamisch, eine feste IP koennte mit einem anderen Container kollidieren.
|
|
# Das Subnetz muss fest sein, weil Dockers `dns:`-Option nur IPs akzeptiert.
|
|
# Falls 10.99.0.0/24 bei euch schon belegt ist (VPN, AWS-VPC), hier und bei
|
|
# `dns:` sowie `ipv4_address` oben gemeinsam auf ein freies Netz aendern.
|
|
dns_network:
|
|
name: dms_dns
|
|
ipam:
|
|
driver: default
|
|
config:
|
|
- subnet: 10.99.0.0/24
|