feat(caddy): single owner via CADDY_MANAGER env flag

One Caddy serves the whole container and POST /load replaces the entire
config, so two instances pushing would clobber each other. Now only the
instance with CADDY_MANAGER=true (production) pushes, seeds routes from the
Caddyfile, and accepts route mutations (others get 403). /api/auth/config
exposes caddyManaged so the non-owner Settings UI shows the Caddy section
read-only. The installer sets the flag on the production .env only.
This commit is contained in:
Brückner
2026-06-09 12:47:20 +02:00
parent bc677ff805
commit e0332b05ad
4 changed files with 53 additions and 14 deletions

View File

@ -478,7 +478,15 @@ importCaddyfileRoutes(): reads /etc/caddy/Caddyfile on first Caddy enable
pushCaddyConfig(): POST <caddy_admin_url>/load (Content-Type: text/caddyfile)
called on startup, after settings save, after route add/delete
(failures logged as warnings, non-fatal; skipped if caddy_enabled !== 'true')
(failures logged as warnings, non-fatal; skipped if caddy_enabled !== 'true'
or if this instance is not the Caddy manager)
Ownership — one Caddy serves the whole container (admin API on :2019); POST /load
replaces the ENTIRE config. Only the instance with env CADDY_MANAGER=true (production)
pushes, seeds routes, and accepts route edits (POST/PUT/DELETE → 403 otherwise). The
other instance shows the Caddy section read-only (/api/auth/config → caddyManaged:false)
and never pushes — otherwise its own (partial) config would clobber the owner's. The
owner's caddy table therefore holds ALL routes (both GhostGrid domains + every service).
```
---
@ -660,6 +668,7 @@ Backup : ghostgrid.db + ghostgrid.db-wal + ghostgrid.db-shm
| `APP_URL` | `http://localhost:<PORT>` | Base URL for deriving the Azure redirect URI |
| `PORT` | `3000` | HTTP listen port |
| `NODE_ENV` | — | `production` switches to static `dist/` serving |
| `CADDY_MANAGER` | unset | `true` makes this instance the sole Caddy owner (push/seed/edit). Set on production only — one Caddy per container |
| `CHECKMK_API_URL` / `CHECKMK_API_USER` / `CHECKMK_API_SECRET` | — | Fallbacks if not set in the Settings UI |
---