Deployment
Docker-Compose layouts for dev and prod, and the env vars that matter in production.
Two compose files
docker-compose.yml targets local dev — HTTP only, hot-reload bind mounts for admin and api. docker-compose.prod.yml builds the same services as multi-stage images, uses the hardened Caddyfile.prod and expects PUBLIC_URL on HTTPS.
docker compose up -d
open http://localhost:8080docker compose -f docker-compose.prod.yml build
PUBLIC_URL=https://cms.example.com \
docker compose -f docker-compose.prod.yml up -dRequired env vars
These are checked at API boot — the process crashes loudly instead of running with bad defaults.
BETTER_AUTH_SECRETRequired32+ random bytes. Signs session cookies and HMAC-hashes access tokens at rest. Rotating invalidates all tokens.
openssl rand -hex 32PUBLIC_URLRequiredExternal HTTPS URL of the proxy. Used for webhook payloads, asset URLs, and OAuth redirect URIs.
https://cms.example.comDATABASE_URLRequiredPostgres connection string.
postgres://cms:cms@postgres:5432/cmsS3_ENDPOINTRequiredS3-compatible endpoint the storage service talks to.
http://minio:9000S3_ACCESS_KEY / S3_SECRET_KEYRequiredCredentials for the asset bucket — only the storage service reads these.
REDIS_URLOptionalIf empty, the cache client is a silent no-op. If set, CDN responses and link maps are cached with short TTLs.
redis://redis:6379OIDC_ISSUER_URLOptionalPresence toggles OIDC-only mode: disables email+password login and requires OIDC_CLIENT_ID + OIDC_CLIENT_SECRET.
https://auth.example.com/realms/mainOUTBOUND_ALLOW_LOOPBACKOptionalDefault: 0SSRF guard escape hatch. Only set to 1 in tests that fetch against a local receiver — never gate by NODE_ENV.