From 9e3a081f43e506f8f7facd1b552c3240704f56a4 Mon Sep 17 00:00:00 2001 From: MCCarmo Date: Wed, 28 Oct 2026 19:57:16 +0000 Subject: [PATCH] Mount Caddy's folder so a deploy's Caddyfile reaches it The deploy replaces the Caddyfile with a new file, and Caddy saw it through a single-file bind mount, which stays on the old file: every reload read the first Caddyfile, so the Permissions-Policy from #36 never reached the site (ZAP's first run failed on it). Caddy now mounts deploy/caddy/, which shows the new file, and the monitoring job validates the Caddyfile. --- .github/workflows/ci.yml | 10 ++++++---- deploy/README.md | 2 +- deploy/{ => caddy}/Caddyfile | 0 deploy/compose.yaml | 5 ++++- deploy/deploy.sh | 5 +++-- 5 files changed, 14 insertions(+), 8 deletions(-) rename deploy/{ => caddy}/Caddyfile (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5a37c8f..a951826 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -98,9 +98,9 @@ jobs: docker run --rm -v "$PWD":/work -w /work hashicorp/terraform:1.16.5 validate monitoring: - # The monitoring configuration (deploy/): Prometheus' config and alert rules (and their - # unit tests), Alertmanager's config and the Grafana dashboard, checked by the tools - # that read them. + # The server's configuration (deploy/): Prometheus' config and alert rules (and their + # unit tests), Alertmanager's config, the Grafana dashboard and the Caddyfile, checked + # by the tools that read them. runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 @@ -115,6 +115,8 @@ jobs: docker run --rm -v "$PWD/prometheus":/etc/prometheus --entrypoint promtool "$prometheus" test rules /etc/prometheus/alerts.test.yml docker run --rm -v "$PWD/alertmanager":/etc/alertmanager --entrypoint amtool "$alertmanager" check-config /etc/alertmanager/alertmanager.yml python3 -m json.tool grafana/dashboards/extpulse.json > /dev/null + caddy=$(grep -o 'image: caddy:[^ ]*' compose.yaml | cut -d' ' -f2) + docker run --rm -e EXTPULSE_DOMAIN=extpulse.example.com -v "$PWD/caddy":/etc/caddy:ro "$caddy" caddy validate --config /etc/caddy/Caddyfile image: # The production image. Built on an Arm runner, natively, because the server @@ -243,7 +245,7 @@ jobs: - name: Deploy run: | # The files and folders of deploy/, as one archive over the same SSH connection. - tar -C deploy -czf - compose.yaml Caddyfile backup.sh offsite.sh deploy.sh prometheus alertmanager grafana \ + tar -C deploy -czf - compose.yaml caddy backup.sh offsite.sh deploy.sh prometheus alertmanager grafana \ | ssh -o StrictHostKeyChecking=yes "deploy@${DEPLOY_HOST}" tar -xzf - -C /opt/extpulse ssh -o StrictHostKeyChecking=yes "deploy@${DEPLOY_HOST}" bash /opt/extpulse/deploy.sh "sha-${GITHUB_SHA::7}" diff --git a/deploy/README.md b/deploy/README.md index bcdee34..8a37d05 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -6,7 +6,7 @@ this way: [ADR 0014](../docs/decisions/0014-deploy-and-operations.md). | File | What it does | | --- | --- | | `compose.yaml` | The app, PostgreSQL, Caddy (HTTPS) and the daily backup | -| `Caddyfile` | HTTPS for the domain, security headers, proxy to the app | +| `caddy/Caddyfile` | HTTPS for the domain, security headers, proxy to the app | | `deploy.sh` | Starts one image tag, waits for it to be healthy, rolls back if not | | `backup.sh` | `pg_dump` every day at 03:00 UTC, keeping 14 days | | `offsite.sh` | Copies the dumps to Object Storage, off the server, at 03:30 UTC | diff --git a/deploy/Caddyfile b/deploy/caddy/Caddyfile similarity index 100% rename from deploy/Caddyfile rename to deploy/caddy/Caddyfile diff --git a/deploy/compose.yaml b/deploy/compose.yaml index a2b9b42..0b81221 100644 --- a/deploy/compose.yaml +++ b/deploy/compose.yaml @@ -92,7 +92,10 @@ services: environment: EXTPULSE_DOMAIN: ${EXTPULSE_DOMAIN:-extpulse.mccprogrammer.com} volumes: - - ./Caddyfile:/etc/caddy/Caddyfile:ro + # The folder, not the file: a deploy replaces the Caddyfile with a new file, and a + # container keeps seeing the old one through a single-file mount, so the reload + # would read the old configuration. + - ./caddy:/etc/caddy:ro - caddy-data:/data - caddy-config:/config mem_limit: 128m diff --git a/deploy/deploy.sh b/deploy/deploy.sh index 7aa731f..4739d1f 100755 --- a/deploy/deploy.sh +++ b/deploy/deploy.sh @@ -36,8 +36,9 @@ up() { docker compose pull --quiet app docker compose up -d --remove-orphans # Compose recreates a service when its definition changes, not when a mounted file - # does: pick up the Caddyfile (a reload, without dropping connections), backup.sh, - # offsite.sh and the monitoring configuration. + # does: pick up the Caddyfile (a reload, without dropping connections; Caddy mounts its + # folder, which shows the new file), backup.sh, offsite.sh and the monitoring + # configuration (restarts, which mount the new files). docker compose exec -T caddy caddy reload --config /etc/caddy/Caddyfile >/dev/null docker compose restart backup offsite prometheus alertmanager grafana >/dev/null }