Reverse Proxy β Part 1: Foundations & Core Concepts
maang.io System Design Series
What is this?
Picture a grand hotel. You walk up to the front desk and talk to the concierge. You ask for room service, a taxi, a dinner reservation β and the concierge handles all of it. You never march into the kitchen to talk to the chef, you never knock on the housekeeping office, and you certainly never see the staff roster. As far as you're concerned, the concierge is the hotel. Behind that desk, an entire building of people is doing the actual work, but they're shielded from you. The concierge represents them, routes your requests to the right person, and quietly handles anything you're not supposed to deal with directly.
A reverse proxy is that concierge, for servers. Clients send every request to one address β the proxy β and the proxy decides which backend server actually does the work, hides those servers from the outside world, and handles the chores nobody wants to repeat ten times (encryption, caching, security). To a client, a fleet of backend services looks like one calm, single endpoint.
The one-line idea: a reverse proxy is a server that stands in front of your backends and speaks to clients on their behalf β so the outside world only ever talks to one well-guarded front door.
That phrase "on their behalf" is the whole game, and it's the source of the single most common point of confusion in this entire topic. Let's kill that confusion right now.
1. Forward proxy vs reverse proxy β the #1 confusion
Both are "proxies" β a middleman that sits between two parties and relays traffic. The difference is whose side the middleman is on. Burn this distinction into memory, because interviewers love to test it.
- A forward proxy acts for the client. It sits in front of users and reaches out to the wider internet on their behalf. Think of a corporate office where every employee's web traffic flows through one company gateway that filters, logs, and caches it. The websites being visited have no idea who the real user is β they just see the proxy. The proxy represents the people making requests.
- A reverse proxy acts for the server. It sits in front of backends and receives requests from the outside world on their behalf. Clients have no idea how many servers exist behind it β they just see the proxy. The proxy represents the people answering requests.
The trick to never mixing them up: ask "which side is being hidden?" A forward proxy hides the clients from the servers they visit. A reverse proxy hides the servers from the clients that visit them. Same box, opposite direction β and the word "reverse" literally just means "the proxy is on the reverse end of the connection from where you'd first expect."
π‘ A VPN or a school's content filter is a forward proxy. NGINX sitting in front of your web app, or Cloudflare in front of a website, is a reverse proxy. For the rest of this series, "proxy" means reverse proxy unless we say otherwise.
2. Why we even need one
Expose your backend servers directly to the internet and you sign up for a pile of problems β and they compound as you grow.
- Your servers are naked to the internet. Every backend needs its own public IP, its own firewall rules, its own defenses. Every machine is an attack surface, and your internal topology is on full display.
- Every server repeats the same chores. Each one has to terminate TLS, manage certificates, enforce rate limits, gzip responses, and log requests β the same boring infrastructure code copied everywhere.
- There's no single place to route, cache, or observe. Want to send
/api/*to one service and/images/*to another? Want to cache hot responses once for everyone? With direct exposure, there's nowhere to put that logic.
Put a reverse proxy in front and all of it collapses into one tidy layer:
The deep idea here is the same one that powers the load balancer (see the Load Balancer chapter): a clean boundary between how clients reach you and how your service is actually built. Clients get one stable address. Backends get to be private, simple, and swappable. The proxy absorbs the messy middle. Doing a chore once, at the door, beats doing it in every backend forever.
3. Core responsibilities β what a reverse proxy actually does
A reverse proxy isn't one feature; it's a bundle of jobs that all make sense to do at the front door. Here are the big five.
3.1 Routing
Read the incoming request and forward it to the right backend β by path (/api/* β the API service), by hostname (shop.example.com β the storefront), or by header. This is what lets a single public endpoint sit in front of an entire fleet of microservices.
3.2 Load balancing
Spread requests across a pool of identical backends so no single one gets crushed. If this sounds exactly like a load balancer β it is. A load balancer is a specialized reverse proxy whose main job is distribution. We'll untangle the overlap carefully in Part 2; for now, just know that "reverse proxy" is the broader category and "load balancer" is one of the hats it can wear.
3.3 TLS termination
Every HTTPS connection opens with a TLS handshake β a cryptographic "let's agree on a secret" dance β and somebody has to manage certificates. Do that once, at the proxy: it decrypts incoming traffic and hands plain HTTP to backends over the trusted internal network. One place to renew certs, one place to enforce HTTPS. (Same trick the load balancer uses; we go deep on it in Part 2.)
3.4 Caching
Store static or semi-static responses right at the proxy. When a thousand users ask for the same homepage or the same product image, the proxy answers most of them from memory and never bothers the backend. This is the same mechanism a CDN uses β a CDN is essentially a globally-distributed reverse-proxy cache sitting close to users.
3.5 Security & hiding the origin
The proxy is the only thing exposed to the internet, so it's the natural bouncer: enforce rate limits, block bad actors, strip malicious headers, and β critically β hide your origin servers so attackers can't even find them to attack. Your real backends live on a private network with no public address.
4. A concrete example: nginx as a reverse proxy
None of this is abstract. Here's a minimal but real nginx config that turns it into a reverse proxy for a backend app:
# Define the pool of backend servers
upstream app_backend {
server 10.0.0.11:8080;
server 10.0.0.12:8080;
}
server {
listen 443 ssl;
server_name example.com;
# TLS termination happens here β backends speak plain HTTP
ssl_certificate /etc/ssl/example.crt;
ssl_certificate_key /etc/ssl/example.key;
location /api/ {
proxy_pass http://app_backend; # route /api/* to the app pool
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr; # tell the backend the client's real IP
}
}
Read top to bottom, this is the concierge in code. upstream is the staff roster (hidden from guests). listen 443 ssl plus the certificate lines are TLS termination β clients connect over HTTPS, backends receive plain HTTP. location /api/ is routing. proxy_set_header X-Real-IP solves a subtle gotcha: because the backend only ever sees the proxy's IP, you have to forward the real client IP yourself, or every log and rate-limiter thinks all traffic comes from one machine.
β οΈ That
X-Real-IP(and its cousinX-Forwarded-For) is a classic source of bugs. The moment you put any proxy in front of your servers, the backend's notion of "the client's IP" becomes the proxy's IP unless you explicitly pass the original along. Geolocation, abuse-blocking, and audit logs all break quietly if you forget.
5. Where you'll actually meet reverse proxies
This pattern recurs everywhere once you know its shape:
- In front of a web app. The bread and butter β NGINX or a cloud proxy terminates TLS and routes to your app servers.
- As a CDN edge. Cloudflare, Fastly, and CloudFront are reverse proxies distributed across the globe, caching content close to users and shielding your origin.
- As an API gateway. An API gateway is a reverse proxy with extra brains β auth, versioning, request transformation (more in Part 2).
- As a Kubernetes ingress. An ingress controller is just a reverse proxy for your cluster, mapping hostnames and paths to internal services.
- As a service-mesh sidecar. A little proxy (often Envoy) sits next to every service, handling routing, retries, and TLS for service-to-service calls.
A single request often passes through several of these in a row β a CDN edge, then a regional gateway, then an ingress β before it ever reaches your code.
6. The big four, side by side
You'll hear four names that all live near the front door. They overlap, which is exactly why they confuse people. Here's the quick mental map (we'll formalize the reverse-proxy-vs-load-balancer-vs-API-gateway comparison in Part 2):
| Box | One-line job | Relationship |
|---|---|---|
| Reverse proxy | The general "front door" that represents your servers | The umbrella concept |
| Load balancer | Spread traffic across identical backends | A reverse proxy specialized for distribution |
| API gateway | A reverse proxy with auth, versioning, transformation | A reverse proxy specialized for APIs |
| CDN | Cache content globally, near users | A reverse proxy specialized for edge caching |
The honest summary: reverse proxy is the parent category, and the other three are specializations of it. Each adds a focus on top of the same core idea β sit in front of servers and act on their behalf.
Key takeaways
- A reverse proxy is a server that sits in front of your backends and speaks to clients on their behalf β the single guarded front door to your system.
- Forward proxy acts for the client; reverse proxy acts for the server. Ask "which side is being hidden?" β clients (forward) or servers (reverse).
- Its core jobs are routing, load balancing, TLS termination, caching, and security/origin-hiding β chores done once at the door instead of repeated in every backend.
- A load balancer is a specialized reverse proxy, and so are API gateways and CDNs β reverse proxy is the parent concept they all descend from.
- The deepest gift, shared with the load balancer, is a clean boundary between how clients reach you and how your service is built β which keeps backends private, simple, and swappable.
Next up, Part 2 opens the box: the internal processing pipeline, the load-balancing algorithms it uses to pick a backend, multi-level caching, the security stack, and a precise comparison of reverse proxy vs load balancer vs API gateway.