Both sit in the middle of a conversation between client and server. Both forward requests. The names are almost identical, which is why this comes up in interviews so often.
The distinction is a single question: whose side is it on?
- A forward proxy acts for the client. The server does not know who really asked.
- A reverse proxy acts for the server. The client does not know who really answered.
Everything else follows from that.
Diagram, as text
- Clients leads to Proxy
- Proxy leads to Internet
- Clients leads to Reverse proxy
- Reverse proxy leads to Your servers
Forward proxy: the client's agent
Clients send requests to the proxy, which fetches on their behalf. The destination server sees the proxy's address, not the client's.
Where you actually meet this:
Corporate networks. All employee traffic routes through a proxy that blocks certain sites, scans downloads for malware, and logs access for compliance. This is the most common real deployment by far.
Privacy and geography. A VPN is essentially this idea — the destination sees the proxy's location instead of yours.
Shared caching. A university proxy that has already fetched a popular file serves it locally to the next student, saving bandwidth on the shared connection.
The defining trait: the client is configured to use it, deliberately. Someone set it up in browser settings or network policy.
Reverse proxy: the server's agent
Clients think they are talking to your application. They are talking to the reverse proxy, which decides what happens next. Configuration lives entirely on your side; clients know nothing about it.
This is the one you will design with constantly, because it is where you put every concern that should not be duplicated in every service.
TLS termination. The proxy handles HTTPS — certificates, handshakes, encryption — and forwards plain HTTP inside your trusted network. Certificates renew in one place rather than on twenty servers.
Caching. Serve static assets and cacheable responses without touching application servers at all.
Compression. Gzip or Brotli applied centrally, so no application implements it.
Security. Application servers get private IPs unreachable from the internet. The only exposed surface is the proxy, which can also enforce rate limits and filter malicious requests.
Routing. One public hostname fans out to many internal services by path.
Hiding your topology. Clients see one endpoint. Behind it you can split a service in two, move it to another host, or change its port, and nobody outside notices.
So how is that different from a load balancer?
This is the follow-up question, and the honest answer is that they overlap heavily — most tools do both.
The useful distinction is intent:
- A load balancer exists to distribute traffic across several identical servers. Its core concern is which one.
- A reverse proxy exists to be an intermediary. Its core concerns are TLS, caching, routing and protection. It is useful even with one backend server.
That last point is the clarifying test. A reverse proxy in front of a single server is completely sensible — you still want TLS termination and caching. A load balancer in front of a single server does nothing.
In practice nginx, HAProxy and cloud application load balancers are both, and nobody minds. Understand the two roles; do not fuss about the label.
The detail that causes real bugs
Once a reverse proxy is in front of your application, every request appears to come from the proxy. Your application sees the proxy's IP, not the user's.
This silently breaks anything that depends on client identity — rate limiting per user, geographic logic, abuse blocking, audit logs.
The convention is that proxies add headers recording the original client:
X-Forwarded-For: 203.0.113.45, 70.41.3.18
X-Forwarded-Proto: https
X-Forwarded-Host: example.comX-Forwarded-Proto matters too. Since the proxy terminates TLS, your application sees plain HTTP and may conclude the connection is insecure — generating http:// links or refusing to set Secure cookies. Configure your framework to trust the forwarded protocol header.
What to put on the proxy, and what not to
The reverse proxy is genuinely useful for cross-cutting concerns, and genuinely bad as a place for business logic.
Good on the proxy: TLS, compression, static file serving, response caching, rate limiting, request size limits, header manipulation, path routing.
Bad on the proxy: authorisation decisions, business rules, anything requiring database lookups. Configuration languages are awkward to test, hard to review, and invisible to developers debugging application behaviour. Logic that lives in an nginx config is logic nobody will find.
Check your understanding
Common mistakes
Trusting forwarded headers from anywhere. Only trust them from proxies you control; strip them from inbound public traffic.
Mismatched timeouts. If the proxy times out at 30 seconds and the application at 60, the proxy abandons requests the backend is still working on — wasting effort and confusing logs.
Buffering surprises. Some proxies buffer entire responses by default, which breaks streaming and server-sent events. Disable buffering for those routes.
Forgetting the proxy is a single point of failure. Same reasoning as the load balancer: run more than one.
Silent request size limits. Proxies often cap upload size by default, producing confusing failures on large files that work fine locally.
Practice
A security review asks you to add a proxy so that every outbound call from your services to third-party APIs is logged and restricted to an approved list of destinations. Which kind of proxy is this, and what breaks the day you turn it on?
Write your own answer first, on paper or in a note. Then compare.
Show a hint
Ask who is being protected, and what your services currently assume about reaching the internet.
Show a strong answer
This is a forward proxy — it acts on behalf of your services (the clients) and controls where they may go. Reverse proxies protect servers from clients; this is the opposite direction.
What breaks on day one:
- Anything that does not honour proxy configuration. Language HTTP clients usually respect proxy environment variables; SDKs, native libraries and anything speaking a non-HTTP protocol frequently do not. Those calls bypass the proxy silently, so your logging is incomplete in a way that looks like success.
- TLS. To inspect or log destinations beyond the hostname, the proxy must terminate TLS, which means your services must trust the proxy's certificate authority. Anything with pinned certificates will refuse to connect, and the error will look like a network failure rather than a policy one.
- Every destination you forgot. Package registries during a build, time servers, telemetry endpoints, OAuth token endpoints. The allow-list will be wrong on the first day, and each omission surfaces as a timeout somewhere unrelated.
- Latency and a new single point of failure. Every outbound call now has an extra hop, and the proxy failing takes out all third-party integrations at once.
How to turn it on safely: run it in log-only mode first, with no blocking, and use the logs to build the allow-list from observed traffic. Then enforce.
Your team puts response caching, authentication, rate limiting and request logging on the reverse proxy. A colleague argues that authentication belongs in the application instead. Make the strongest case for each position, then decide.
Write your own answer first, on paper or in a note. Then compare.
Show a hint
Ask what happens when the proxy is bypassed, and what the proxy can know about a user.
Show a strong answer
The case for authentication on the proxy: it rejects unauthenticated traffic before it reaches the application, which protects the origin from load and means every service behind it gets authentication for free without each team reimplementing it. Signature checking and token validation are cheap, uniform and easy to get subtly wrong in dozens of places.
The case for authentication in the application: the proxy can verify that a token is valid, but only the application knows whether this user may see this record. Object-level authorisation is inherently application logic. Worse, if the proxy is the only thing enforcing identity, anything that reaches the application by another path — an internal caller, a misrouted rule, a debugging port — is unauthenticated. That makes the proxy a security boundary that a single misconfiguration removes.
The decision: both, with different jobs. Put authentication (is this a valid token?) on the proxy, because it is uniform and it sheds load early. Keep authorisation (may this user do this to this object?) in the application, because it needs domain knowledge the proxy does not have. And have the application verify the token itself rather than trusting a header — defence in depth costs little and removes the single-misconfiguration failure.
Caching, rate limiting and logging stay on the proxy without argument: all three benefit from being early and uniform, and none of them needs to know what a record means.
Key takeaways
- Forward proxy acts for the client and hides the client; reverse proxy acts for the server and hides the server.
- Forward proxies show up in corporate filtering, VPNs and shared caches; the client is deliberately configured to use one.
- A reverse proxy is where TLS termination, caching, compression, routing and rate limiting belong — so no service reimplements them.
- A load balancer is a reverse proxy focused on choosing between identical backends; a reverse proxy is still useful with a single server.
- Behind a proxy your app sees the proxy's IP, which breaks per-client logic. Use
X-Forwarded-For, but count back from the right — the leftmost values are user-controlled. - Keep cross-cutting concerns on the proxy and business logic out of it.
Next: when the intermediary starts making decisions per API and per client rather than per request, it becomes something more specialised.
Further reading
- RFC 9110, HTTP Semantics, section 3.7 — the definition of intermediaries and their obligations.
- RFC 7239, Forwarded HTTP Extension — the standard header for preserving the original client address.
- RFC 9111, HTTP Caching — what a shared cache is permitted to store and reuse.
- Roy Fielding, "Architectural Styles and the Design of Network-based Software Architectures" (doctoral dissertation, 2000), chapter 5 — layered systems and why intermediaries are possible at all.
- Michael Nygard, Release It!, second edition (Pragmatic Bookshelf, 2018) — proxies as a place to put stability patterns.