# /etc/nginx/sites-available/test.ph.sokaris.link # # Production Nginx reverse proxy configuration for YEG SpookyBooth # Domain: test.ph.sokaris.link # Backend: Next.js on 127.0.0.1:34821 # Rate limiting zones (must be placed in http block on server, or included here) limit_req_zone $binary_remote_addr zone=booth_api_limit:10m rate=10r/s; limit_req_zone $binary_remote_addr zone=booth_auth_limit:10m rate=5r/m; upstream photobooth_backend { server 127.0.0.1:34821; keepalive 32; } # HTTP: Redirect all traffic to HTTPS (and allow Certbot ACME challenges) server { listen 80; listen [::]:80; server_name test.ph.sokaris.link; # Certbot challenge directory location /.well-known/acme-challenge/ { root /var/www/html; } # Redirect all other HTTP traffic to HTTPS location / { return 301 https://$host$request_uri; } } # HTTPS: Secure proxy block server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name test.ph.sokaris.link; # SSL Certificates (Managed by Let's Encrypt / Certbot) ssl_certificate /etc/letsencrypt/live/test.ph.sokaris.link/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/test.ph.sokaris.link/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # Maximum upload size for photo uploads (10MB max) client_max_body_size 10M; # Camera Access & Security Policy Headers add_header Permissions-Policy "camera=(self), microphone=()" always; add_header Feature-Policy "camera 'self'; microphone 'none'" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; # Logs access_log /var/log/nginx/photobooth_access.log; error_log /var/log/nginx/photobooth_error.log; # 1. Block access to hidden files and directories (.git, .env, etc.) location ~ /\. { deny all; access_log off; log_not_found off; } # 2. Block access to sensitive and executable file extensions location ~* \.(env|git|bak|config|sql|sh|exe|bat|cmd|py|php|cgi)$ { deny all; access_log off; log_not_found off; } # Next.js static asset caching (immutable, high performance) location /_next/static/ { proxy_pass http://photobooth_backend; proxy_http_version 1.1; proxy_set_header Connection ""; expires 365d; access_log off; add_header Cache-Control "public, max-age=31536000, immutable"; } # Public static assets location /assets/ { proxy_pass http://photobooth_backend; proxy_http_version 1.1; proxy_set_header Connection ""; expires 30d; add_header Cache-Control "public, max-age=2592000"; } # Rate-limited auth endpoint location = /api/portal/auth { limit_req zone=booth_auth_limit burst=5 nodelay; limit_req_status 429; proxy_pass http://photobooth_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; } # Rate-limited general API endpoints location /api/ { limit_req zone=booth_api_limit burst=25 nodelay; limit_req_status 429; proxy_pass http://photobooth_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_connect_timeout 60s; proxy_send_timeout 120s; proxy_read_timeout 120s; proxy_buffering off; } # Main Application Proxy location / { proxy_pass http://photobooth_backend; proxy_http_version 1.1; # WebSocket & connection upgrade headers proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; # Standard Proxy Headers 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 X-Forwarded-Host $host; proxy_set_header X-Forwarded-Port $server_port; # AI Generation Timeouts (allow up to 2 minutes for slow AI models) proxy_connect_timeout 60s; proxy_send_timeout 120s; proxy_read_timeout 120s; # Disable buffering for instant streaming / server-sent events proxy_buffering off; } }