From ce31a51b1811ab27e6e4cfbbb205c8d36dd46b7c Mon Sep 17 00:00:00 2001 From: boksbc Date: Fri, 17 Oct 2025 00:41:49 +0200 Subject: [PATCH] Laudende Default seite entfernen --- scripts/21-le-deploy-hook.sh | 147 ++++++++++++++++------------ scripts/75-le-issue.sh | 3 +- scripts/98-motd.sh | 171 +++++++++++++++++++++++++++++++-- scripts/99-summary.sh | 179 +++++++++++++++++++++++++++-------- 4 files changed, 387 insertions(+), 113 deletions(-) diff --git a/scripts/21-le-deploy-hook.sh b/scripts/21-le-deploy-hook.sh index a62aaa6..01514ae 100644 --- a/scripts/21-le-deploy-hook.sh +++ b/scripts/21-le-deploy-hook.sh @@ -2,17 +2,18 @@ set -euo pipefail source ./lib.sh -# ----------------------------------------------------------------------------- +# ──────────────────────────────────────────────────────────────────────────── # 21-le-deploy-hook.sh -# - Legt /etc/mailwolt/installer.env (falls fehlt) an -# - Erzeugt LE-Deploy-Hooks: -# * 50-mailwolt-symlinks.sh → verlinkt LE-Zerts nach /etc/ssl/{ui,webmail,mail} -# * 60-mailwolt-tlsa.sh → schreibt TLSA (3 1 1) für MX nach jedem Renew -# ----------------------------------------------------------------------------- +# • legt /etc/mailwolt/installer.env an (falls fehlt) +# • erzeugt Deploy-Hooks: +# - 50-mailwolt-symlinks.sh → verlinkt LE-Zerts nach /etc/ssl/{ui,webmail,mail} +# - 60-mailwolt-tlsa.sh → aktualisiert TLSA (3 1 1) für MX bei jedem Renew +# • KEIN Reload von Postfix/Dovecot (kommt später im Installer) +# ──────────────────────────────────────────────────────────────────────────── -# 1) Sicherstellen, dass die Hosts persistent verfügbar sind +# 0) Hostnamen persistent speichern (für spätere Deploys) +install -d -m 0755 /etc/mailwolt if [[ ! -f /etc/mailwolt/installer.env ]]; then - install -d -m 0755 /etc/mailwolt cat >/etc/mailwolt/installer.env </etc/letsencrypt/renewal-hooks/deploy/50-mailwolt-symlinks.sh <<'HOOK' +# ──────────────────────────────────────────────────────────────────────────── +# 2) 50-mailwolt-symlinks.sh +# ──────────────────────────────────────────────────────────────────────────── +cat >/etc/letsencrypt/renewal-hooks/deploy/50-mailwolt-symlinks.sh < ${le_base}" - fi + local le_base="\$1" target_dir="\$2" + local cert="\${le_base}/fullchain.pem" + local key="\${le_base}/privkey.pem" + [[ -s "\$cert" && -s "\$key" ]] || return 0 + ln -sf "\$cert" "\${target_dir}/fullchain.pem" + ln -sf "\$key" "\${target_dir}/privkey.pem" + chmod 644 "\${target_dir}/fullchain.pem" 2>/dev/null || true + chmod 600 "\${target_dir}/privkey.pem" 2>/dev/null || true + echo "[+] Linked \${target_dir} -> \${le_base}" } -# Nur linken, wenn Hostnamen vorhanden sind -[[ -n "$UI_HOST" ]] && link_if "$UI_LE" "$UI_SSL_DIR" -[[ -n "$WEBMAIL_HOST" ]] && link_if "$WEBMAIL_LE" "$WEBMAIL_SSL_DIR" -[[ -n "$MX_HOST" ]] && link_if "$MX_LE" "$MAIL_SSL_DIR" +# Verlinken (nur wenn Host konfiguriert) +[[ -n "${UI_HOST}" ]] && link_if "\$UI_LE" "\$UI_SSL_DIR" +[[ -n "${WEBMAIL_HOST}" ]] && link_if "\$WEBMAIL_LE" "\$WEBMAIL_SSL_DIR" +[[ -n "${MAIL_HOSTNAME}" ]] && link_if "\$MX_LE" "\$MAIL_SSL_DIR" -# sinnvolle Rechte (Key nur für root lesbar, Chain world-readable) -chmod 640 "${UI_SSL_DIR}/privkey.pem" 2>/dev/null || true -chmod 640 "${WEBMAIL_SSL_DIR}/privkey.pem" 2>/dev/null || true -chmod 640 "${MAIL_SSL_DIR}/privkey.pem" 2>/dev/null || true -chmod 644 "${UI_SSL_DIR}/fullchain.pem" 2>/dev/null || true -chmod 644 "${WEBMAIL_SSL_DIR}/fullchain.pem" 2>/dev/null || true -chmod 644 "${MAIL_SSL_DIR}/fullchain.pem" 2>/dev/null || true - -# Nur Nginx neu laden – Postfix/Dovecot startet später im Installer -systemctl reload nginx || true +# Nur reloaden, wenn Nginx aktiv ist (Installer startet ihn später erst) +if systemctl is-active --quiet nginx; then + systemctl reload nginx || true +fi HOOK chmod +x /etc/letsencrypt/renewal-hooks/deploy/50-mailwolt-symlinks.sh -# 4) Hook: TLSA (3 1 1) für MX nach jedem Renew/Issue generieren +# ──────────────────────────────────────────────────────────────────────────── +# 3) 60-mailwolt-tlsa.sh +# → nutzt Laravel, falls vorhanden; sonst Fallback mit OpenSSL. +# → schreibt nur, wenn sich der Hash geändert hat (idempotent) +# ──────────────────────────────────────────────────────────────────────────── cat >/etc/letsencrypt/renewal-hooks/deploy/60-mailwolt-tlsa.sh <<'HOOK' #!/usr/bin/env bash set -euo pipefail -# MAIL_HOSTNAME kommt von certbot via Environment nicht automatisch, -# daher direkt aus installer.env lesen, falls gesetzt. +# installer.env lesen set +u [ -r /etc/mailwolt/installer.env ] && . /etc/mailwolt/installer.env set -u + +APP_ENV_VAL="${APP_ENV:-production}" +BASE_DOMAIN_VAL="${BASE_DOMAIN:-example.com}" + +case "$APP_ENV_VAL" in + local|dev|development) exit 0 ;; +esac +[ "$BASE_DOMAIN_VAL" = "example.com" ] && exit 0 + MX_HOST="${MAIL_HOSTNAME:-}" +SERVICE="_25._tcp" +DNS_DIR="/etc/mailwolt/dns" +OUT_FILE="${DNS_DIR}/${MX_HOST}.tlsa.txt" -[[ -n "$MX_HOST" ]] || exit 0 - -# Nur reagieren, wenn das MX-Zert in diesem Run drin war +# Nur reagieren, wenn MX-Zertifikat betroffen war case " ${RENEWED_DOMAINS:-} " in - *" ${MX_HOST} "*) ;; # ok + *" ${MX_HOST} "*) ;; *) exit 0 ;; esac CERT="${RENEWED_LINEAGE}/fullchain.pem" -if [[ -s "$CERT" ]]; then - HASH="$(openssl x509 -in "$CERT" -noout -pubkey \ - | openssl pkey -pubin -outform DER \ - | openssl dgst -sha256 | sed 's/^.*= //')" - TLSA_LINE="_25._tcp.${MX_HOST}. IN TLSA 3 1 1 ${HASH}" - install -d -m 0755 /etc/mailwolt/dns - echo "${TLSA_LINE}" > "/etc/mailwolt/dns/${MX_HOST}.tlsa.txt" - echo "[TLSA] ${TLSA_LINE}" +[ -s "$CERT" ] || exit 0 + +# Wenn Laravel vorhanden ist → interner Command (DB + Datei idempotent) +if command -v php >/dev/null 2>&1 && [ -d /var/www/mailwolt ]; then + cd /var/www/mailwolt || exit 0 + php artisan dns:tlsa:refresh || true + exit 0 fi + +# Fallback: nur Datei aktualisieren, wenn Hash sich ändert +HASH="$(openssl x509 -in "$CERT" -noout -pubkey \ + | openssl pkey -pubin -outform DER \ + | openssl dgst -sha256 | sed 's/^.*= //')" +NEW_LINE="${SERVICE}.${MX_HOST}. IN TLSA 3 1 1 ${HASH}" + +mkdir -p "$DNS_DIR" + +if [ -r "$OUT_FILE" ] && grep -q "IN TLSA" "$OUT_FILE"; then + if grep -q "$HASH" "$OUT_FILE"; then + echo "[TLSA] Unverändert – kein Update nötig." + exit 0 + fi +fi + +echo "$NEW_LINE" > "$OUT_FILE" +echo "[TLSA] Aktualisiert: $NEW_LINE" HOOK -chmod +x /etc/letsencrypt/renewal-hooks/deploy/60-mailwolt-tlsa.sh \ No newline at end of file +chmod +x /etc/letsencrypt/renewal-hooks/deploy/60-mailwolt-tlsa.sh + +# ──────────────────────────────────────────────────────────────────────────── +echo "[✓] Deploy-Hooks installiert." \ No newline at end of file diff --git a/scripts/75-le-issue.sh b/scripts/75-le-issue.sh index 1de7be7..d3ff276 100644 --- a/scripts/75-le-issue.sh +++ b/scripts/75-le-issue.sh @@ -50,7 +50,8 @@ if [[ "$BASE_DOMAIN" != "example.com" ]]; then issue "$WEBMAIL_HOST" issue "$MAIL_HOSTNAME" - systemctl reload nginx || true +run-parts /etc/letsencrypt/renewal-hooks/deploy || true +systemctl reload nginx || true # TLSA direkt einmal schreiben (Hook macht es bei Renewals sowieso) MX_CERT="/etc/letsencrypt/live/${MAIL_HOSTNAME}/fullchain.pem" diff --git a/scripts/98-motd.sh b/scripts/98-motd.sh index 1e6afea..a8e912a 100644 --- a/scripts/98-motd.sh +++ b/scripts/98-motd.sh @@ -3,12 +3,31 @@ set -euo pipefail source ./lib.sh log "MOTD installieren …" + install -d /usr/local/bin + cat >/usr/local/bin/mw-motd <<'SH' #!/usr/bin/env bash set -euo pipefail -NC="\033[0m"; CY="\033[1;36m"; GR="\033[1;32m"; YE="\033[1;33m"; RD="\033[1;31m"; GY="\033[0;90m" -printf "\033[1;36m" + +# Farben +NC="\033[0m"; CY="\033[1;36m"; GR="\033[1;32m"; YE="\033[1;33m"; RD="\033[1;31m"; GY="\033[0;90m"; WH="\033[1;37m" + +# Installer-Variablen (optional) +UI_HOST=""; WEBMAIL_HOST=""; MAIL_HOSTNAME=""; LE_EMAIL=""; PROXY_MODE=""; NPM_IP="" +if [ -r /etc/mailwolt/installer.env ]; then + # shellcheck disable=SC1091 + . /etc/mailwolt/installer.env || true +fi +# Aus .env (falls vorhanden) +if [ -r /var/www/mailwolt/.env ]; then + LE_EMAIL="${LE_EMAIL:-$(grep -E '^LE_EMAIL=' /var/www/mailwolt/.env 2>/dev/null | sed 's/^LE_EMAIL=//')}" + PROXY_MODE="${PROXY_MODE:-$(grep -E '^PROXY_MODE=' /var/www/mailwolt/.env 2>/dev/null | sed 's/^PROXY_MODE=//')}" + NPM_IP="${NPM_IP:-$(grep -E '^NPM_IP=' /var/www/mailwolt/.env 2>/dev/null | sed 's/^NPM_IP=//')}" +fi + +# ASCII-Header +printf "${CY}" cat <<'ASCII' :::: :::: ::: ::::::::::: ::: ::: ::: :::::::: ::: ::::::::::: +:+:+: :+:+:+ :+: :+: :+: :+: :+: :+: :+: :+: :+: :+: @@ -18,25 +37,101 @@ cat <<'ASCII' #+# #+# #+# #+# #+# #+# #+#+# #+#+# #+# #+# #+# #+# ### ### ### ### ########### ########## ### ### ######## ########## ### ASCII -printf "\033[0m\n" +printf "${NC}\n" + +# Systemdaten now="$(date '+%Y-%m-%d %H:%M:%S %Z')" fqdn="$(hostname -f 2>/dev/null || hostname)" ip_int="$(hostname -I 2>/dev/null | awk '{print $1}')" -ip_ext=""; command -v curl >/dev/null 2>&1 && ip_ext="$(curl -s --max-time 1 https://ifconfig.me || true)" +ip_ext=""; command -v curl >/dev/null 2>&1 && ip_ext="$(curl -fsS --max-time 1 https://ifconfig.me 2>/dev/null || true)" upt="$(uptime -p 2>/dev/null || true)" cores="$(nproc 2>/dev/null || echo -n '?')" load="$(awk '{print $1" / "$2" / "$3}' /proc/loadavg 2>/dev/null)" -svc(){ systemctl is-active --quiet "$1" && echo -e "${GR}OK${NC}" || echo -e "${RD}FAIL${NC}"; } + +# RAM/SWAP (MiB) +mem_total="$(awk '/MemTotal/ {print int($2/1024)}' /proc/meminfo 2>/dev/null)" +mem_avail="$(awk '/MemAvailable/ {print int($2/1024)}' /proc/meminfo 2>/dev/null)" +mem_used=$(( (mem_total-mem_avail) )) +swap_total="$(awk '/SwapTotal/ {print int($2/1024)}' /proc/meminfo 2>/dev/null)" +swap_free="$(awk '/SwapFree/ {print int($2/1024)}' /proc/meminfo 2>/dev/null)" +swap_used=$(( (swap_total-swap_free) )) + +# Disks (/, /var) +disk_line(){ + local mnt="$1" + df -hP "$mnt" 2>/dev/null | awk 'NR==2{printf "%s/%s (%s used)", $3,$2,$5}' +} +disk_root="$(disk_line /)" +disk_var="$(disk_line /var)" + +svc_state(){ + local unit="$1" + if systemctl is-active --quiet "$unit"; then + printf "${GR}OK${NC}" + else + printf "${RD}FAIL${NC}" + fi +} + +# Zeilen printf "${CY}Information as of:${NC} ${YE}%s${NC}\n" "$now" printf "${GY}FQDN :${NC} %s\n" "$fqdn" -if [ -n "$ip_ext" ]; then printf "${GY}IP :${NC} %s ${GY}(ext:${NC} %s${GY})${NC}\n" "${ip_int:-?}" "$ip_ext"; else printf "${GY}IP :${NC} %s\n" "${ip_int:-?}"; fi +if [ -n "$ip_ext" ]; then + printf "${GY}IP :${NC} %s ${GY}(ext:${NC} %s${GY})${NC}\n" "${ip_int:-?}" "$ip_ext" +else + printf "${GY}IP :${NC} %s\n" "${ip_int:-?}" +fi printf "${GY}Uptime :${NC} %s\n" "${upt:-?}" -printf "${GY}Cores :${NC} %s\n" "$cores" -printf "${GY}Load :${NC} %s (1/5/15)\n" "${load:-?}" -printf "${GY}Svc :${NC} postfix: $(svc postfix) dovecot: $(svc dovecot) nginx: $(svc nginx) mariadb: $(svc mariadb) redis: $(svc redis)\n" +printf "${GY}CPU :${NC} %s cores, load %s (1/5/15)\n" "$cores" "${load:-?}" +printf "${GY}RAM :${NC} %s MiB used / %s MiB total\n" "${mem_used:-?}" "${mem_total:-?}" +printf "${GY}SWAP :${NC} %s MiB used / %s MiB total\n" "${swap_used:-?}" "${swap_total:-?}" +printf "${GY}Disk / :${NC} %s\n" "${disk_root:-?}" +printf "${GY}Disk/var:${NC} %s\n" "${disk_var:-?}" + +# App/Installer Infos +[ -n "$LE_EMAIL" ] && printf "${GY}LE E-Mail:${NC} %s\n" "$LE_EMAIL" +[ -n "$UI_HOST" ] && printf "${GY}UI Host :${NC} %s\n" "$UI_HOST" +[ -n "$WEBMAIL_HOST" ] && printf "${GY}Webmail :${NC} %s\n" "$WEBMAIL_HOST" +[ -n "$MAIL_HOSTNAME" ]&& printf "${GY}MX Host :${NC} %s\n" "$MAIL_HOSTNAME" +if [ -n "${PROXY_MODE:-}" ]; then + if [ "$PROXY_MODE" = "1" ]; then + printf "${GY}Proxy :${NC} ja (NPM: %s)\n" "${NPM_IP:-unbekannt}" + else + printf "${GY}Proxy :${NC} nein\n" + fi +fi + +# Services +printf "${WH}\nServices:${NC}\n" +printf " nginx … %b\n" "$(svc_state nginx)" +printf " mariadb … %b\n" "$(svc_state mariadb)" +printf " redis-server … %b\n" "$(svc_state redis-server)" +printf " postfix … %b\n" "$(svc_state postfix)" +printf " dovecot … %b\n" "$(svc_state dovecot)" +# App Units (optional) +printf " mailwolt-ws … %b\n" "$(svc_state mailwolt-ws)" +printf " mailwolt-queue… %b\n" "$(svc_state mailwolt-queue)" +printf " mailwolt-schedule … %b\n" "$(svc_state mailwolt-schedule)" + +# Zertifikate (kurzer Hinweis, optional) +show_cert_hint(){ + local name="$1" path="$2" + if [ -r "$path" ]; then + local exp + exp="$(openssl x509 -in "$path" -noout -enddate 2>/dev/null | sed 's/notAfter=//')" + [ -n "$exp" ] && printf "${GY}%s cert:${NC} expires %s\n" "$name" "$exp" + fi +} +show_cert_hint "UI" "/etc/ssl/ui/fullchain.pem" +show_cert_hint "Webmail" "/etc/ssl/webmail/fullchain.pem" +show_cert_hint "MX" "/etc/ssl/mail/fullchain.pem" + +echo SH + chmod +x /usr/local/bin/mw-motd +# update-motd integration if [[ -d /etc/update-motd.d ]]; then cat >/etc/update-motd.d/10-mailwolt <<'SH' #!/usr/bin/env bash @@ -45,8 +140,64 @@ SH chmod +x /etc/update-motd.d/10-mailwolt [[ -f /etc/update-motd.d/50-motd-news ]] && chmod -x /etc/update-motd.d/50-motd-news || true else + # Fallback für Systeme ohne dynamic MOTD cat >/etc/profile.d/10-mailwolt-motd.sh <<'SH' case "$-" in *i*) /usr/local/bin/mw-motd ;; esac SH fi -: > /etc/motd 2>/dev/null || true \ No newline at end of file + +# altes /etc/motd leeren (sonst doppelt) +: > /etc/motd 2>/dev/null || true + +##!/usr/bin/env bash +#set -euo pipefail +#source ./lib.sh +# +#log "MOTD installieren …" +#install -d /usr/local/bin +#cat >/usr/local/bin/mw-motd <<'SH' +##!/usr/bin/env bash +#set -euo pipefail +#NC="\033[0m"; CY="\033[1;36m"; GR="\033[1;32m"; YE="\033[1;33m"; RD="\033[1;31m"; GY="\033[0;90m" +#printf "\033[1;36m" +#cat <<'ASCII' +#:::: :::: ::: ::::::::::: ::: ::: ::: :::::::: ::: ::::::::::: +#+:+:+: :+:+:+ :+: :+: :+: :+: :+: :+: :+: :+: :+: :+: +#+:+ +:+:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +#+#+ +:+ +#+ +#++:++#++: +#+ +#+ +#+ +:+ +#+ +#+ +:+ +#+ +#+ +#+#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+#+ +#+ +#+ +#+ +#+ +#+ +##+# #+# #+# #+# #+# #+# #+#+# #+#+# #+# #+# #+# #+# +#### ### ### ### ########### ########## ### ### ######## ########## ### +#ASCII +#printf "\033[0m\n" +#now="$(date '+%Y-%m-%d %H:%M:%S %Z')" +#fqdn="$(hostname -f 2>/dev/null || hostname)" +#ip_int="$(hostname -I 2>/dev/null | awk '{print $1}')" +#ip_ext=""; command -v curl >/dev/null 2>&1 && ip_ext="$(curl -s --max-time 1 https://ifconfig.me || true)" +#upt="$(uptime -p 2>/dev/null || true)" +#cores="$(nproc 2>/dev/null || echo -n '?')" +#load="$(awk '{print $1" / "$2" / "$3}' /proc/loadavg 2>/dev/null)" +#svc(){ systemctl is-active --quiet "$1" && echo -e "${GR}OK${NC}" || echo -e "${RD}FAIL${NC}"; } +#printf "${CY}Information as of:${NC} ${YE}%s${NC}\n" "$now" +#printf "${GY}FQDN :${NC} %s\n" "$fqdn" +#if [ -n "$ip_ext" ]; then printf "${GY}IP :${NC} %s ${GY}(ext:${NC} %s${GY})${NC}\n" "${ip_int:-?}" "$ip_ext"; else printf "${GY}IP :${NC} %s\n" "${ip_int:-?}"; fi +#printf "${GY}Uptime :${NC} %s\n" "${upt:-?}" +#printf "${GY}Cores :${NC} %s\n" "$cores" +#printf "${GY}Load :${NC} %s (1/5/15)\n" "${load:-?}" +#printf "${GY}Svc :${NC} postfix: $(svc postfix) dovecot: $(svc dovecot) nginx: $(svc nginx) mariadb: $(svc mariadb) redis: $(svc redis)\n" +#SH +#chmod +x /usr/local/bin/mw-motd +# +#if [[ -d /etc/update-motd.d ]]; then +# cat >/etc/update-motd.d/10-mailwolt <<'SH' +##!/usr/bin/env bash +#/usr/local/bin/mw-motd +#SH +# chmod +x /etc/update-motd.d/10-mailwolt +# [[ -f /etc/update-motd.d/50-motd-news ]] && chmod -x /etc/update-motd.d/50-motd-news || true +#else +# cat >/etc/profile.d/10-mailwolt-motd.sh <<'SH' +#case "$-" in *i*) /usr/local/bin/mw-motd ;; esac +#SH +#fi +#: > /etc/motd 2>/dev/null || true \ No newline at end of file diff --git a/scripts/99-summary.sh b/scripts/99-summary.sh index ac19a8b..c47fd31 100644 --- a/scripts/99-summary.sh +++ b/scripts/99-summary.sh @@ -2,82 +2,181 @@ set -euo pipefail source ./lib.sh -log() { printf "\033[1;32m[+]\033[0m %s\n" "$*"; } -ok() { printf " [\033[1;32mOK\033[0m]\n"; } -fail() { printf " [\033[1;31mFAIL\033[0m]\n"; } +# ───────────────────────────────────────────────────────────── +# Schöner Abschluss-Summary mit Farben, Diensten & Smoke-Test +# ───────────────────────────────────────────────────────────── +# Farben & Symbole +BOLD="\033[1m"; DIM="\033[2m"; NC="\033[0m" +GREEN="\033[1;32m"; RED="\033[1;31m"; YELLOW="\033[1;33m"; CYAN="\033[1;36m"; GREY="\033[0;90m" +OKS="${GREEN}OK${NC}"; FAILS="${RED}FAIL${NC}"; WARN="${YELLOW}!${NC}" +PLUS="${GREEN}[+]${NC}" + +bar(){ printf "${CYAN}%s${NC}\n" "──────────────────────────────────────────────────────────────────────────────"; } +log(){ printf "${GREEN}[+]${NC} %s\n" "$*"; } +ok() { printf " [${OKS}]\n"; } +fail(){ printf " [${FAILS}]\n"; } + +# Evtl. persistente Variablen laden (falls vom Installer geschrieben) +set +u +[ -r /etc/mailwolt/installer.env ] && . /etc/mailwolt/installer.env +set -u + +# Defaults / Umgebung APP_USER="${APP_USER:-mailwolt}" APP_GROUP="${APP_GROUP:-www-data}" APP_DIR="${APP_DIR:-/var/www/${APP_USER}}" +BASE_DOMAIN="${BASE_DOMAIN:-example.com}" +UI_HOST="${UI_HOST:-}" +WEBMAIL_HOST="${WEBMAIL_HOST:-}" +MAIL_HOSTNAME="${MAIL_HOSTNAME:-}" + +APP_ENV="${APP_ENV:-production}" +PROXY_MODE="${PROXY_MODE:-0}" +NPM_IP="${NPM_IP:-}" + +LE_EMAIL="${LE_EMAIL:-admin@${BASE_DOMAIN}}" +ACME_WEBROOT="/var/www/letsencrypt" + +# Zert-Pfade (werden idR via Hook symlinked) UI_CERT="/etc/ssl/ui/fullchain.pem" UI_KEY="/etc/ssl/ui/privkey.pem" -SCHEME="http" +WEBMAIL_CERT="/etc/ssl/webmail/fullchain.pem" +MAIL_CERT="/etc/ssl/mail/fullchain.pem" -SERVER_PUBLIC_IPV4="$(detect_ip)" +# IPs +SERVER_PUBLIC_IPV4="${SERVER_PUBLIC_IPV4:-$(detect_ip)}" +SERVER_PUBLIC_IPV6="${SERVER_PUBLIC_IPV6:-$(detect_ipv6)}" + +# Scheme/URLs ableiten +SCHEME="http" [[ -s "$UI_CERT" && -s "$UI_KEY" ]] && SCHEME="https" -UI_HOST="${UI_HOST:-}" -APP_URL="${APP_URL:-${SCHEME}://${SERVER_PUBLIC_IPV4}}" -if [[ -n "$UI_HOST" ]]; then - APP_URL="${SCHEME}://${UI_HOST}" -fi +APP_URL="${SCHEME}://${UI_HOST:-$SERVER_PUBLIC_IPV4}" +WEBMAIL_URL="${SCHEME}://${WEBMAIL_HOST:-$SERVER_PUBLIC_IPV4}" -MAIL_HOSTNAME="${MAIL_HOSTNAME:-${SERVER_PUBLIC_IPV4}}" +# Erkennen, ob die Zert-Symlinks auf LE zeigen (nur kosmetisch) +real_target() { readlink -f -- "$1" 2>/dev/null || true; } +UI_CERT_TARGET="$(real_target "$UI_CERT")" +WEBMAIL_CERT_TARGET="$(real_target "$WEBMAIL_CERT")" +MAIL_CERT_TARGET="$(real_target "$MAIL_CERT")" + +is_le(){ [[ "$1" == /etc/letsencrypt/live/*/fullchain.pem ]]; } +UI_LE=$([[ -n "$UI_CERT_TARGET" ]] && is_le "$UI_CERT_TARGET" && echo "LE" || echo "self-signed/none") +WEBMAIL_LE=$([[ -n "$WEBMAIL_CERT_TARGET" ]] && is_le "$WEBMAIL_CERT_TARGET" && echo "LE" || echo "self-signed/none") +MAIL_LE=$([[ -n "$MAIL_CERT_TARGET" ]] && is_le "$MAIL_CERT_TARGET" && echo "LE" || echo "self-signed/none") echo -echo "──────────────────────────────────────────────────────────────────────────────" -echo "✔ MailWolt Bootstrap fertig" -echo "──────────────────────────────────────────────────────────────────────────────" -printf " Aufruf UI: %s\n" "${APP_URL}" -printf " App Root: %s\n" "${APP_DIR}" -printf " Nginx Site: %s\n" "/etc/nginx/sites-available/${APP_USER}.conf" -printf " Mail-FQDN: %s\n" "${MAIL_HOSTNAME}" +bar +printf " %s %s\n" "✔ MailWolt Bootstrap fertig" "" +bar + +# Kopf-Infos +printf " %-14s %s\n" "Aufruf UI:" "${APP_URL}" +printf " %-14s %s\n" "Webmail:" "${WEBMAIL_URL}" +printf " %-14s %s\n" "App Root:" "${APP_DIR}" +printf " %-14s %s\n" "Mail-FQDN:" "${MAIL_HOSTNAME:-$SERVER_PUBLIC_IPV4}" +printf " %-14s %s\n" "BASE_DOMAIN:" "${BASE_DOMAIN}" +printf " %-14s %s\n" "LE-Email:" "${LE_EMAIL}" +printf " %-14s %s\n" "APP_ENV:" "${APP_ENV}" +[[ -v PROXY_MODE ]] && printf " %-14s %s\n" "Proxy-Mode:" "$([[ "$PROXY_MODE" = "1" ]] && echo "ja (NPM: ${NPM_IP:-unbekannt})" || echo "nein")"printf " %-14s %s\n" "Server IPv4:" "${SERVER_PUBLIC_IPV4}" +printf " %-14s %s\n" "Server IPv6:" "${SERVER_PUBLIC_IPV6:-–}" +printf " %-14s %s\n" "ACME Webroot:" "${ACME_WEBROOT}" + echo +printf " %-14s UI=%s, Webmail=%s, MX=%s\n" "Zertifikate:" "$UI_LE" "$WEBMAIL_LE" "$MAIL_LE" +echo + echo " Anmeldung: Keine vordefinierten Admin-Daten." echo " Bitte zuerst registrieren (Erst-User wird Admin, danach" echo " wird die Registrierung automatisch gesperrt)." echo -# -------- Services ---------- -printf "Services:\n" +# Dienste-Status +bar +echo " Services" +bar + +OK_LIST=() +FAIL_LIST=() + svc(){ - local name="$1" - printf " • %-10s … " "$name" - if systemctl is-active --quiet "$name"; then ok; else fail; fi + local unit="$1" label="${2:-$1}" + printf " • %-18s … " "$label" + if systemctl is-active --quiet "$unit"; then + ok + OK_LIST+=("$label") + else + fail + FAIL_LIST+=("$label") + fi } + +# Kern-Services svc nginx svc mariadb svc redis-server svc postfix svc dovecot -svc "${APP_USER}-ws" || true -svc "${APP_USER}-schedule" || true -svc "${APP_USER}-queue" || true +# App-Worker (tolerant) +svc "${APP_USER}-ws" "mailwolt-ws" || true +svc "${APP_USER}-schedule" "mailwolt-schedule" || true +svc "${APP_USER}-queue" "mailwolt-queue" || true + +# Kurze Zusammenfassung +echo +if ((${#OK_LIST[@]})); then + printf " ${GREEN}OK:${NC} %s\n" "$(IFS=', '; echo "${OK_LIST[*]}")" +fi +if ((${#FAIL_LIST[@]})); then + printf " ${RED}FAIL:${NC} %s\n" "$(IFS=', '; echo "${FAIL_LIST[*]}")" + echo " ${YELLOW}Hinweis:${NC} Details mit: journalctl -u -b --no-pager" +fi echo -# -------- Ports / Smoke Test ---------- -echo "──────────────────────────────────────────────────────────────────────────────" +# Smoke-Test +bar echo " Smoke-Test (SMTP/IMAP/POP3 mit/ohne TLS)" -echo "──────────────────────────────────────────────────────────────────────────────" +bar check_port(){ - local label="$1" cmd="$2" - printf "[%-3s] %-35s … " "$label" "$3" + local tag="$1" cmd="$2" desc="$3" + printf " [%-3s] %-35s … " "$tag" "$desc" if timeout 8s bash -lc "$cmd" >/dev/null 2>&1; then ok; else fail; fi } +# ein kurzes Delay, damit frisch gestartete Dienste lauschen sleep 6 || true -# SMTP family -check_port "25" 'printf "QUIT\r\n" | nc -w 3 127.0.0.1 25' "SMTP (EHLO)" -check_port "465" 'printf "QUIT\r\n" | openssl s_client -connect 127.0.0.1:465 -quiet -ign_eof' "SMTPS (TLS + EHLO)" -check_port "587" 'printf "EHLO x\r\nSTARTTLS\r\nQUIT\r\n" | openssl s_client -starttls smtp -connect 127.0.0.1:587 -quiet -ign_eof' "Submission (STARTTLS)" +# SMTP +check_port "25" 'printf "EHLO x\r\nQUIT\r\n" | nc -w 3 127.0.0.1 25' \ + "SMTP (EHLO)" +check_port "465" 'printf "QUIT\r\n" | openssl s_client -connect 127.0.0.1:465 -quiet -ign_eof' \ + "SMTPS (TLS + EHLO)" +check_port "587" 'printf "EHLO x\r\nSTARTTLS\r\nQUIT\r\n" | openssl s_client -starttls smtp -connect 127.0.0.1:587 -quiet -ign_eof' \ + "Submission (STARTTLS)" # POP/IMAP -check_port "110" 'printf "QUIT\r\n" | nc -w 3 127.0.0.1 110' "POP3 (QUIT)" -check_port "995" 'printf "QUIT\r\n" | openssl s_client -connect 127.0.0.1:995 -quiet -ign_eof' "POP3S (TLS + QUIT)" -check_port "143" 'printf ". CAPABILITY\r\n. LOGOUT\r\n" | nc -w 3 127.0.0.1 143' "IMAP (CAPABILITY/LOGOUT)" -check_port "993" 'printf ". CAPABILITY\r\n. LOGOUT\r\n" | openssl s_client -connect 127.0.0.1:993 -quiet -ign_eof' "IMAPS (TLS + CAPABILITY/LOGOUT)" +check_port "110" 'printf "QUIT\r\n" | nc -w 3 127.0.0.1 110' \ + "POP3 (QUIT)" +check_port "995" 'printf "QUIT\r\n" | openssl s_client -connect 127.0.0.1:995 -quiet -ign_eof' \ + "POP3S (TLS + QUIT)" +check_port "143" 'printf ". CAPABILITY\r\n. LOGOUT\r\n" | nc -w 3 127.0.0.1 143' \ + "IMAP (CAPABILITY/LOGOUT)" +check_port "993" 'printf ". CAPABILITY\r\n. LOGOUT\r\n" | openssl s_client -connect 127.0.0.1:993 -quiet -ign_eof' \ + "IMAPS (TLS + CAPABILITY/LOGOUT)" -echo \ No newline at end of file +echo + +# Nützliche Hinweise am Ende +if [[ "$UI_LE" != "LE" || "$WEBMAIL_LE" != "LE" ]]; then + echo -e " ${YELLOW}Hinweis:${NC} UI/Webmail verwenden noch kein Let's-Encrypt-Zertifikat." + echo -e " Prüfe Symlinks unter /etc/ssl/{ui,webmail} und den LE-Hook (21/75-Skripte)." + echo +fi + +if [[ "$PROXY_MODE" = "1" ]]; then + echo -e " ${GREY}Proxy-Hinweis:${NC} App erwartet TLS am Proxy (keine https-Redirects im Backend)." + echo +fi \ No newline at end of file