#!/usr/bin/env bash set -euo pipefail if [ -f /etc/mailwolt/installer.env ]; then set -a . /etc/mailwolt/installer.env set +a fi # ── Styling ──────────────────────────────────────────────────────────────── GREEN="$(printf '\033[1;32m')"; YELLOW="$(printf '\033[1;33m')" RED="$(printf '\033[1;31m')"; CYAN="$(printf '\033[1;36m')" GREY="$(printf '\033[0;90m')"; NC="$(printf '\033[0m')" BAR="──────────────────────────────────────────────────────────────────────────────" log(){ echo -e "${GREEN}[+]${NC} $*"; } warn(){ echo -e "${YELLOW}[!]${NC} $*"; } err(){ echo -e "${RED}[x]${NC} $*"; } die(){ err "$*"; exit 1; } require_root(){ [[ "$(id -u)" -eq 0 ]] || die "Bitte als root ausführen."; } # --- Defaults, nur wenn noch nicht gesetzt --------------------------------- : "${APP_USER:=mailwolt}" : "${APP_GROUP:=www-data}" : "${APP_DIR:=/var/www/${APP_USER}}" : "${APP_NAME:=MailWolt}" : "${BASE_DOMAIN:=example.com}" : "${UI_SUB:=ui}" : "${WEBMAIL_SUB:=webmail}" : "${MTA_SUB:=mx}" # DB / Redis (werden später durch .env überschrieben) : "${DB_NAME:=${APP_USER}}" : "${DB_USER:=${APP_USER}}" : "${DB_PASS:=}" : "${REDIS_PASS:=}" # Stabile Zert-Pfade (UI/WEBMAIL/MX → symlinked via 20-ssl.sh) : "${MAIL_SSL_DIR:=/etc/ssl/mail}" : "${UI_SSL_DIR:=/etc/ssl/ui}" : "${WEBMAIL_SSL_DIR:=/etc/ssl/webmail}" : "${UI_CERT:=${UI_SSL_DIR}/fullchain.pem}" : "${UI_KEY:=${UI_SSL_DIR}/privkey.pem}" # Optional: E-Mail für LE : "${LE_EMAIL:=admin@${BASE_DOMAIN}}" load_env_file(){ local f="$1" [[ -f "$f" ]] || return 0 while IFS='=' read -r k v; do [[ "$k" =~ ^[A-Z0-9_]+$ ]] || continue export "$k=$v" done < <(grep -E '^[A-Z0-9_]+=' "$f") } header(){ echo -e "${CYAN}${BAR}${NC} ${CYAN} :::: :::: ::: ::::::::::: ::: ::: ::: :::::::: ::: ::::::::::: ${CYAN} +:+:+: :+:+:+ :+: :+: :+: :+: :+: :+: :+: :+: :+: :+: ${CYAN} +:+ +:+:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ ${CYAN} +#+ +:+ +#+ +#++:++#++: +#+ +#+ +#+ +:+ +#+ +#+ +:+ +#+ +#+ ${CYAN} +#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+#+ +#+ +#+ +#+ +#+ +#+ ${CYAN} #+# #+# #+# #+# #+# #+# #+#+# #+#+# #+# #+# #+# #+# ${CYAN} ### ### ### ### ########### ########## ### ### ######## ########## ### ${CYAN} ${CYAN}${BAR}${NC}\n"; } #header(){ echo -e "${CYAN}${BAR}${NC} #${CYAN} 888b d888 d8b 888 888 888 888 888 #${CYAN} 8888b d8888 Y8P 888 888 o 888 888 888 #${CYAN} 88888b.d88888 888 888 d8b 888 888 888 #${CYAN} 888Y88888P888 8888b. 888 888 888 d888b 888 .d88b. 888 888888 #${CYAN} 888 Y888P 888 '88b 888 888 888d88888b888 d88''88b 888 888 #${CYAN} 888 Y8P 888 .d888888 888 888 88888P Y88888 888 888 888 888 #${CYAN} 888 ' 888 888 888 888 888 8888P Y8888 Y88..88P 888 Y88b. #${CYAN} 888 888 'Y888888 888 888 888P Y888 'Y88P' 888 'Y888 #${CYAN}${BAR}${NC}\n"; } detect_ip(){ local ip ip="$(ip -4 route get 1.1.1.1 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="src"){print $(i+1); exit}}')" || true [[ -n "${ip:-}" ]] || ip="$(hostname -I 2>/dev/null | awk '{print $1}')" [[ -n "${ip:-}" ]] || die "Konnte Server-IP nicht ermitteln." echo "$ip" } detect_ipv4() { local ext="" if command -v curl >/dev/null 2>&1; then ext="$(curl -fsS --max-time 2 https://ifconfig.me 2>/dev/null || true)" [[ "$ext" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] || ext="" fi echo "$ext" } detect_ipv6(){ local ip6 ip6="$(ip -6 addr show scope global 2>/dev/null | awk '/inet6/{print $2}' | cut -d/ -f1 | head -n1)" || true [[ -n "${ip6:-}" ]] || ip6="$(hostname -I 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i ~ /:/){print $i; exit}}')" || true echo "${ip6:-}" } detect_timezone(){ local tz if command -v timedatectl >/dev/null 2>&1; then tz="$(timedatectl show -p Timezone --value 2>/dev/null | tr -d '[:space:]')" || true [[ -n "${tz:-}" && "$tz" == */* ]] && { echo "$tz"; return; } fi [[ -r /etc/timezone ]] && { tz="$(sed -n '1p' /etc/timezone | tr -d '[:space:]')" || true; [[ "$tz" == */* ]] && { echo "$tz"; return; }; } if [[ -L /etc/localtime ]]; then tz="$(readlink -f /etc/localtime 2>/dev/null || true)"; tz="${tz#/usr/share/zoneinfo/}" [[ "$tz" == */* ]] && { echo "$tz"; return; } fi if command -v curl >/dev/null 2>&1; then tz="$(curl -fsSL --max-time 3 https://ipapi.co/timezone 2>/dev/null || true)"; [[ "$tz" == */* ]] && { echo "$tz"; return; } fi echo "UTC" } guess_locale_from_tz(){ case "${1:-UTC}" in Europe/Berlin|Europe/Vienna|Europe/Zurich|Europe/Luxembourg|Europe/Brussels|Europe/Amsterdam) echo "de";; *) echo "en";; esac; } resolve_ok(){ local host="$1"; getent ahosts "$host" | awk '{print $1}' | sort -u | grep -q -F "${SERVER_PUBLIC_IPV4:-}" ; } join_host(){ local sub="$1" base="$2"; [[ -z "$sub" ]] && echo "$base" || echo "$sub.$base"; } upsert_env(){ # upsert in $ENV_FILE local k="$1" v="$2" ek ev ek="$(printf '%s' "$k" | sed -e 's/[.[\*^$(){}+?|/]/\\&/g')" ev="$(printf '%s' "$v" | sed -e 's/[&/]/\\&/g')" if grep -qE "^[#[:space:]]*${ek}=" "$ENV_FILE" 2>/dev/null; then sed -Ei "s|^[#[:space:]]*${ek}=.*|${k}=${ev}|g" "$ENV_FILE" else printf '%s=%s\n' "$k" "$v" >> "$ENV_FILE" fi }