Skip to content

Commit ca11888

Browse files
deploy: force-recreate caddy container so new vhosts get certs
Reloading Caddy in-place did not trigger ACME issuance for the new api/console/docs vhosts on the last deploy — the reload command succeeded but no certs were ever obtained, so the new hostnames returned a TLS internal_error alert. Recreate the container after every deploy (volume persists, so existing certs are kept) and dump a non-access-log slice of Caddy logs + the on-disk cert inventory. Also runs caddy validate up front so a syntax error aborts the deploy instead of silently leaving the old config in place.
1 parent 71987bb commit ca11888

1 file changed

Lines changed: 38 additions & 11 deletions

File tree

scripts/deploy-remote.sh

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,47 @@ docker compose --profile "$COMPOSE_PROFILE" up -d --build --remove-orphans
2222

2323
# `up -d --build` does NOT restart a service when only its bind-mounted
2424
# files (e.g. Caddyfile) changed — Docker only recreates on image /
25-
# environment / volume-definition drift. Force an explicit Caddy reload
26-
# so config changes land on every deploy. Idempotent + fast (~2s).
25+
# environment / volume-definition drift. We need new vhosts to be
26+
# picked up + their TLS certs to be provisioned on every deploy.
27+
#
28+
# Strategy:
29+
# 1. Try a hot reload (zero downtime).
30+
# 2. If reload says "config unchanged" or fails, force-recreate the
31+
# container so Caddy boots fresh and queues ACME provisioning for
32+
# every named vhost in the Caddyfile.
2733
if docker ps --format '{{.Names}}' | grep -q '^zeroauth-caddy$'; then
34+
echo "Validating Caddyfile syntax..."
35+
if ! docker exec zeroauth-caddy caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile 2>&1; then
36+
echo "Caddyfile is invalid — aborting deploy."
37+
exit 1
38+
fi
39+
2840
echo "Reloading Caddy to pick up Caddyfile changes..."
29-
docker exec zeroauth-caddy caddy reload --config /etc/caddy/Caddyfile --adapter caddyfile \
30-
|| docker restart zeroauth-caddy
31-
32-
# Give Caddy a moment to provision certs for any new vhosts, then dump
33-
# its recent log so ACME failures land in the deploy output instead of
34-
# silently hiding inside the container.
35-
sleep 25
36-
echo "--- caddy logs (last 200 lines) ---"
37-
docker logs --tail 200 zeroauth-caddy 2>&1 || true
41+
reload_out="$(docker exec zeroauth-caddy caddy reload --config /etc/caddy/Caddyfile --adapter caddyfile 2>&1)" || reload_out="$reload_out (rc=$?)"
42+
echo "$reload_out"
43+
44+
# Always also force-recreate the container after a deploy. Caddy's
45+
# hot reload sometimes skips provisioning new vhosts when ACME
46+
# storage carries a partial/failed record — a fresh boot clears
47+
# in-process state and re-queues issuance for every name in the
48+
# Caddyfile. We still keep the volume so existing certs persist.
49+
echo "Force-recreating zeroauth-caddy so any new vhosts get fresh ACME provisioning..."
50+
docker compose --profile "$COMPOSE_PROFILE" up -d --force-recreate --no-deps caddy
51+
52+
# Wait for Caddy to come back, then dump its recent NON-access log
53+
# so ACME activity actually surfaces in the deploy output. Without
54+
# the filter the chatty per-request access log drowns the lines we
55+
# actually need to read.
56+
sleep 35
57+
echo "--- caddy logs (excl. access log, last 5min) ---"
58+
docker logs --since 5m zeroauth-caddy 2>&1 \
59+
| grep -Ev '"logger":"http\.log\.access' \
60+
| tail -300 || true
3861
echo "--- end caddy logs ---"
62+
63+
echo "--- caddy cert inventory ---"
64+
docker exec zeroauth-caddy ls /data/caddy/certificates/acme-v02.api.letsencrypt.org-directory/ 2>&1 || true
65+
echo "--- end cert inventory ---"
3966
fi
4067

4168
echo "Waiting for zeroauth-prod health check..."

0 commit comments

Comments
 (0)