# 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;