update
This commit is contained in:
@@ -1,37 +1,40 @@
|
||||
#!/bin/bash
|
||||
# setup-dms-tls.sh
|
||||
# Generiert Dovecot und Postfix SNI-Konfigurationen für Multi-Domain TLS.
|
||||
# Liest die vorhandenen Domains aus den DMS Accounts und erstellt:
|
||||
# - docker-data/dms/config/dovecot-sni.cf (Dovecot SNI pro Domain)
|
||||
# - docker-data/dms/config/postfix-main.cf (Postfix SNI Map + TLS Chain)
|
||||
# Gehört ins Root-Verzeichnis des DMS (neben docker-compose.yml).
|
||||
#
|
||||
# Voraussetzung:
|
||||
# - Caddy hat Wildcard-Certs gezogen (z.B. *.andreasknuth.de)
|
||||
# - Cert-Verzeichnis ist gemountet unter /etc/mail/certs im Container
|
||||
# - Konvention Cert-Pfad: /etc/mail/certs/DOMAIN_NAME/*.DOMAIN_NAME.crt|.key
|
||||
# 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
|
||||
#
|
||||
# Cert-Konvention (Caddy Wildcard):
|
||||
# /etc/mail/certs/*.domain.tld/*.domain.tld.crt
|
||||
# /etc/mail/certs/*.domain.tld/*.domain.tld.key
|
||||
#
|
||||
# Usage:
|
||||
# DMS_CONTAINER=mailserver ./setup-dms-tls.sh
|
||||
# DMS_CONTAINER=mailserver DEFAULT_DOMAIN=email-srvr.com ./setup-dms-tls.sh
|
||||
# ./setup-dms-tls.sh
|
||||
# DMS_CONTAINER=mailserver NODE_HOSTNAME=node1.email-srvr.com ./setup-dms-tls.sh
|
||||
|
||||
set -e
|
||||
|
||||
DMS_CONTAINER=${DMS_CONTAINER:-"mailserver"}
|
||||
CONFIG_DIR=${CONFIG_DIR:-"./docker-data/dms/config"}
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
CONFIG_DIR="$SCRIPT_DIR/docker-data/dms/config"
|
||||
CERTS_BASE_PATH=${CERTS_BASE_PATH:-"/etc/mail/certs"}
|
||||
|
||||
# Die Default-Domain für DMS hostname/domainname (bleibt email-srvr.com)
|
||||
DEFAULT_DOMAIN=${DEFAULT_DOMAIN:-"email-srvr.com"}
|
||||
# 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 " Container: $DMS_CONTAINER"
|
||||
echo " Config Dir: $CONFIG_DIR"
|
||||
echo " Certs Base: $CERTS_BASE_PATH"
|
||||
echo " Default Domain: $DEFAULT_DOMAIN"
|
||||
echo " DMS Container: $DMS_CONTAINER"
|
||||
echo " Config Dir: $CONFIG_DIR"
|
||||
echo " Certs Base: $CERTS_BASE_PATH"
|
||||
echo " Node Hostname: $NODE_HOSTNAME"
|
||||
echo "============================================================"
|
||||
|
||||
# --- Alle Domains aus DMS Accounts lesen ---
|
||||
# --- Domains aus DMS lesen ---
|
||||
echo ""
|
||||
echo "📋 Lese Domains aus DMS..."
|
||||
DOMAINS=$(docker exec "$DMS_CONTAINER" setup email list 2>/dev/null \
|
||||
@@ -40,74 +43,80 @@ DOMAINS=$(docker exec "$DMS_CONTAINER" setup email list 2>/dev/null \
|
||||
|
||||
if [ -z "$DOMAINS" ]; then
|
||||
echo "❌ Keine Accounts im DMS gefunden!"
|
||||
echo " Bitte zuerst Accounts anlegen: ./manage_mail_user.sh add user@domain.com PW"
|
||||
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-Verfügbarkeit prüfen ---
|
||||
# --- Cert-Verfügbarkeit im Container prüfen ---
|
||||
echo ""
|
||||
echo "🔍 Prüfe Zertifikat-Verfügbarkeit (im Container)..."
|
||||
DOMAINS_WITH_CERTS=""
|
||||
DOMAINS_WITHOUT_CERTS=""
|
||||
echo "🔍 Prüfe Zertifikat-Verfügbarkeit..."
|
||||
DOMAINS_OK=""
|
||||
DOMAINS_MISSING=""
|
||||
|
||||
for domain in $DOMAINS; do
|
||||
# Caddy speichert Wildcard-Certs als: *.domain.tld/
|
||||
# Pfad im Container (über den Volume-Mount): /etc/mail/certs/*.domain.tld/
|
||||
CERT_PATH="$CERTS_BASE_PATH/*.$domain/*.$domain.crt"
|
||||
KEY_PATH="$CERTS_BASE_PATH/*.$domain/*.$domain.key"
|
||||
|
||||
# Prüfe ob die Datei im Container existiert
|
||||
if docker exec "$DMS_CONTAINER" test -f "$CERT_PATH" 2>/dev/null; then
|
||||
echo " ✅ $domain → Cert gefunden"
|
||||
DOMAINS_WITH_CERTS="$DOMAINS_WITH_CERTS $domain"
|
||||
echo " ✅ $domain → Cert vorhanden"
|
||||
DOMAINS_OK="$DOMAINS_OK $domain"
|
||||
else
|
||||
echo " ⚠️ $domain → KEIN Cert unter $CERT_PATH"
|
||||
echo " Caddy-Block '*.${domain}' eintragen und Caddy neu starten!"
|
||||
DOMAINS_WITHOUT_CERTS="$DOMAINS_WITHOUT_CERTS $domain"
|
||||
echo " → update-caddy-certs.sh ausführen + caddy reload!"
|
||||
DOMAINS_MISSING="$DOMAINS_MISSING $domain"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "$DOMAINS_WITHOUT_CERTS" ]; then
|
||||
echo ""
|
||||
echo "⚠️ WARNUNG: Fehlende Certs für:$DOMAINS_WITHOUT_CERTS"
|
||||
echo " Diese Domains werden NICHT in die SNI-Configs eingetragen."
|
||||
echo " Bitte Certs erzeugen und Script erneut ausführen."
|
||||
echo ""
|
||||
# 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)"
|
||||
NODE_CERT_OK=true
|
||||
else
|
||||
echo " ⚠️ $NODE_HOSTNAME → KEIN Cert! Caddy-Block im Caddyfile prüfen."
|
||||
NODE_CERT_OK=false
|
||||
fi
|
||||
|
||||
if [ -z "$DOMAINS_WITH_CERTS" ]; then
|
||||
echo "❌ Kein einziges Zertifikat gefunden! Abbruch."
|
||||
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 generieren
|
||||
# DOVECOT SNI Konfiguration
|
||||
# ================================================================
|
||||
DOVECOT_CFG="$CONFIG_DIR/dovecot-sni.cf"
|
||||
echo ""
|
||||
echo "📝 Generiere Dovecot SNI Konfiguration: $DOVECOT_CFG"
|
||||
echo "📝 Generiere: $DOVECOT_CFG"
|
||||
|
||||
cat > "$DOVECOT_CFG" << 'HEADER'
|
||||
# dovecot-sni.cf - Automatisch generiert von setup-dms-tls.sh
|
||||
# SNI-basierte TLS-Konfiguration für mehrere Domains.
|
||||
# Dovecot wählt das Zertifikat anhand des SNI-Hostnamens des Clients.
|
||||
# Dieses File wird via Volume-Mount in den Container eingebunden.
|
||||
# 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.
|
||||
#
|
||||
# Gemounteter Pfad: /tmp/docker-mailserver/dovecot-sni.cf
|
||||
# In DMS docker-compose.yml volumes Sektion:
|
||||
# Volume-Mount in docker-compose.yml:
|
||||
# - ./docker-data/dms/config/dovecot-sni.cf:/tmp/docker-mailserver/dovecot-sni.cf:ro
|
||||
|
||||
HEADER
|
||||
|
||||
for domain in $DOMAINS_WITH_CERTS; do
|
||||
for domain in $DOMAINS_OK; do
|
||||
CERT_PATH="$CERTS_BASE_PATH/*.$domain/*.$domain.crt"
|
||||
KEY_PATH="$CERTS_BASE_PATH/*.$domain/*.$domain.key"
|
||||
|
||||
cat >> "$DOVECOT_CFG" << EOF
|
||||
# Domain: $domain
|
||||
# $domain
|
||||
local_name mail.$domain {
|
||||
ssl_cert = <$CERT_PATH
|
||||
ssl_key = <$KEY_PATH
|
||||
@@ -128,75 +137,69 @@ local_name pop.$domain {
|
||||
EOF
|
||||
done
|
||||
|
||||
echo " ✅ $DOVECOT_CFG erstellt ($(echo $DOMAINS_WITH_CERTS | wc -w) Domains)"
|
||||
echo " ✅ Dovecot SNI: $(echo $DOMAINS_OK | wc -w) Domain(s)"
|
||||
|
||||
# ================================================================
|
||||
# POSTFIX SNI Konfiguration generieren
|
||||
# POSTFIX SNI Konfiguration
|
||||
# ================================================================
|
||||
POSTFIX_CFG="$CONFIG_DIR/postfix-main.cf"
|
||||
echo ""
|
||||
echo "📝 Generiere Postfix SNI Konfiguration: $POSTFIX_CFG"
|
||||
echo "📝 Generiere: $POSTFIX_CFG"
|
||||
|
||||
# Prüfe ob postfix-main.cf schon existiert und sichere sie
|
||||
# Backup falls vorhanden
|
||||
if [ -f "$POSTFIX_CFG" ]; then
|
||||
cp "$POSTFIX_CFG" "${POSTFIX_CFG}.bak.$(date +%Y%m%d%H%M%S)"
|
||||
echo " ℹ️ Backup erstellt: ${POSTFIX_CFG}.bak.*"
|
||||
echo " ℹ️ Backup: ${POSTFIX_CFG}.bak.*"
|
||||
fi
|
||||
|
||||
# TLS Chain Files für Postfix aufbauen
|
||||
# Postfix unterstützt smtpd_tls_chain_files mit mehreren Key/Cert Paaren
|
||||
CHAIN_FILES=""
|
||||
for domain in $DOMAINS_WITH_CERTS; do
|
||||
# smtpd_tls_chain_files aufbauen: Key + Cert Paar pro Domain
|
||||
# Postfix wählt automatisch per SNI das passende Paar
|
||||
CHAIN_LINES=""
|
||||
for domain in $DOMAINS_OK; do
|
||||
KEY_PATH="$CERTS_BASE_PATH/*.$domain/*.$domain.key"
|
||||
CERT_PATH="$CERTS_BASE_PATH/*.$domain/*.$domain.crt"
|
||||
if [ -z "$CHAIN_FILES" ]; then
|
||||
CHAIN_FILES=" $KEY_PATH, $CERT_PATH"
|
||||
if [ -z "$CHAIN_LINES" ]; then
|
||||
CHAIN_LINES=" $KEY_PATH, $CERT_PATH"
|
||||
else
|
||||
CHAIN_FILES="$CHAIN_FILES,\n $KEY_PATH, $CERT_PATH"
|
||||
CHAIN_LINES="$CHAIN_LINES,\n $KEY_PATH, $CERT_PATH"
|
||||
fi
|
||||
done
|
||||
|
||||
cat > "$POSTFIX_CFG" << POSTFIX_CONF
|
||||
cat > "$POSTFIX_CFG" << POSTFIX_EOF
|
||||
# postfix-main.cf - Automatisch generiert von setup-dms-tls.sh
|
||||
# Postfix SNI-Konfiguration für mehrere Domains.
|
||||
# DMS lädt dieses File automatisch beim Start via /tmp/docker-mailserver/
|
||||
# Postfix SNI-Konfiguration: pro Kundendomain ein Key/Cert-Paar.
|
||||
# Postfix wählt beim TLS-Handshake das passende Paar per SNI.
|
||||
# DMS lädt dieses File automatisch beim Start.
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# TLS Chain Files (Key + Cert pro Domain)
|
||||
# Postfix wählt das passende Paar automatisch per SNI
|
||||
# ------------------------------------------------------------------
|
||||
# TLS Chain: Key + Cert Paare (Postfix >= 3.4)
|
||||
smtpd_tls_chain_files =
|
||||
$(printf '%b' "$CHAIN_FILES")
|
||||
$(printf '%b' "$CHAIN_LINES")
|
||||
|
||||
POSTFIX_CONF
|
||||
POSTFIX_EOF
|
||||
|
||||
echo " ✅ $POSTFIX_CFG erstellt"
|
||||
echo " ✅ Postfix SNI: $(echo $DOMAINS_OK | wc -w) Domain(s)"
|
||||
|
||||
# ================================================================
|
||||
# Hinweise für docker-compose.yml
|
||||
# Zusammenfassung
|
||||
# ================================================================
|
||||
echo ""
|
||||
echo "============================================================"
|
||||
echo "✅ Konfigurationen generiert."
|
||||
echo ""
|
||||
echo "📋 Nächste Schritte:"
|
||||
echo ""
|
||||
echo "1. Volume-Mounts in DMS docker-compose.yml hinzufügen:"
|
||||
echo ""
|
||||
echo " volumes:"
|
||||
echo " # Bestehend (Caddy Certs - gesamtes Verzeichnis):"
|
||||
echo " - /var/lib/docker/volumes/caddy_data/_data/caddy/certificates/"
|
||||
echo " acme-v02.api.letsencrypt.org-directory:/etc/mail/certs:ro"
|
||||
echo ""
|
||||
echo " # NEU - Dovecot SNI:"
|
||||
echo " - ./docker-data/dms/config/dovecot-sni.cf:/tmp/docker-mailserver/dovecot-sni.cf:ro"
|
||||
echo ""
|
||||
echo " # Postfix-main.cf wird von DMS automatisch geladen wenn sie liegt unter:"
|
||||
echo " - ./docker-data/dms/config/postfix-main.cf:/tmp/docker-mailserver/postfix-main.cf:ro"
|
||||
echo ""
|
||||
echo "2. DMS neu starten:"
|
||||
echo "1. DMS neu starten:"
|
||||
echo " docker compose restart mailserver"
|
||||
echo ""
|
||||
echo "3. TLS testen:"
|
||||
for domain in $DOMAINS_WITH_CERTS; do
|
||||
echo " openssl s_client -connect mail.$domain:993 -servername mail.$domain"
|
||||
echo "2. 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 ""
|
||||
echo "3. Bei neuen Domains:"
|
||||
echo " a) Accounts anlegen: ./manage_mail_user.sh add user@newdomain.com PW"
|
||||
echo " b) Im Caddy-Dir: ./update-caddy-certs.sh && docker exec caddy caddy reload ..."
|
||||
echo " c) Warten bis Cert generiert (~30s)"
|
||||
echo " d) Dieses Script erneut ausführen"
|
||||
echo " e) docker compose restart mailserver"
|
||||
echo "============================================================"
|
||||
Reference in New Issue
Block a user