From 73000d42d37766be0da8c9b526188813bba7107a Mon Sep 17 00:00:00 2001 From: Nate Barlow Date: Fri, 2 Oct 2026 01:30:22 -0600 Subject: [PATCH 1/3] Guard the shared proxy against Do It List's server block A broken or missing Do It List block could stop cz-nginx from starting. The guard loads it only when nginx -t passes, and keeps the last good one when a change fails. Already live on the server. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01F2FtvCF7avZZieGpKiLKYX --- compose.alpha.yaml | 6 ++-- docker/production/nginx/doitlist-guard.sh | 38 +++++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) create mode 100755 docker/production/nginx/doitlist-guard.sh diff --git a/compose.alpha.yaml b/compose.alpha.yaml index 9dc0e53e..a5f09e25 100644 --- a/compose.alpha.yaml +++ b/compose.alpha.yaml @@ -25,8 +25,10 @@ services: - /etc/letsencrypt:/etc/letsencrypt:ro - ./certbot-webroot:/var/www/certbot:ro # Do It List shares this box and this proxy; its server block lives - # in its own folder, and its containers join doitlist_edge. - - /opt/doitlist/proxy/doitlist.conf:/etc/nginx/conf.d/doitlist.conf:ro + # in its own folder, and its containers join doitlist_edge. The guard + # loads that block only when nginx accepts it. + - /opt/doitlist/proxy:/etc/nginx/doitlist:ro + - ./docker/production/nginx/doitlist-guard.sh:/docker-entrypoint.d/90-doitlist-guard.sh:ro networks: - default - doitlist_edge diff --git a/docker/production/nginx/doitlist-guard.sh b/docker/production/nginx/doitlist-guard.sh new file mode 100755 index 00000000..222676f8 --- /dev/null +++ b/docker/production/nginx/doitlist-guard.sh @@ -0,0 +1,38 @@ +#!/bin/sh +# Do It List shares this proxy. Its server block may only join the config +# when nginx still accepts it, so a broken or missing Do It List file can +# never keep CryptoZing from starting or reloading. +# +# Runs at container start (from /docker-entrypoint.d) and on every Do It List +# routing change: docker exec cz-nginx /docker-entrypoint.d/90-doitlist-guard.sh --strict +# At start it always exits 0, since a failing entrypoint script stops nginx; +# --strict exits 1 when it turned the new block away. +set -u +status=0 +[ "${1:-}" = "--strict" ] && status=1 + +src=/etc/nginx/doitlist/doitlist.conf +live=/etc/nginx/conf.d/doitlist.conf +prev=/tmp/doitlist.conf.prev + +rm -f "$prev" +[ -f "$live" ] && cp "$live" "$prev" + +if [ -f "$src" ]; then + cp "$src" "$live" +else + rm -f "$live" +fi + +if nginx -t -q 2>/dev/null; then + exit 0 +fi + +echo "doitlist-guard: Do It List's server block failed nginx -t; keeping the last good one" >&2 +if [ -f "$prev" ]; then + cp "$prev" "$live" + nginx -t -q 2>/dev/null && exit "$status" +fi +rm -f "$live" +echo "doitlist-guard: serving without Do It List" >&2 +exit "$status" From 8082d9d620f9c67f186b283abfd9b516c7c61ac1 Mon Sep 17 00:00:00 2001 From: Nate Barlow Date: Fri, 2 Oct 2026 01:41:08 -0600 Subject: [PATCH 2/3] Log why the proxy guard turned Do It List's block away Under --strict the guard also writes to the container log, so a rejected routing change is visible in docker logs, not only the caller's console. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01MchCV6T5B393x87E8xonCX --- docker/production/nginx/doitlist-guard.sh | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/docker/production/nginx/doitlist-guard.sh b/docker/production/nginx/doitlist-guard.sh index 222676f8..2d6e8a31 100755 --- a/docker/production/nginx/doitlist-guard.sh +++ b/docker/production/nginx/doitlist-guard.sh @@ -15,6 +15,14 @@ src=/etc/nginx/doitlist/doitlist.conf live=/etc/nginx/conf.d/doitlist.conf prev=/tmp/doitlist.conf.prev +# At start, stderr is already the container log. Under docker exec it is only +# the caller's console, so --strict also writes to the container log. +log() { + echo "doitlist-guard: $*" >&2 + [ "$status" = 1 ] && echo "doitlist-guard: $*" > /proc/1/fd/2 2>/dev/null + return 0 +} + rm -f "$prev" [ -f "$live" ] && cp "$live" "$prev" @@ -24,15 +32,16 @@ else rm -f "$live" fi -if nginx -t -q 2>/dev/null; then +if err=$(nginx -t -q 2>&1); then exit 0 fi -echo "doitlist-guard: Do It List's server block failed nginx -t; keeping the last good one" >&2 +log "Do It List's server block failed nginx -t; keeping the last good one" +log "$err" if [ -f "$prev" ]; then cp "$prev" "$live" nginx -t -q 2>/dev/null && exit "$status" fi rm -f "$live" -echo "doitlist-guard: serving without Do It List" >&2 +log "serving without Do It List" exit "$status" From 609e4764f0282f2aab2e9c231274e71dddc526ca Mon Sep 17 00:00:00 2001 From: Nate Barlow Date: Fri, 2 Oct 2026 01:45:17 -0600 Subject: [PATCH 3/3] Create the shared doitlist_edge network before deploying Neither stack owns it; deploy.sh makes sure it exists so a missing network can't stop cz-nginx from starting. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01MchCV6T5B393x87E8xonCX --- scripts/deploy.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/deploy.sh b/scripts/deploy.sh index 4a72ecaa..52c9e849 100755 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -16,6 +16,12 @@ FILES=(-f compose.production.yaml) # Our deployment layers the site container in; self-hosters won't have it. [ -f compose.alpha.yaml ] && FILES+=(-f compose.alpha.yaml) +# Do It List shares our front nginx over doitlist_edge. Neither stack owns the +# network; make sure it exists so a missing one can't stop our proxy starting. +if [ -f compose.alpha.yaml ] && ! docker network inspect doitlist_edge > /dev/null 2>&1; then + docker network create doitlist_edge > /dev/null +fi + # Persist the tag so later compose invocations keep serving it. if grep -q '^CZ_TAG=' .env; then sed -i "s|^CZ_TAG=.*|CZ_TAG=${TAG}|" .env