What a reverse proxy in Nginx is and why you need one
A reverse proxy is a server that accepts requests from clients and forwards them to one or more backends: an application on Node.js, Python, Java, or another Nginx instance. The client only talks to the proxy and never sees the internal structure of the service. Nginx can act as a reverse proxy out of the box — all it takes is the proxy_pass directive inside a location block.
A reverse proxy in Nginx solves several tasks at once: it terminates TLS in front of the application, serves static files directly bypassing a slow backend, hides internal ports and IP addresses, and adds security headers. On a ZevsHost.net VDS this setup is often placed in front of a Node.js or Python application: Nginx listens on port 80 and 443, while the service itself runs on localhost and is never exposed directly.
- Load balancing across several copies of the application.
- A single SSL certificate covering the whole set of internal services.
- Caching backend responses without touching the application code.
Configuring proxy_pass: a basic example
The minimal config is a server block with one location that forwards every request to the local application over HTTP.
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
}
}
If location ends with a trailing slash and proxy_pass includes a path, Nginx replaces the matched part of the URI with that path. Without a path in proxy_pass, the original URI is passed to the backend as is — the most predictable option, especially when the application does its own routing. For matching rules in detail, see the article on location priority.
Forwarding client headers to the backend
By default Nginx replaces the Host header with the backend address and never tells the application the visitor's real IP. If this is left unfixed, application logs will only show the Nginx IP, and links in emails or redirects may point to localhost instead of the real domain.
location / {
proxy_pass http://127.0.0.1:3000;
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;
}
The backend application should trust these headers only when a request truly comes from the local Nginx — otherwise a client could forge X-Forwarded-For directly.
Timeouts and buffers: what each parameter controls
If the backend responds slowly or returns a large response, Nginx default timeouts and buffers can cut the connection off too early. The values below are a working starting point for an ordinary web application, not for streaming.
| Parameter | Purpose | Typical value |
|---|---|---|
| proxy_connect_timeout | waiting for the TCP connection to the backend | 5s |
| proxy_send_timeout | time between writes of data to the backend | 60s |
| proxy_read_timeout | time between reads of the backend response | 60s |
| proxy_buffer_size | buffer for the first part of the response (headers) | 4k |
| proxy_buffers | number and size of buffers for the response body | 8 4k |
A too short proxy_read_timeout is a common cause of 504 Gateway Timeout on heavy requests such as exporting a report or uploading a file. Buffers that are too small force Nginx to write temporary files to disk, which is noticeable on a VDS with a slow disk.
Reverse proxy to several servers through upstream
If the application runs in several copies, instead of a single address in proxy_pass you use an upstream block with a list of servers.
upstream backend {
server 127.0.0.1:3000;
server 127.0.0.1:3001;
server 127.0.0.1:3002 backup;
}
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://backend;
}
}
By default Nginx distributes requests round robin and skips the server marked backup while the others are alive. For load distribution algorithms and backend health checks, see the separate article on the Nginx load balancer. If HTTPS is also needed in front of the reverse proxy, the certificate is configured on the outer server — see the article on SSL/TLS in Nginx.
Checklist: reverse proxy before production
- The Host, X-Real-IP, and X-Forwarded-For headers are forwarded to the backend and visible in its logs.
- The
nginx -tcommand passes without errors after every config change. - Timeouts are tuned to the application's real response time instead of being left at defaults.
- With several backends in upstream, at least one backup server is configured.
- The response has been checked with
curl -I http://app.example.com/— headers and status code match expectations.