Files
kapteins-daagbok/docs/deployment/npm-security.md
T
elpatron e138752dd3 feat(security): Sprint 1 hardening for production behind NPM
Add trust proxy, WebAuthn challenge TTL, stricter public collaboration
rate limits, generic 500 responses, Docker POSTGRES_PASSWORD from env,
nginx security headers/CSP, and deployment documentation.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-01 15:02:15 +02:00

2.3 KiB

Deployment: Nginx Proxy Manager & Security (Sprint 1)

Kapteins Daagbok läuft öffentlich unter https://kapteins-daagbok.eu/ hinter Nginx Proxy Manager (NPM, z. B. 172.16.10.10) mit Upstream auf den App-Stack (172.16.10.110).

NPM Proxy Host

Einstellung Wert
Domain kapteins-daagbok.eu
Scheme https
Forward Hostname / IP 172.16.10.110 (oder Container-Port auf dem Host)
Forward Port 80 (Frontend-Nginx)
Websockets an, falls genutzt
Block Common Exploits an
SSL Let's Encrypt o. ä.

Custom Nginx (Advanced) — empfohlen

NPM setzt X-Forwarded-* in der Regel automatisch. Falls nicht, im Proxy-Host unter Advanced:

proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;

Backend-Umgebung (.env auf dem Server)

ORIGIN=https://kapteins-daagbok.eu
RP_ID=kapteins-daagbok.eu
SESSION_SECRET=<min. 32 Zeichen, openssl rand -base64 48>
TRUST_PROXY=172.16.10.10
# oder TRUST_PROXY=1 für genau einen Proxy-Hop

ORIGIN muss exakt der Browser-URL entsprechen (ohne trailing slash).

Security-Header

  • HSTS, CSP (optional restriktiver): können in NPM unter „Custom Headers“ oder im Advanced-Block gesetzt werden.
  • Basis-Header für statische Dateien setzt client/nginx.conf (X-Content-Type-Options, X-Frame-Options, Referrer-Policy, CSP inkl. Plausible).

Plausible Analytics

Script-Host: https://plausible.elpatron.me — in CSP als script-src und connect-src erlaubt. Gemessene Site: data-domain="kapteins-daagbok.eu".

Optional später: analytics.kapteins-daagbok.eu als Alias auf dieselbe Plausible-Instanz.

Nach Deploy prüfen

  1. https://kapteins-daagbok.eu/api/healthstatus: ok
  2. Passkey Login / Registrierung
  3. DevTools → Application → Cookie daagbok_session: Secure, HttpOnly, SameSite=Lax
  4. Response-Header auf index.html: CSP, X-Frame-Options
  5. Zwei Geräte hinter NAT: unabhängige Rate-Limits (nicht alle als eine IP)

Docker Compose

Keine Default-Passwörter in Produktion: POSTGRES_PASSWORD und SESSION_SECRET in .env setzen (siehe .env.example).