# nginx reverse-proxy recipe for internet-facing self-hosts. # This file is included inside nginx's `http {}` context by the official image. # # Note on basepath: this recipe proxies the app at the URL root and does # NOT strip a path prefix. Do not set ETHERCALC_BASEPATH behind it — # the worker expects a prefix-stripping edge when a basepath is in use. limit_req_zone $binary_remote_addr zone=ethercalc_api:10m rate=10r/s; # Two conn zones: WebSockets are held open for a tab's whole lifetime, so # they get a generous budget; plain HTTP requests are short-lived and a # small in-flight cap is plenty. (A single shared zone with mixed limits # would let idle WS tabs starve HTTP requests behind one NAT/CGNAT IP.) limit_conn_zone $binary_remote_addr zone=ethercalc_conn_ws:10m; limit_conn_zone $binary_remote_addr zone=ethercalc_conn_http:10m; map $http_upgrade $connection_upgrade { default upgrade; '' close; } upstream ethercalc_backend { server ethercalc:8000; } server { listen 80; server_name _; # For production HTTPS, uncomment these lines after mounting certs # under deploy/nginx/certs/ AND publishing 443 in # docker-compose.proxy.yml (see the commented ports entry there): # listen 443 ssl; # http2 on; # ssl_certificate /etc/nginx/certs/fullchain.pem; # ssl_certificate_key /etc/nginx/certs/privkey.pem; client_max_body_size 25m; location /_ws/ { limit_req zone=ethercalc_api burst=30 nodelay; limit_conn ethercalc_conn_ws 100; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # Spreadsheet WebSockets idle between keystrokes and neither end # heartbeats; without these, nginx's 60s default read timeout # severs every quiet connection. proxy_read_timeout 1h; proxy_send_timeout 1h; proxy_pass http://ethercalc_backend; } location /socket.io/ { limit_req zone=ethercalc_api burst=30 nodelay; limit_conn ethercalc_conn_ws 100; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 1h; proxy_send_timeout 1h; proxy_pass http://ethercalc_backend; } location /_/ { limit_req zone=ethercalc_api burst=60 nodelay; limit_conn ethercalc_conn_http 20; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://ethercalc_backend; } location / { limit_req zone=ethercalc_api burst=60 nodelay; limit_conn ethercalc_conn_http 20; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://ethercalc_backend; } }