server { listen 3000; server_name _; root /usr/share/nginx/html; index index.html; # Security headers 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; # WebSocket reverse proxy — relay to remote gateway with correct Origin location ~ ^/gwproxy/(.+) { resolver 8.8.8.8 valid=30s; proxy_pass https://api.routin.ai/$1; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host api.routin.ai; proxy_set_header Origin "https://api.routin.ai"; proxy_ssl_server_name on; proxy_read_timeout 86400; proxy_send_timeout 86400; } location / { try_files $uri $uri/ /index.html; } location /assets/ { expires 1y; add_header Cache-Control "public, immutable"; } location = /index.html { add_header Cache-Control "no-cache, no-store, must-revalidate"; add_header Pragma "no-cache"; add_header Expires "0"; } gzip on; gzip_types text/plain text/css application/json application/javascript text/xml application/xml text/javascript image/svg+xml; gzip_min_length 256; }