From 0f2273545a40582372201abc36744f0b75b3b8a7 Mon Sep 17 00:00:00 2001 From: William Gill Date: Wed, 16 Sep 2026 14:21:07 -0500 Subject: [PATCH] fix(simplex): repair the caddy-init YAML fold that broke every deploy The caddy-init service's `command:` used a YAML FOLDED scalar (`>`). Base indent is set by `sh -c '` at 6; the closing `}` and the heredoc's `EOF` were BOTH at 6, so YAML folded them into `} EOF`. The heredoc opened with `<` redirect ever ran -- no Caddyfile was ever written, on any deploy. The `if [ ! -f /etc/caddy/Caddyfile ]` guard never executed at all. caddy gates on `caddy-init: condition: service_completed_successfully`, and smp-server and xftp-server gate on caddy being healthy, so nothing in the stack started. `docker compose up -d` returned non-zero and `set -euo pipefail` aborted the script before the final report. The same failure hit every entry point: automations.sh, cloud-init, the OpenRC unit's start() (so every boot), and restore.sh -- which restores the same broken compose file backup.sh saved. Generate the Caddyfile from the deploy shell instead and drop caddy-init entirely, which removes the whole class of problem. Unlike the old first-run-only guard this also applies a changed DOMAIN, ACME_EMAIL or KEY_TYPE on a re-run rather than freezing them at the first deploy. The heredoc here is deliberately unquoted so ${DOMAIN}/${ACME_EMAIL}/ ${KEY_TYPE} expand; Caddy's {uri} has no `$` and survives. `cmp -s` stays inside an `if` condition -- as `cmp -s A B && CADDY_CHANGED=1` it would trip set -e whenever the files matched. Caddy is restarted only when the file actually changed AND compose did not already replace the container, since a bind-mounted file's contents are not part of the compose config hash and restarting seconds after a first start would interrupt initial ACME issuance. The Caddyfile is now real on-disk state rather than something a container regenerates, so it is added to backup.sh's targets and restore.sh's file list; without that, a restore would start caddy against an empty ./caddy_conf and the servers would never pass their health gate. Verified: first deploy writes it and reports no change; an identical re-run reports no change; a corrected DOMAIN rewrites it and flags the restart; {uri} survives and no .new file is left behind. Co-Authored-By: Claude Opus 5 --- deployments/simplex/backup.sh | 1 + deployments/simplex/deploy-simplex.sh | 98 +++++++++++++++------------ deployments/simplex/restore.sh | 1 + 3 files changed, 58 insertions(+), 42 deletions(-) diff --git a/deployments/simplex/backup.sh b/deployments/simplex/backup.sh index c5e8271..cf43301 100644 --- a/deployments/simplex/backup.sh +++ b/deployments/simplex/backup.sh @@ -98,6 +98,7 @@ TARGETS=( # Current environment and docker-compose setup "$SIMPLEX_DIR/.env" "$SIMPLEX_DIR/docker-compose.yml" + "$SIMPLEX_DIR/caddy_conf/Caddyfile" "$SIMPLEX_DIR/print-addresses.sh" # Tor configs diff --git a/deployments/simplex/deploy-simplex.sh b/deployments/simplex/deploy-simplex.sh index 66e5b47..38c0685 100644 --- a/deployments/simplex/deploy-simplex.sh +++ b/deployments/simplex/deploy-simplex.sh @@ -221,7 +221,7 @@ done # 5. Lay out /opt/simplex # ---------------------------------------------------------------------------- log "Writing compose stack to ${INSTALL_DIR}..." -mkdir -p "$INSTALL_DIR"/tor_conf +mkdir -p "$INSTALL_DIR"/tor_conf "$INSTALL_DIR"/caddy_conf cd "$INSTALL_DIR" cat > .env <`): the closing `}` and the heredoc's `EOF` were +# both at the scalar's base indent, so YAML folded them into `} EOF`, leaving the +# heredoc unterminated and the script a parse error. caddy-init exited 2 on every +# run, `service_completed_successfully` never fired, and nothing downstream of +# caddy ever started. Generating the file here removes the whole class of problem +# -- and, unlike the old `if [ ! -f ]` guard, applies a changed DOMAIN/ACME_EMAIL/ +# KEY_TYPE on a re-run instead of freezing them at the first deploy. +# +# The heredoc is deliberately UNQUOTED so ${DOMAIN}/${ACME_EMAIL}/${KEY_TYPE} +# expand here. Caddy's own {uri} has no `$` so it survives; any future Caddy +# {$ENV} placeholder must be escaped as \${...}. +CADDY_CHANGED=0 +cat > caddy_conf/Caddyfile.new < docker-compose.yml <<'YAML' name: simplex services: - caddy-init: - image: alpine:latest - command: > - sh -c ' - if [ ! -f /etc/caddy/Caddyfile ]; then - cat > /etc/caddy/Caddyfile <