#!/bin/bash # setup-dms-tls.sh # Gehört ins Root-Verzeichnis des DMS (neben docker-compose.yml). # # Generiert Dovecot- und Postfix-SNI-Konfigurationen für Multi-Domain TLS. # Liest Domains aus dem laufenden DMS und erstellt: # - docker-data/dms/config/dovecot-sni.cf # - docker-data/dms/config/postfix-main.cf # - docker-data/dms/config/postfix-sni.map (NEU für Postfix SNI) # # Cert-Konvention (Caddy Wildcard): # Caddy speichert *.domain.tld unter: wildcard_.domain.tld/wildcard_.domain.tld.crt # Im Container (gemountet unter /etc/mail/certs): # /etc/mail/certs/wildcard_.domain.tld/wildcard_.domain.tld.crt # /etc/mail/certs/wildcard_.domain.tld/wildcard_.domain.tld.key # # Usage: # ./setup-dms-tls.sh # DMS_CONTAINER=mailserver NODE_HOSTNAME=node1.email-srvr.com ./setup-dms-tls.sh set -e DMS_CONTAINER=${DMS_CONTAINER:-"mailserver"} SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" CONFIG_DIR="$SCRIPT_DIR/docker-data/dms/config" CERTS_BASE_PATH=${CERTS_BASE_PATH:-"/etc/mail/certs"} # Node-Hostname: Fallback-Cert für DMS (kein Wildcard, direktes Cert) # Muss mit dem 'hostname' in docker-compose.yml übereinstimmen. NODE_HOSTNAME=${NODE_HOSTNAME:-"node1.email-srvr.com"} echo "============================================================" echo " 🔐 DMS TLS SNI Setup (Multi-Domain)" echo " DMS Container: $DMS_CONTAINER" echo " Config Dir: $CONFIG_DIR" echo " Certs Base: $CERTS_BASE_PATH" echo " Node Hostname: $NODE_HOSTNAME" echo "============================================================" # --- Domains aus DMS lesen --- echo "" echo "📋 Lese Domains aus DMS..." DOMAINS=$(docker exec "$DMS_CONTAINER" setup email list 2>/dev/null \ | grep -oP '(?<=@)[^\s]+' \ | sort -u) if [ -z "$DOMAINS" ]; then echo "❌ Keine Accounts im DMS gefunden!" echo " Bitte zuerst anlegen: ./manage_mail_user.sh add user@domain.com PW" exit 1 fi echo " Gefundene Domains:" for d in $DOMAINS; do echo " - $d"; done # --- Cert-Pfad Hilfsfunktionen --- wildcard_cert_path() { echo "$CERTS_BASE_PATH/wildcard_.${1}/wildcard_.${1}.crt" } wildcard_key_path() { echo "$CERTS_BASE_PATH/wildcard_.${1}/wildcard_.${1}.key" } # --- Cert-Verfügbarkeit im Container prüfen --- echo "" echo "🔍 Prüfe Zertifikat-Verfügbarkeit..." DOMAINS_OK="" DOMAINS_MISSING="" for domain in $DOMAINS; do CERT_PATH=$(wildcard_cert_path "$domain") KEY_PATH=$(wildcard_key_path "$domain") if docker exec "$DMS_CONTAINER" test -f "$CERT_PATH" 2>/dev/null; then echo " ✅ $domain → $CERT_PATH" DOMAINS_OK="$DOMAINS_OK $domain" else echo " ⚠️ $domain → KEIN Cert unter $CERT_PATH" echo " → update-caddy-certs.sh ausführen + caddy reload!" DOMAINS_MISSING="$DOMAINS_MISSING $domain" fi done # Node-Hostname Cert prüfen (direktes Cert, kein Wildcard) NODE_CERT_PATH="$CERTS_BASE_PATH/$NODE_HOSTNAME/$NODE_HOSTNAME.crt" NODE_KEY_PATH="$CERTS_BASE_PATH/$NODE_HOSTNAME/$NODE_HOSTNAME.key" if docker exec "$DMS_CONTAINER" test -f "$NODE_CERT_PATH" 2>/dev/null; then echo " ✅ $NODE_HOSTNAME → Cert vorhanden (Node Default)" else echo " ⚠️ $NODE_HOSTNAME → KEIN Cert! Caddy-Block im Caddyfile prüfen." fi if [ -n "$DOMAINS_MISSING" ]; then echo "" echo " ⚠️ Fehlende Certs:$DOMAINS_MISSING" echo " Diese Domains werden NICHT in SNI-Config eingetragen." fi if [ -z "$DOMAINS_OK" ]; then echo "❌ Kein einziges Kundendomain-Cert gefunden!" echo " Bitte zuerst update-caddy-certs.sh ausführen + caddy reload abwarten." exit 1 fi # ================================================================ # DOVECOT SNI Konfiguration # ================================================================ DOVECOT_CFG="$CONFIG_DIR/dovecot-sni.cf" echo "" echo "📝 Generiere: $DOVECOT_CFG" cat > "$DOVECOT_CFG" << 'HEADER' # dovecot-sni.cf - Automatisch generiert von setup-dms-tls.sh # SNI-basierte Zertifikat-Auswahl für Dovecot (IMAP/POP3). # Dovecot liest dieses File über den Volume-Mount in /tmp/docker-mailserver/ # und wendet es automatisch an. HEADER for domain in $DOMAINS_OK; do CERT_PATH=$(wildcard_cert_path "$domain") KEY_PATH=$(wildcard_key_path "$domain") cat >> "$DOVECOT_CFG" << EOF # $domain local_name mail.$domain { ssl_cert = <$CERT_PATH ssl_key = <$KEY_PATH } local_name imap.$domain { ssl_cert = <$CERT_PATH ssl_key = <$KEY_PATH } local_name smtp.$domain { ssl_cert = <$CERT_PATH ssl_key = <$KEY_PATH } local_name pop.$domain { ssl_cert = <$CERT_PATH ssl_key = <$KEY_PATH } EOF done echo " ✅ Dovecot SNI: $(echo $DOMAINS_OK | wc -w) Domain(s)" # ================================================================ # POSTFIX SNI Konfiguration (Neu geschrieben für echte SNI Maps) # ================================================================ POSTFIX_CFG="$CONFIG_DIR/postfix-main.cf" POSTFIX_MAP="$CONFIG_DIR/postfix-sni.map" echo "" echo "📝 Generiere: $POSTFIX_CFG und $POSTFIX_MAP" if [ -f "$POSTFIX_CFG" ]; then cp "$POSTFIX_CFG" "${POSTFIX_CFG}.bak.$(date +%Y%m%d%H%M%S)" fi # 1. postfix-main.cf erstellen cat > "$POSTFIX_CFG" << POSTFIX_EOF # postfix-main.cf - Automatisch generiert von setup-dms-tls.sh # # 1. Fallback-Zertifikat (Wird genutzt, wenn kein SNI-Match gefunden wird) smtpd_tls_chain_files = ${NODE_KEY_PATH}, ${NODE_CERT_PATH} # 2. SNI-Mapping aktivieren # Wir nutzen 'texthash', damit Postfix die Map direkt lesen kann, # ohne dass 'postmap' ausgeführt werden muss! tls_server_sni_maps = texthash:/tmp/docker-mailserver/postfix-sni.map POSTFIX_EOF # 2. postfix-sni.map erstellen echo "# postfix-sni.map - Automatisch generiert (Format: host key_pfad cert_pfad)" > "$POSTFIX_MAP" for domain in $DOMAINS_OK; do KEY_PATH=$(wildcard_key_path "$domain") CERT_PATH=$(wildcard_cert_path "$domain") cat >> "$POSTFIX_MAP" << EOF mail.${domain} ${KEY_PATH} ${CERT_PATH} smtp.${domain} ${KEY_PATH} ${CERT_PATH} imap.${domain} ${KEY_PATH} ${CERT_PATH} pop.${domain} ${KEY_PATH} ${CERT_PATH} ${domain} ${KEY_PATH} ${CERT_PATH} EOF done echo " ✅ Postfix SNI: $(echo $DOMAINS_OK | wc -w) Domain(s) konfiguriert" # ================================================================ # Zusammenfassung # ================================================================ echo "" echo "============================================================" echo "✅ Konfigurationen generiert." echo "" echo "🔄 Lade Postfix und Dovecot neu (ohne Downtime)..." docker exec "$DMS_CONTAINER" postfix reload || echo "⚠️ Postfix Reload fehlgeschlagen" docker exec "$DMS_CONTAINER" dovecot reload || echo "⚠️ Dovecot Reload fehlgeschlagen" echo "" echo "📋 Nächste Schritte:" echo "" echo "1. TLS testen (SNI):" for domain in $DOMAINS_OK; do echo " openssl s_client -connect mail.$domain:993 -servername mail.$domain 2>/dev/null | grep 'subject\|issuer'" done echo "============================================================"