# Dangerous Pi - Nginx reverse proxy configuration # Serves frontend on / and proxies /api/*, /ws/* to backend upstream frontend { server 127.0.0.1:3000; } upstream backend { server 127.0.0.1:8000; } server { listen 80 default_server; listen [::]:80 default_server; server_name dangerous-pi.local _; # =========================================== # CAPTIVE PORTAL DETECTION # =========================================== # These endpoints respond to OS connectivity checks. # When a device connects to the AP, the OS checks these URLs. # By responding correctly, we trigger the captive portal popup. # Android / Chrome OS connectivity check location = /generate_204 { return 204; } # Additional Android check paths location = /gen_204 { return 204; } # Google connectivity check location = /connectivitycheck/gstatic/generate_204 { return 204; } # iOS / macOS captive portal detection location = /hotspot-detect.html { return 200 'SuccessSuccess'; add_header Content-Type text/html; } # iOS alternate path location = /library/test/success.html { return 200 'SuccessSuccess'; add_header Content-Type text/html; } # Windows 10/11 connectivity check location = /connecttest.txt { return 200 'Microsoft Connect Test'; add_header Content-Type text/plain; } # Windows NCSI check location = /ncsi.txt { return 200 'Microsoft NCSI'; add_header Content-Type text/plain; } # Firefox / Mozilla connectivity check location = /success.txt { return 200 'success'; add_header Content-Type text/plain; } # Kindle / Amazon devices location = /kindle-wifi/wifistub.html { return 200 'Kindle81ce4465-7167-4dcb-835b-dcc9e44c112a'; add_header Content-Type text/html; } # =========================================== # END CAPTIVE PORTAL DETECTION # =========================================== # Proxy API requests to FastAPI backend location /api/ { proxy_pass http://backend; 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_read_timeout 300s; proxy_connect_timeout 75s; } # Proxy WebSocket connections to backend location /ws/ { proxy_pass http://backend; 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_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 86400s; proxy_send_timeout 86400s; } # Everything else goes to Remix frontend location / { proxy_pass http://frontend; 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_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_cache_bypass $http_upgrade; } # Security headers add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; # Gzip compression gzip on; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_types text/plain text/css text/xml application/json application/javascript application/xml; }