diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..fa0ba26 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,130 @@ +# nginx config for llm.home.ms - kokorotts-server reverse proxy +# Addresses: issues #15-#24 (OPE-Web security audit findings) + +server { + listen 443 ssl http2; + server_name llm.home.ms; + + # SSL configuration + ssl_certificate /etc/letsencrypt/live/llm.home.ms/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/llm.home.ms/privkey.pem; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + + # Issue #21: Hide server version + server_tokens off; + + # Issue #16: HSTS header (1 year, include subdomains) + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + + # Issue #17: Content-Security-Policy + # Allow Swagger UI inline scripts/styles while restricting external sources + add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self';" always; + + # Issue #18: X-Frame-Options - prevent clickjacking + add_header X-Frame-Options "DENY" always; + + # Issue #19: X-Content-Type-Options - prevent MIME sniffing + add_header X-Content-Type-Options "nosniff" always; + + # Issue #20: Referrer-Policy + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + + # Permissions Policy + add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always; + + # Issue #15: Restrict Swagger UI access - require authentication + location /docs { + auth_basic "API Documentation - Restricted Access"; + auth_basic_user_file /etc/nginx/.htpasswd; + proxy_pass http://127.0.0.1:5012; + 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; + } + + location /openapi.json { + auth_basic "API Documentation - Restricted Access"; + auth_basic_user_file /etc/nginx/.htpasswd; + proxy_pass http://127.0.0.1:5012; + 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; + } + + # Main API endpoint + location /tts { + proxy_pass http://127.0.0.1:5012; + 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 limiting + limit_req zone=tts_zone burst=5 nodelay; + } + + # Health check endpoint (no auth needed) + location /health { + proxy_pass http://127.0.0.1:5012; + 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; + } + + # Issue #22: Fix protocol-relative links by redirecting absolute paths + # These locations handle the broken //ui, //fallback/login, //ui/model_hub_table links + location /ui/ { + proxy_pass http://127.0.0.1:5012/ui/; + 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; + } + + location /fallback/login { + proxy_pass http://127.0.0.1:5012/fallback/login; + 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; + } + + location /ui/model_hub_table { + proxy_pass http://127.0.0.1:5012/ui/model_hub_table; + 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; + } + + # Default: proxy to Flask app + location / { + proxy_pass http://127.0.0.1:5012; + 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; + } + + # Block access to version info + location ~* /version { + return 403; + } +} + +# HTTP -> HTTPS redirect +server { + listen 80; + server_name llm.home.ms; + return 301 https://$server_name$request_uri; +} + +# Rate limiting zone (add to http block in nginx.conf) +# limit_req_zone $binary_remote_addr zone=tts_zone:10m rate=10r/s;