An Nginx reverse proxy config builder for putting Nginx in front of a Node, Python, or
any HTTP backend. It generates an upstream block, a server block with the correct
forwarded headers, sensible timeouts, request buffering, and optional SSL and WebSocket
support — copy-and-deploy ready.
How it works
The config has two parts. The upstream block names your backend pool and lists each
host:port. With more than one backend it adds least_conn load balancing; in all cases it
adds keepalive 32 so Nginx reuses connections to the backend instead of opening a new
socket per request (which is why proxy_http_version 1.1 and an empty Connection header
matter).
The server block proxies location / to that upstream and forwards the four headers a
backend needs to know the real client: Host, X-Real-IP, X-Forwarded-For, and
X-Forwarded-Proto. When WebSocket support is on, it adds a top-level map that drives
the Connection: upgrade header so socket upgrades pass through. Timeouts,
client_max_body_size, and proxy_buffers round out the block, and enabling SSL adds a
443 listener plus an 80→443 redirect.
Why use an upstream block even with one backend
Pointing proxy_pass directly to http://localhost:3000 works but the upstream block gives you more control. With keepalive 32, Nginx maintains a pool of persistent connections to the backend rather than opening a new TCP connection for each request — at moderate traffic this meaningfully reduces latency. When you are ready to add a second backend for load balancing or blue/green deployments, you just add another server line to the upstream block without touching the location.
WebSocket proxying — what the map block does
WebSocket connections start as an HTTP Upgrade request. Nginx by default forwards HTTP/1.0 and strips the Upgrade header. The generated map block detects the Upgrade header and sets $connection_upgrade to either upgrade or close:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
Combined with proxy_http_version 1.1 and forwarding both the Upgrade and Connection headers, this lets WebSocket handshakes pass cleanly through the proxy to a backend like Socket.IO or a real-time API.
Handling different backend response patterns
- Standard JSON API — keep
proxy_buffering on(the default). Nginx buffers the full response into memory, which frees the backend connection quickly and improves throughput. - Server-sent events (SSE) or streaming endpoints — set
proxy_buffering offon the specific location. Buffering would hold the stream until the backend closes the connection, defeating the purpose. - Large file uploads — raise
client_max_body_sizeto match the largest file your API accepts, otherwise Nginx returns413 Request Entity Too Largebefore the request even reaches your backend.
Tips and notes
- The
map $http_upgrade $connection_upgradedirective must live in the http{} context, not inside a server block — keep it at the top of the file as generated. - Forwarding
X-Forwarded-Protois essential for frameworks like Express (trust proxy) and Django (SECURE_PROXY_SSL_HEADER) to build correct absolute URLs and set secure cookies behind the proxy. - For server-sent events or streaming responses, set
proxy_buffering off;on that specific location so clients receive data as it is produced. - Validate with
nginx -tbefore reloading; a typo in an upstream address will otherwise take the whole virtual host down.