# FrankenPHP Caddyfile for the ui container. # Serves Slim from public/ on :8080. { frankenphp order php_server before file_server auto_https off admin off servers { trusted_proxies static private_ranges } } :8080 { root * /app/public encode zstd gzip # ── Security headers (M14) ────────────────────────────────────────── header { -Server -X-Powered-By X-Content-Type-Options "nosniff" X-Frame-Options "DENY" Referrer-Policy "strict-origin-when-cross-origin" Permissions-Policy "geolocation=(), microphone=(), camera=()" # CSP for the ui: # - script-src needs 'unsafe-eval' for Alpine.js v3's Function() # constructor. Migrating to @alpinejs/csp would let us drop it # but requires rewriting every x-data="..." inline expression. # Documented trade-off. # - style-src 'unsafe-inline' for inline style attrs that drive # score bars and dynamic widths. # - img-src data: for inline SVG icons. Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'" } @prod expression `{env.APP_ENV} == "production"` header @prod Strict-Transport-Security "max-age=31536000; includeSubDomains" php_server }