docs(deploy): caddy conf bind mounts are inode-pinned — recreate, not reload

Document the gotcha hit fixing distribution CORS: caddy/conf.d/*.caddy are
single-file bind mounts pinned to the host inode at container creation. git pull
rewrites tracked files via atomic rename (new inode), so a running caddy keeps
the old config; `restart`/`caddy reload` reuse the stale inode. Apply conf
changes with `docker compose up -d --force-recreate caddy` (or the --hard
down/up). Added to plan/14-deploy.md and the deploy skill guardrails.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-11 02:26:42 +02:00
parent db63aa7d10
commit 8a71709048
2 changed files with 20 additions and 1 deletions

View File

@@ -24,7 +24,18 @@ Two modes:
ONLY the services whose mounted inputs changed since a pre-run snapshot
(drasl/nmsr on a config re-render, minecraft on a mod change). Minimal
downtime. Does **not** detect caddy static-conf (`caddy/conf.d/*.caddy`)
changes — use `--hard` for those.
changes — apply those with a **recreate**, not a reload/restart (see gotcha
below): `docker compose up -d --force-recreate caddy` (no world downtime), or
`--hard` for a full redeploy.
> **Caddy conf bind mounts are inode-pinned — recreate, don't reload.** Each
> `caddy/conf.d/*.caddy` is a *single-file* bind mount, which Docker pins to
> the host file's inode at container creation. `git pull` rewrites a tracked
> file via atomic rename = a NEW inode, so the running container keeps the OLD
> config. `docker compose restart caddy` and `caddy reload` reuse the same
> container → same stale inode → no effect. Only re-creating the container
> (`up -d --force-recreate caddy`, or the `--hard` down/up) re-resolves the
> mount. Verify: `docker compose exec caddy cat /etc/caddy/conf.d/<file>`.
- `./update-all.sh --hard` — `docker compose down --remove-orphans && up -d
--build`. Full restart (Minecraft world downtime); picks up everything.