From 0f951281d57684608eb74fb9be0c420ca518922e Mon Sep 17 00:00:00 2001 From: Timothy Kim Date: Mon, 8 Jun 2026 11:35:37 -0400 Subject: [PATCH] self-heal standalone cert renewal configs on provision --- ARCHITECTURE.md | 7 ++++++- scripts/configure.sh | 24 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 0c0cd19..c97b923 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -105,7 +105,12 @@ cert as SANs. 1. Run `app.sh cert ` (uses `certbot --webroot`, zero downtime) 2. Deploy nginx config — `deploy.sh` verifies certs exist, fails if missing -**Renewal:** certbot timer/cron runs daily, deploy hook reloads nginx. +**Renewal:** certbot timer/cron runs daily, deploy hook reloads nginx. All certs +must use the `webroot` authenticator so nginx can keep port 80; certs issued by +the old `--standalone` flow (removed in `de1d60b`) can never renew because nginx +holds port 80. `configure.sh` self-heals this on every `provision`: it scans +`/etc/letsencrypt/renewal/*.conf` and reissues any `standalone` cert via the +`cert-` webroot path (best-effort; warns and exits non-zero on failure). ## `.env.keys` mechanism diff --git a/scripts/configure.sh b/scripts/configure.sh index a068afe..7a2b714 100755 --- a/scripts/configure.sh +++ b/scripts/configure.sh @@ -37,6 +37,25 @@ fi echo "==> Deploying services..." # Deploy nginx first (creates the shared network) bash "$REPO_DIR/scripts/deploy.sh" deploy-nginx + +# Self-heal renewal config drift: certs issued by the old --standalone flow +# (removed in de1d60b) can never renew because nginx now holds port 80. Reissue +# any such cert via the canonical webroot path. nginx must be up (above) to +# serve the ACME challenge. Best-effort: a single failure warns but does not +# block the rest of the provision. +echo "==> Healing standalone cert renewal configs..." +heal_failed=false +for conf in /etc/letsencrypt/renewal/*.conf; do + [ -e "$conf" ] || continue + grep -q '^authenticator = standalone' "$conf" || continue + cert_name=$(basename "$conf" .conf) + echo " $cert_name uses standalone; reissuing via webroot..." + if ! bash "$REPO_DIR/scripts/deploy.sh" "cert-$cert_name"; then + echo " WARNING: failed to reissue $cert_name; leaving standalone config in place" + heal_failed=true + fi +done + # Deploy all other apps for app in "$REPO_DIR"/docker/*/; do app_name=$(basename "$app") @@ -46,3 +65,8 @@ for app in "$REPO_DIR"/docker/*/; do done echo "==> Done." + +if [ "$heal_failed" = true ]; then + echo "ERROR: one or more standalone certs could not be reissued (see warnings above)." + exit 1 +fi