Reverse Proxy in Practice
A server that sits in front of origins and terminates, caches, routes and protects — the cheapest place to solve several problems at once.
Definition
A reverse proxy accepts client connections on behalf of one or more origin servers. It commonly terminates TLS, caches responses, routes by path or host, compresses, buffers slow clients, and enforces limits.
What it solves that is hard to solve elsewhere
Slow client buffering. A client on a poor mobile connection takes seconds to receive a response. Without a proxy, an application worker is held for that whole time. The proxy accepts the response quickly, frees the worker, and dribbles it out at the client's pace. On a thread-per-request application server this single property can multiply effective capacity.
Caching in front of the origin. For read-heavy content, the proxy answers most requests and the origin sees a fraction of traffic.
A single place for cross-cutting concerns. TLS certificates, header manipulation, redirect rules, compression, request logging with a correlation ID.
Industry example
News publishing is the canonical case. A story is written once and read millions of times, with traffic arriving as a step function on a major event. Rendering each request at the origin is impossible; rendering once and serving from cache is trivial.
The architecture that follows is a hard split: a write-side publishing system optimised for editorial workflow, and a read-side that is essentially cached artefacts served from proxies and CDN nodes. The valuable consequence is that the read path survives the origin being down — which nobody requested as a feature and which is the most important property the system has on the day it matters.
The hard part is the fragments that resist caching: personalisation, paywall state, live vote counts, comments. Each is solved separately — client-side fetch, edge-evaluated token, short TTL with stale-while-revalidate, a fully separate service — and each is a decision about what to sacrifice when it fails.
Failure scenarios
- Caching a personalised response because the cache key omitted the user dimension. This leaks one user's data to another and is the highest-severity mistake in this area.
Varyheaders ignored, so a compressed response is served to a client that cannot decompress it, or a mobile rendition to a desktop.- Cache key including a tracking query parameter, so every visitor gets a unique key and the hit rate collapses.
- Buffering disabled for streaming responses, so a long-lived stream is held until complete.
- The proxy as an unmonitored single point of failure, more critical than anything behind it.
Trade-offs
Bought: origin protection, latency, capacity multiplication, one place for cross-cutting concerns. Sold: an extra hop, a component that must be more available than the origin, and a class of bug — serving the wrong cached thing — that is worse than an error because it is silent.
Interview question
"How would you cache a page that is identical for all users except a small personalised header?"