#!/usr/bin/env bash set -Eeuo pipefail WM_DEPLOY_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" # shellcheck source=common.sh source "$WM_DEPLOY_DIR/scripts/common.sh" wm_load_env wm_assert_data_mount if [[ "$(id -u)" -ne 0 ]]; then wm_die "Dieses Skript muss als root ausgeführt werden." fi domain="${WATERMAPS_DOMAIN:-}" email="${WATERMAPS_ACME_EMAIL:-}" expected_ipv4="${1:-${WATERMAPS_EXPECTED_IPV4:-}}" [[ "$domain" =~ ^([A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)+[A-Za-z]{2,63}$ ]] || wm_die "Ungültiger WATERMAPS_DOMAIN: $domain" [[ "$email" == *@*.* && "$email" != "admin@example.com" ]] || wm_die "Bitte WATERMAPS_ACME_EMAIL in deploy/.env.production konfigurieren." [[ "$expected_ipv4" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] || wm_die "Erwartete Server-IPv4 fehlt. Als Argument übergeben oder WATERMAPS_EXPECTED_IPV4 setzen." wm_assert_route_data wm_wait_for_health watermaps 120 wm_wait_for_health nginx 60 wm_smoke_test_route mapfile -t resolved_ipv4s < <(dig +short A "$domain" | awk '/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/') [[ "${#resolved_ipv4s[@]}" -gt 0 ]] || wm_die "Für $domain ist noch kein A-Record auflösbar." for resolved_ipv4 in "${resolved_ipv4s[@]}"; do [[ "$resolved_ipv4" == "$expected_ipv4" ]] || wm_die "$domain zeigt zusätzlich/abweichend auf $resolved_ipv4 statt ausschließlich auf $expected_ipv4." done challenge_name="watermaps-preflight-$$" challenge_dir="$WATERMAPS_DATA_DIR/certbot/www/.well-known/acme-challenge" challenge_file="$challenge_dir/$challenge_name" install -d -m 0755 "$challenge_dir" printf 'watermaps-acme-preflight\n' >"$challenge_file" trap 'rm -f "$challenge_file"' EXIT curl --fail --silent --show-error \ --header "Host: $domain" \ "http://127.0.0.1/.well-known/acme-challenge/$challenge_name" \ | grep -qx 'watermaps-acme-preflight' || wm_die "Nginx stellt den ACME-Webroot nicht korrekt bereit." certbot_args=( certonly --webroot --webroot-path /var/www/certbot --domain "$domain" --email "$email" --agree-tos --non-interactive --keep-until-expiring ) cert_name="$domain" if [[ "${WATERMAPS_CERTBOT_STAGING:-false}" == "true" ]]; then cert_name="${domain}-staging" certbot_args+=(--staging) fi certbot_args+=(--cert-name "$cert_name") wm_log "Let's-Encrypt-Zertifikat wird angefordert." wm_compose --profile maintenance run --rm certbot "${certbot_args[@]}" certificate_path="$WATERMAPS_DATA_DIR/certbot/letsencrypt/live/$cert_name/fullchain.pem" private_key_path="$WATERMAPS_DATA_DIR/certbot/letsencrypt/live/$cert_name/privkey.pem" [[ -s "$certificate_path" && -s "$private_key_path" ]] || wm_die "Certbot war beendet, aber Zertifikat oder privater Schlüssel fehlen." candidate="$(mktemp "$WATERMAPS_RUNTIME_DIR/nginx/conf.d/.https.XXXXXX")" trap 'rm -f "$challenge_file" "$candidate"' EXIT sed \ -e "s/__WATERMAPS_DOMAIN__/$domain/g" \ -e "s/__WATERMAPS_CERT_NAME__/$cert_name/g" \ "$WM_DEPLOY_DIR/nginx/https.conf.template" \ >"$candidate" wm_compose run --rm --no-deps \ --volume "$candidate:/etc/nginx/conf.d/default.conf:ro" \ nginx nginx -t active_config="$WATERMAPS_RUNTIME_DIR/nginx/conf.d/default.conf" previous_config="$WATERMAPS_RUNTIME_DIR/nginx/conf.d/.default.conf.previous" cp --preserve=mode,timestamps "$active_config" "$previous_config" install -m 0644 "$candidate" "$active_config" if ! wm_compose exec --no-TTY nginx nginx -t; then install -m 0644 "$previous_config" "$active_config" wm_compose exec --no-TTY nginx nginx -s reload || true wm_die "HTTPS-Konfiguration war ungültig; Bootstrap-Konfiguration wurde wiederhergestellt." fi wm_compose exec --no-TTY nginx nginx -s reload https_curl_args=(--fail --silent --show-error) if [[ "${WATERMAPS_CERTBOT_STAGING:-false}" == "true" ]]; then https_curl_args+=(--insecure) fi if ! curl "${https_curl_args[@]}" \ --resolve "$domain:443:$expected_ipv4" \ "https://$domain/health" \ >/dev/null; then install -m 0644 "$previous_config" "$active_config" wm_compose exec --no-TTY nginx nginx -t wm_compose exec --no-TTY nginx nginx -s reload wm_die "HTTPS-Smoke-Test fehlgeschlagen; vorherige Nginx-Konfiguration wurde wiederhergestellt." fi wm_log "Livegang erfolgreich: https://$domain"