# nginx default.conf — Vue3 SPA (history mode) + /api reverse proxy to backend # Mounted at /etc/nginx/conf.d/default.conf by the frontend Dockerfile. # Spec §10: client_max_body_size 50m (ingest payloads can be large; Express limit is 50mb). server { listen 80; listen [::]:80; server_name _; # Spec §10 reliability: allow large ingest payloads up to 50m. client_max_body_size 50m; # Defense-in-depth: don't leak the nginx version in Server: headers / error pages. server_tokens off; root /usr/share/nginx/html; index index.html; # ---- gzip: text assets over the wire ---- gzip on; gzip_vary on; gzip_min_length 1024; gzip_proxied any; gzip_comp_level 5; gzip_types text/plain text/css text/xml application/json application/javascript text/javascript application/xml+rss application/atom+xml image/svg+xml font/ttf font/otf font/woff font/woff2; # ---- API reverse proxy: /api/* -> http://backend:8080/api/* ---- # No trailing slash on proxy_pass => the /api prefix is preserved, so # /api/health -> http://backend:8080/api/health. location /api/ { proxy_pass http://backend:8080; 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; # Clear Connection so upstream keep-alive isn't disabled by client headers. proxy_set_header Connection ""; # Backend has some slow queries; give them room. proxy_connect_timeout 10s; proxy_send_timeout 60s; proxy_read_timeout 60s; } # ---- Hashed static assets: long immutable cache ---- location /assets/ { expires 1y; add_header Cache-Control "public, max-age=31536000, immutable"; access_log off; } # ---- SPA history-mode fallback (CRITICAL) ---- # vue-router uses createWebHistory, so deep links like /inquiries or # /inquiries/:id MUST fall back to index.html instead of 404. location / { try_files $uri $uri/ /index.html; } # index.html itself should never be aggressively cached, so deploys take # effect immediately (the asset files it references are content-hashed). location = /index.html { add_header Cache-Control "no-cache, no-store, must-revalidate"; expires off; } }