Reverse Proxies Explained: What Nginx and Similar Tools Actually Do
Every production web app sits behind something that isn't the app itself — usually Nginx, HAProxy, or a cloud load balancer. That thing is a reverse proxy, and understanding what it's actually doing clears up a lot of confusing production behavior.
Published July 6, 2026A proxy, in the general sense, is anything that sits between a client and a server and forwards requests on someone's behalf. The direction of "on whose behalf" is what separates the two common kinds. A forward proxy sits in front of clients and hides them from the servers they talk to — a corporate network's outbound proxy, or a VPN, both act on behalf of the client. A reverse proxy sits in front of servers and hides them from the clients that talk to them. When a browser hits example.com, it has no idea whether that request lands directly on an application server or gets intercepted, inspected, and forwarded by Nginx first. That's the point: the reverse proxy presents a single, stable address to the outside world while the real servers behind it can change, scale, or restart without the client ever knowing.
What it actually does, concretely
A minimal Nginx reverse proxy config looks like this:
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/ssl/example.com.crt;
ssl_certificate_key /etc/ssl/example.com.key;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
The client connects to Nginx on port 443, which handles the TLS handshake and decrypts the request, then opens a plain HTTP connection to the actual application on port 8080 and forwards the request there. This is TLS termination: the certificate lives on the proxy, not on every backend process, so you manage and renew it in one place instead of on every application server. The X-Forwarded-For and X-Real-IP headers exist because, from the application's point of view, every request now appears to come from the proxy's own IP address (127.0.0.1 in this example) — without those headers, the app loses the client's real IP entirely, which breaks rate limiting, geolocation, and abuse logging unless the app is explicitly configured to trust and read them.
The jobs it typically does
TLS termination is one job among several a reverse proxy commonly handles. It can serve static files directly without ever reaching the application server, since Nginx serving a file from disk is faster than a request round-tripping through an app framework. It can route based on path or hostname — /api/ to one backend, everything else to another, or different hostnames to entirely different applications on the same machine. It can enforce rate limits and reject abusive traffic before it burns application resources. And it very often does load balancing across multiple backend instances, though that's a distinct function bundled into the same piece of software rather than something reverse proxies inherently do — a reverse proxy with exactly one backend is still a reverse proxy, it just isn't balancing anything.
Buffering and timeouts, the part that bites people
A reverse proxy usually buffers the response from the backend before sending it to the client, which means slow clients on bad connections don't hold a backend worker thread open waiting for bytes to trickle out over a slow link — the proxy absorbs that once and serves the client from its buffer. That's good for throughput but it means a backend that streams a response gradually (server-sent events, a long file download with progress) can appear to arrive all at once or get delayed, unless buffering is explicitly disabled for that route with something like proxy_buffering off. Proxy timeouts are the other frequent surprise: if a backend takes longer than the proxy's configured proxy_read_timeout to respond, the proxy kills the connection and returns a 504 gateway timeout to the client, even though the backend might have finished the work a second later. Debugging "why does this request fail after exactly 60 seconds" almost always ends at a proxy timeout setting, not the application code.
Reverse proxy vs API gateway vs CDN
These terms overlap in practice more than the marketing suggests. An API gateway is a reverse proxy with extra responsibilities layered on — authentication, request transformation, per-client rate limiting, and often aggregating calls to multiple backend services into one response. A CDN is a reverse proxy that's also a cache, distributed to edge locations close to users, primarily built to serve cached content without hitting the origin at all. All three sit in the same architectural position: between the client and the real server, changing or optimizing what passes through. Nginx's own documentation on the proxy module is the reference worth bookmarking once you're tuning buffering, timeouts, or header handling for a specific production issue rather than learning the concept for the first time.