From 8a717090484af33d2ece92e3c9f1e98836a91f37 Mon Sep 17 00:00:00 2001 From: Oier Bravo Urtasun Date: Thu, 11 Jun 2026 02:26:42 +0200 Subject: [PATCH] =?UTF-8?q?docs(deploy):=20caddy=20conf=20bind=20mounts=20?= =?UTF-8?q?are=20inode-pinned=20=E2=80=94=20recreate,=20not=20reload?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .claude/skills/deploy/SKILL.md | 8 ++++++++ plan/14-deploy.md | 13 ++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/.claude/skills/deploy/SKILL.md b/.claude/skills/deploy/SKILL.md index f172c01..7276e70 100644 --- a/.claude/skills/deploy/SKILL.md +++ b/.claude/skills/deploy/SKILL.md @@ -73,6 +73,14 @@ invoking this skill is the authorization to proceed, but: - Never `git reset --hard` or discard changes on `cochi` without telling the user first — there may be host-local edits. +- **Caddy conf changes need a recreate, not reload/restart.** If the deploy + touched any `caddy/conf.d/*.caddy` or the Caddyfile and you did a *rolling* + `update-all.sh` (not `--hard`), the change WON'T apply: those are single-file + bind mounts pinned to the host inode, and `git pull` gives the file a new inode. + `restart`/`caddy reload` reuse the stale inode. Run + `docker compose up -d --force-recreate caddy`, then verify with + `docker compose exec caddy cat /etc/caddy/conf.d/`. The `--hard` path + (full `down`/`up`) already recreates, so it's unaffected. - Volumes (`mc_data`, `drasl_state`, `kuma_data`) persist across `down`; the world and monitors are safe. Do NOT pass `-v`/`--volumes` to `down`. - If a step fails, STOP and surface the exact error + the failing command. Do not diff --git a/plan/14-deploy.md b/plan/14-deploy.md index cb9d9dd..6a5314e 100644 --- a/plan/14-deploy.md +++ b/plan/14-deploy.md @@ -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/`. - `./update-all.sh --hard` — `docker compose down --remove-orphans && up -d --build`. Full restart (Minecraft world downtime); picks up everything.