Zwei Compose-Files

docker-compose.yml ist für lokales Dev — nur HTTP, Hot-Reload-Bind-Mounts für Admin und API. docker-compose.prod.yml baut dieselben Services als Multi-Stage-Images, nutzt das gehärtete Caddyfile.prod und erwartet PUBLIC_URL über HTTPS.

bash
docker compose up -d
open http://localhost:8080
Dev — Hot Reload, nur HTTP.
bash
docker compose -f docker-compose.prod.yml build
PUBLIC_URL=https://cms.example.com \
  docker compose -f docker-compose.prod.yml up -d
Prod — Images bauen, PUBLIC_URL auf eigene Domain.

Pflicht-Env-Vars

Werden beim API-Start geprüft — der Prozess crasht laut statt mit schlechten Defaults weiterzulaufen.

BETTER_AUTH_SECRETPflicht

32+ Zufalls-Bytes. Signiert Session-Cookies und hashiert Access-Tokens at-rest. Rotieren invalidiert alle Tokens.

openssl rand -hex 32
PUBLIC_URLPflicht

Externe HTTPS-URL des Proxys. Wird in Webhook-Payloads, Asset-URLs und OAuth-Redirect-URIs verwendet.

https://cms.example.com
DATABASE_URLPflicht

Postgres-Connection-String.

postgres://cms:cms@postgres:5432/cms
S3_ENDPOINTPflicht

S3-kompatibler Endpunkt, gegen den der Storage-Service spricht.

http://minio:9000
S3_ACCESS_KEY / S3_SECRET_KEYPflicht

Credentials für den Asset-Bucket — nur der Storage-Service kennt sie.

REDIS_URLOptional

Leer → Cache-Client ist stiller No-Op. Gesetzt → CDN-Responses und Link-Maps werden kurzlebig gecacht.

redis://redis:6379
OIDC_ISSUER_URLOptional

Wenn gesetzt: OIDC-only — Email+Passwort-Login wird deaktiviert, OIDC_CLIENT_ID + OIDC_CLIENT_SECRET werden Pflicht.

https://auth.example.com/realms/main
OUTBOUND_ALLOW_LOOPBACKOptionalDefault: 0

Escape-Hatch für den SSRF-Guard. Nur in Tests auf 1 setzen, die gegen einen lokalen Receiver fetchen — niemals über NODE_ENV gaten.