# /etc/nginx/sites-available/karate.ph.sokaris.link # # Production Nginx reverse proxy configuration for Karate Halloween Photo Booth # Domain: karate.ph.sokaris.link # Backend: Next.js PM2 process on 127.0.0.1:34822 # User: www-data # Rate limiting zones (can be defined in http block in /etc/nginx/nginx.conf or here if http-level included) limit_req_zone $binary_remote_addr zone=karate_api_limit:10m rate=10r/s; limit_req_zone $binary_remote_addr zone=karate_auth_limit:10m rate=5r/m; upstream karate_backend { server 127.0.0.1:34822; keepalive 32; } # HTTP: Redirect all traffic to HTTPS (and allow Let's Encrypt / Certbot challenges) server { listen 80; listen [::]:80; server_name karate.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 karate.ph.sokaris.link; # SSL Certificates (Managed by Let's Encrypt / Certbot) ssl_certificate /etc/letsencrypt/live/karate.ph.sokaris.link/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/karate.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 (15MB) client_max_body_size 15M; # 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/karate_photobooth_access.log; error_log /var/log/nginx/karate_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://karate_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://karate_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=karate_auth_limit burst=5 nodelay; limit_req_status 429; proxy_pass http://karate_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=karate_api_limit burst=25 nodelay; limit_req_status 429; proxy_pass http://karate_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://karate_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 proxy_connect_timeout 60s; proxy_send_timeout 120s; proxy_read_timeout 120s; # Disable buffering for instant streaming / server-sent events proxy_buffering off; } }