#!/usr/bin/env bash set -euo pipefail source ./lib.sh ACME_WEBROOT="/var/www/letsencrypt" install -d -m 0755 "${ACME_WEBROOT}/.well-known/acme-challenge" # Staging optional (verbraucht kein Live-Limit) CERTBOT_EXTRA=() LE_STAGING="${LE_STAGING:-0}" [[ "$LE_STAGING" = "1" ]] && CERTBOT_EXTRA+=(--test-cert) # Einheitliche LE-Mail (Fallback) LE_MAIL="${LE_EMAIL:-admin@${BASE_DOMAIN}}" resolve_ok() { local host="$1" local pats=() [[ -n "${SERVER_PUBLIC_IPV4:-}" ]] && pats+=("${SERVER_PUBLIC_IPV4//./\\.}") [[ -n "${SERVER_PUBLIC_IPV6:-}" ]] && pats+=("${SERVER_PUBLIC_IPV6//:/\\:}") [[ ${#pats[@]} -eq 0 ]] && return 0 getent ahosts "$host" | awk '{print $1}' | sort -u \ | grep -Eq "^($(IFS='|'; echo "${pats[*]}"))$" } probe_http() { local host="$1" echo test > "${ACME_WEBROOT}/.well-known/acme-challenge/_probe" curl -fsS --max-time 5 -4 "http://${host}/.well-known/acme-challenge/_probe" >/dev/null \ || curl -fsS --max-time 5 -6 "http://${host}/.well-known/acme-challenge/_probe" >/dev/null } issue() { local host="${1:-}" [[ -z "$host" ]] && return 0 echo "[i] Versuche LE für ${host} …" if ! resolve_ok "$host"; then echo "[!] DNS zeigt (noch) nicht hierher – überspringe: ${host}" return 0 fi if ! probe_http "$host"; then echo "[!] ACME-HTTP-Check für ${host} fehlgeschlagen (Port 80/IPv6/Firewall/Nginx prüfen)." # wir versuchen trotzdem – Certbot meldet sich, falls es scheitert fi EXTRA_ARGS=() # Für MX den Key wiederverwenden → stabiler TLSA (3 1 1) [[ "$host" == "${MAIL_HOSTNAME}" ]] && EXTRA_ARGS+=(--reuse-key) # WICHTIG: Deploy-Wrapper anhängen, damit Symlinks/Nginx gesetzt werden certbot certonly \ --agree-tos -m "${LE_MAIL}" --non-interactive \ --webroot -w "${ACME_WEBROOT}" -d "${host}" \ --deploy-hook /usr/local/sbin/mailwolt-deploy.sh \ "${EXTRA_ARGS[@]}" "${CERTBOT_EXTRA[@]}" || true } if [[ "${BASE_DOMAIN}" != "example.com" ]]; then issue "${UI_HOST:-}" issue "${WEBMAIL_HOST:-}" issue "${MAIL_HOSTNAME:-}" # Nginx nur neu laden, wenn aktiv if systemctl is-active --quiet nginx; then systemctl reload nginx || true fi else echo "[i] BASE_DOMAIN=example.com – LE wird übersprungen." fi # ────────────────────────────────────────────────────────────────────────────── # FIX: Validierung & Reparatur des Mail-Zertifikats # ────────────────────────────────────────────────────────────────────────────── MAIL_SSL_DIR="/etc/ssl/mail" install -d -m 0755 "$MAIL_SSL_DIR" MAIL_CERT="${MAIL_SSL_DIR}/fullchain.pem" MAIL_KEY="${MAIL_SSL_DIR}/privkey.pem" HOST="${MAIL_HOSTNAME:-}" LE_DIR="" [[ -n "$HOST" ]] && LE_DIR="/etc/letsencrypt/live/${HOST}" need_fix=0 # Ist der vorhandene Key gültig? (leer/nicht vorhanden/ungültig -> fix) if [[ ! -s "$MAIL_KEY" ]] || ! openssl pkey -in "$MAIL_KEY" -noout >/dev/null 2>&1; then need_fix=1 fi # Wenn Fix nötig: aus Let's Encrypt Live kopieren if [[ $need_fix -eq 1 ]]; then echo "[!] Ungültiger oder fehlender Mail-Private-Key – versuche Reparatur …" if [[ -n "$LE_DIR" && -r "${LE_DIR}/privkey.pem" && -r "${LE_DIR}/fullchain.pem" ]]; then cp -f "${LE_DIR}/privkey.pem" "$MAIL_KEY" cp -f "${LE_DIR}/fullchain.pem" "$MAIL_CERT" chown root:root "$MAIL_CERT" "$MAIL_KEY" chmod 600 "$MAIL_KEY" chmod 644 "$MAIL_CERT" echo "[+] Zertifikate neu kopiert aus ${LE_DIR}." # Reload NICHT sofort – flaggen für 90-services touch /run/mailwolt.need-dovecot-reload else echo "[!] Konnte ${LE_DIR}/privkey.pem oder fullchain.pem nicht lesen – bitte prüfen." fi else echo "[✓] Mail-Zertifikat & -Key sind gültig." fi # Optionaler Live-Check (nur wenn Host gesetzt) if [[ -n "$HOST" ]]; then if openssl s_client -connect "${HOST}:993" -servername "${HOST}" /dev/null \ | grep -q "Verify return code: 0"; then echo "[✓] TLS-Handshake erfolgreich auf imaps://${HOST}:993." else echo "[!] TLS-Handshake auf imaps://${HOST}:993 fehlgeschlagen (Dovecot Reload folgt in 90-services, falls Flag gesetzt)." fi fi