# proxy-vm/nginx/nginx.conf worker_processes auto; error_log /dev/stderr warn; pid /tmp/nginx.pid; events { worker_connections 1024; } http { # --- JSON access log --- log_format json_log escape=json '{' '"time":"$time_iso8601",' '"remote_addr":"$remote_addr",' '"method":"$request_method",' '"uri":"$request_uri",' '"status":$status,' '"bytes_sent":$bytes_sent,' '"request_time":$request_time,' '"upstream_addr":"$upstream_addr",' '"upstream_response_time":"$upstream_response_time"' '}'; access_log /dev/stdout json_log; # --- Hash bucket size for long map keys (PROXY_SECRET) --- map_hash_bucket_size 128; # --- Performance --- sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; client_max_body_size 50m; gzip off; # --- DNS resolver (Google + Cloudflare, re-resolve every 30s) --- resolver 8.8.8.8 1.1.1.1 valid=30s ipv6=off; resolver_timeout 5s; # --- IP allowlist (generated at container start) --- include /etc/nginx/conf.d/allowlist.conf; # --- Token auth --- include /etc/nginx/conf.d/auth.conf; server { listen 8080; server_name _; # --- Health check (no auth) --- location = /health { access_log off; default_type application/json; return 200 '{"status":"ok","version":"1.0"}'; } # --- ElevenLabs --- location /elevenlabs/ { # Auth checks if ($allowed_ip = 0) { return 403 '{"error":"ip_not_allowed"}'; } if ($auth_ok = 0) { return 403 '{"error":"invalid_token"}'; } # Variable forces runtime DNS resolution (not cached at startup) set $elevenlabs_upstream https://api.elevenlabs.io; # Strip /elevenlabs/ prefix and proxy rewrite ^/elevenlabs/(.*) /$1 break; proxy_pass $elevenlabs_upstream; proxy_ssl_server_name on; proxy_ssl_name api.elevenlabs.io; proxy_ssl_protocols TLSv1.2 TLSv1.3; # Host header must match upstream for Cloudflare proxy_set_header Host api.elevenlabs.io; proxy_set_header Connection ""; # Scrub all headers that leak the original client IP # Cloudflare reads these to determine "real" client geo proxy_set_header X-Forwarded-For ""; proxy_set_header X-Real-IP ""; proxy_set_header True-Client-IP ""; proxy_set_header CF-Connecting-IP ""; proxy_set_header X-Client-IP ""; proxy_set_header Forwarded ""; proxy_set_header Via ""; # Remove proxy token before forwarding to upstream proxy_set_header X-Proxy-Token ""; # HTTP/1.1 for keepalive proxy_http_version 1.1; # Streaming / performance proxy_buffering off; proxy_request_buffering off; proxy_read_timeout 120s; proxy_send_timeout 120s; } # --- OpenAI --- location /openai/ { if ($allowed_ip = 0) { return 403 '{"error":"ip_not_allowed"}'; } if ($auth_ok = 0) { return 403 '{"error":"invalid_token"}'; } set $openai_upstream https://api.openai.com; rewrite ^/openai/(.*) /$1 break; proxy_pass $openai_upstream; proxy_ssl_server_name on; proxy_ssl_name api.openai.com; proxy_ssl_protocols TLSv1.2 TLSv1.3; proxy_set_header Host api.openai.com; proxy_set_header Connection ""; # Scrub all headers that leak the original client IP proxy_set_header X-Forwarded-For ""; proxy_set_header X-Real-IP ""; proxy_set_header True-Client-IP ""; proxy_set_header CF-Connecting-IP ""; proxy_set_header X-Client-IP ""; proxy_set_header Forwarded ""; proxy_set_header Via ""; proxy_set_header X-Proxy-Token ""; proxy_http_version 1.1; proxy_buffering off; proxy_request_buffering off; proxy_read_timeout 120s; proxy_send_timeout 120s; } # --- Catch-all --- location / { default_type application/json; return 404 '{"error":"unknown_upstream","hint":"use /elevenlabs/ or /openai/"}'; } } }