#!/usr/bin/env bash set -euo pipefail UI_HOST=""; WEBMAIL_HOST=""; MAIL_HOST=""; SSL_AUTO=0 while [[ $# -gt 0 ]]; do case "$1" in --ui-host) UI_HOST="$2"; shift 2 ;; --webmail-host) WEBMAIL_HOST="$2"; shift 2 ;; --mail-host) MAIL_HOST="$2"; shift 2 ;; --ssl-auto) SSL_AUTO="$2"; shift 2 ;; *) shift ;; esac done PHPV=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;') PHP_FPM_SOCK="/run/php/php${PHPV}-fpm.sock" [ -S "$PHP_FPM_SOCK" ] || PHP_FPM_SOCK="/run/php/php-fpm.sock" APP_DIR="/var/www/mailwolt" NGINX_SITE="/etc/nginx/sites-available/mailwolt.conf" ACME_ROOT="/var/www/letsencrypt" mkdir -p "${ACME_ROOT}/.well-known/acme-challenge" # --- Phase 1: HTTP-only Vhosts mit ACME-Challenge --- cat > "${NGINX_SITE}" </dev/null | grep -q 'inet6' } cert_needs_action() { local domain="$1" local cert="/etc/letsencrypt/live/${domain}/fullchain.pem" [ ! -f "${cert}" ] && return 0 # 0 = gültig für >10 Tage → überspringen; 1 = läuft ab → erneuern openssl x509 -checkend 864000 -noout -in "${cert}" 2>/dev/null && return 1 return 0 } certbot_safe() { local domain="$1" local has_aaaa has_aaaa=$(dig +short AAAA "${domain}" 2>/dev/null | head -1) if [ -n "${has_aaaa}" ] && ! has_global_ipv6; then echo "[!] ${domain}: AAAA-Record vorhanden aber kein IPv6 auf diesem Server — Let's Encrypt würde fehlschlagen. Self-signed wird verwendet." >&2 return 1 fi certbot certonly --webroot \ -w "${ACME_ROOT}" \ -d "${domain}" \ --non-interactive --agree-tos \ --email "webmaster@${domain}" \ --no-eff-email } if [ "${SSL_AUTO}" = "1" ]; then for DOMAIN in "${UI_HOST}" "${WEBMAIL_HOST}"; do [ -z "${DOMAIN}" ] && continue if cert_needs_action "${DOMAIN}"; then certbot_safe "${DOMAIN}" || true fi done fi # --- Phase 3: Finale Vhosts --- # Nur HTTPS wenn LE-Cert tatsächlich vorhanden, sonst HTTP-only (kein self-signed Fallback) UI_HAS_CERT=0 WM_HAS_CERT=0 [ -f "/etc/letsencrypt/live/${UI_HOST}/fullchain.pem" ] && UI_HAS_CERT=1 [ -f "/etc/letsencrypt/live/${WEBMAIL_HOST}/fullchain.pem" ] && WM_HAS_CERT=1 ( if [ "${UI_HAS_CERT}" = "1" ] || [ "${WM_HAS_CERT}" = "1" ]; then # Mindestens ein Cert vorhanden → HTTP-Redirect Block cat < "${NGINX_SITE}" # State-Dateien schreiben — korrekt pro Domain, nicht pauschal "done" STATE_DIR="/var/lib/mailwolt/wizard" if [ -d "${STATE_DIR}" ]; then # UI: done nur wenn LE-Cert tatsächlich vorhanden, sonst error if [ -f "${STATE_DIR}/ui" ]; then if [ "${UI_HAS_CERT}" = "1" ]; then printf "done" > "${STATE_DIR}/ui" else printf "error" > "${STATE_DIR}/ui" fi fi # Webmail: done nur wenn LE-Cert tatsächlich vorhanden, sonst error if [ -f "${STATE_DIR}/webmail" ]; then if [ "${WM_HAS_CERT}" = "1" ]; then printf "done" > "${STATE_DIR}/webmail" else printf "error" > "${STATE_DIR}/webmail" fi fi # Mail-Domain: kein certbot im Wizard für MX → skip (kein Fehler, nur nicht zutreffend) [ -f "${STATE_DIR}/mail" ] && printf "skip" > "${STATE_DIR}/mail" # done-Signal: immer schreiben damit der 2s-Poll stoppt if [ "${UI_HAS_CERT}" = "1" ] || [ "${WM_HAS_CERT}" = "1" ]; then # Erst done schreiben, dann 6s warten bevor nginx auf HTTPS wechselt — # so hat der Browser Zeit den "Zum Login"-Button zu rendern bevor der Switch passiert printf "1" > "${STATE_DIR}/done" sleep 6 else printf "0" > "${STATE_DIR}/done" fi fi nginx -t && systemctl reload nginx