Sep 10, 2026
Proxy vs. Reverse Proxy: What's the Difference and Why It Matters
The word "proxy" gets used for two very different things depending on which side of the connection it sits on. A proxy (forward proxy) sits in front of clients; a reverse proxy sits in front of servers. Mixing the two up is common, but the direction of traffic — and what problem each one solves — is completely different.
Forward proxy: standing in for the client
A forward proxy makes requests on behalf of a client. Instead of your browser talking directly to a website, it talks to the proxy, and the proxy talks to the website for you. The website only ever sees the proxy's IP address, not yours. This is why companies route employee traffic through a proxy for content filtering or caching, and why some people use one to mask their own location.
Concretely, the client sends a request naming the destination URL, addressed to the proxy itself:
GET http://example.com/index.html HTTP/1.1
Host: example.com
sent to the proxy's address (corp-proxy:8080). The proxy opens its own connection to example.com, fetches the page, and relays the response back to the client. example.com sees the proxy's IP as the requester, never the client's.
Reverse proxy: standing in for the server
A reverse proxy does the opposite: it sits in front of one or more backend servers and receives requests on their behalf. The client only ever talks to the reverse proxy — it doesn't know, and doesn't need to know, which actual server handled the request behind it.
The client sends a normal-looking request to the public hostname:
GET /api/users HTTP/1.1
Host: api.example.com
The reverse proxy receives this, matches api.example.com against its rules, then makes its own request to the real backend:
GET /api/users HTTP/1.1
Host: 10.0.0.6
and returns that response to the client as if it had generated it. The client never addressed 10.0.0.6 directly and doesn't know it exists.
How it decides where to send a request
A reverse proxy matches each incoming request against rules you configure, most commonly by hostname or by path:
api.example.com → API server (10.0.0.6:80)
app.example.com → app server (10.0.0.5:80)
example.com/api/* → API server (localhost:8000)
example.com/* → frontend (localhost:3000)
In a Caddyfile, host-based routing looks like this:
api.example.com {
reverse_proxy 10.0.0.6:80
}
app.example.com {
reverse_proxy 10.0.0.5:80
}
A visitor requesting api.example.com never sees or knows about 10.0.0.6 — the reverse proxy handles that mapping invisibly, on every request.
This isn't a Caddy-only trick. Apache does the same job via mod_proxy:
ProxyPass /api/ http://10.0.0.6:8000/
ProxyPassReverse /api/ http://10.0.0.6:8000/
Nginx, HAProxy, and most web servers support reverse proxying too — none of them are reverse-proxy-exclusive. The difference between them is mostly configuration style and what else they're good at: Apache and Nginx also serve static files and run app modules directly, Caddy defaults to automatic HTTPS, and HAProxy specializes in load balancing.
Why infrastructure is built this way
Putting a reverse proxy in front of backend servers means those servers never need to be directly reachable from the internet — only the proxy does. It also gives you a single place to handle SSL/TLS termination, load balancing across multiple backend instances, and caching, instead of building that into every backend service separately.
Why this matters for monitoring
When you monitor a URL like api.example.com, you're checking the reverse proxy's response — not necessarily the specific backend instance that served it, especially if there's more than one behind a load balancer. That's usually exactly what you want: it reflects what a real visitor experiences. But if a specific backend instance is unhealthy while others behind the same proxy are fine, a single monitor hitting the proxy may not catch it — worth keeping in mind when deciding what to monitor directly versus through the proxy.