121 lines
4.3 KiB
Bash
121 lines
4.3 KiB
Bash
#!/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 2>/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 |