:80 { encode gzip zstd header { X-Frame-Options "SAMEORIGIN" X-Content-Type-Options "nosniff" X-XSS-Protection "1; mode=block" Referrer-Policy "strict-origin-when-cross-origin" Content-Security-Policy "default-src 'self'; connect-src 'self' https://api.github.com https://raw.githubusercontent.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; script-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' https://fonts.gstatic.com" Permissions-Policy "geolocation=(), microphone=(), camera=()" } handle /api/anthropic/* { uri strip_prefix /api/anthropic reverse_proxy https://api.anthropic.com { header_up Host api.anthropic.com header_up x-api-key "{$ANTHROPIC_API_KEY}" header_up anthropic-dangerous-direct-browser-access "true" } } handle /api/* { reverse_proxy pocketbase-learning:8090 } handle /_/* { reverse_proxy pocketbase-learning:8090 } handle { root * /srv @static { path *.css *.js *.png *.jpg *.jpeg *.gif *.webp *.svg *.woff *.woff2 *.ttf } header @static Cache-Control "public, max-age=31536000, immutable" @html { path *.html / } header @html Cache-Control "public, max-age=0, must-revalidate" try_files {path} /index.html file_server } handle_errors { # Don't mask API errors with the SPA shell — return a proper # JSON error so the frontend can display a meaningful message. @api path /api/* respond @api `{"code":{err.status_code},"message":"Backend unavailable"}` {err.status_code} { Content-Type application/json } rewrite * /index.html file_server } log { output stdout format console } }