server { listen 80; server_name localhost; root /usr/share/nginx/html; index index.html; add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always; # Docker-Embedded DNS: Hostname »backend« bei Container-Neustarts neu auflösen # — verringert sporadische 502, wenn sich nur die Backend-Container-IP geändert hat. resolver 127.0.0.11 valid=10s ipv6=off; # Uploads (Übungsmedien) und API erreichen Clients unter derselben Host-URL wie die SPA — # dafür muss Nginx zur FastAPI-Instanz im Compose-Netz weiterleiten. client_max_body_size 64m; location ^~ /api/ { set $docker_backend_svc backend; proxy_pass http://$docker_backend_svc:8000$request_uri; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_connect_timeout 60s; proxy_send_timeout 300s; proxy_read_timeout 300s; } location ^~ /media/ { set $docker_backend_svc backend; proxy_pass http://$docker_backend_svc:8000$request_uri; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location = /health { set $hc_upstream backend; proxy_pass http://$hc_upstream:8000/health; proxy_http_version 1.1; proxy_set_header Host $host; } # SPA routing - serve index.html for all routes location / { try_files $uri $uri/ /index.html; } # Cache static assets location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires 1y; add_header Cache-Control "public, immutable"; } }