# Work Package Suite — NGINX site config # This container sits behind an external reverse proxy that handles SSL. # It listens on port 80 (plain HTTP on the internal Docker network). server { listen 80; server_name wp.controls.dev; root /usr/share/nginx/html; index index.html; # ── Security response headers (defense-in-depth) ───────────────────────── # CSP keeps 'unsafe-inline' for now because the app uses inline handlers/styles # heavily; even so, connect-src/img-src/object-src/base-uri/frame-ancestors # sharply limit what injected script could load or exfiltrate. Tighten toward # nonce-based scripts once inline handlers are refactored. add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header Referrer-Policy "no-referrer" always; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self'; connect-src 'self'; object-src 'none'; base-uri 'none'; frame-ancestors 'self'; form-action 'self'" always; location / { try_files $uri $uri/ =404; } # Proxy /api/ to the FastAPI container (service name "api" on the internal network) location /api/ { proxy_pass http://api:8000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; # This container is only ever reached via the TLS-terminating external # proxy, so the real client scheme is HTTPS. Hard-set it (a local $scheme # here is always "http") so the API marks the session cookie Secure. proxy_set_header X-Forwarded-Proto https; client_max_body_size 5m; } }