What Sits in Front of Almost Every Web Service
Welcome
If you type example.com into a browser, you almost never reach the machine that actually runs the application. You reach a machine that forwards the request to one that does. That forwarding machine carries a name: a reverse proxy.
This lesson teaches what a reverse proxy does, why almost every public web service hides behind one, & what three jobs the edge layer handles at the same time.
By the end you will understand:
- The difference between a client, a proxy, & an origin
- Why a proxy in front of an origin protects, scales, & lets you swap pieces without anyone noticing
- The three jobs a reverse proxy handles at once: hiding the origin, terminating TLS, & distributing load across replicas
- How a request travels from browser to proxy to upstream & back, hop by hop
By the end you will reason confidently about proxy placement, separation of concerns at the edge, & why a stateless proxy tier multiplies cheaply while a single origin does not.
Forward Proxy vs Reverse Proxy
Two Proxy Directions
Both kinds of proxy stand between two parties & relay traffic. They differ in which party they represent.
Forward proxy: stands in front of a group of clients. The clients know about a proxy; an outside server sees a proxy address, not a client address. Corporate egress proxies, content filters, & SOCKS proxies fit this pattern.
Reverse proxy: stands in front of a group of servers. The outside world (clients) talks to a proxy address; clients have no idea a real server hides behind it. Almost every public web service uses one.
Mnemonic: a forward proxy hides clients from servers. A reverse proxy hides servers from clients.
Why care about which way? The job, the failure modes, & the security boundary all differ. A forward proxy worries about who its users contact; a reverse proxy worries about who contacts its servers.
A client sending traffic through both kinds at once travels: client -> forward_proxy -> internet -> reverse_proxy -> origin.
Why So Much Lives at the Edge
The Edge Layer Earns Its Keep
A reverse proxy carries three jobs at the same time. Any one of them justifies the layer; carrying all three at the same address explains why almost every production web architecture looks the same shape at the front.
Job 1: Hide the origin. The proxy answers on a public IP. Backends sit on private IPs the internet cannot reach. An attacker who wants to hit the origin must first compromise the proxy.
Job 2: Terminate TLS. The proxy holds the certificate for example.com & decrypts incoming HTTPS requests. Backends speak plain HTTP (or simpler internal TLS) to the proxy across a trusted network segment. Certificate rotation, renewal, & cipher policy all live in one place.
Job 3: Distribute load. The proxy chooses which backend handles each request. Backends behind one proxy form a pool; the proxy picks one per request using a strategy (round-robin, least-connections, hash on a header). Adding capacity means adding a backend to the pool, not telling every client a new address.
Each job is a small program. Together they explain why a tier as simple as 'Caddy in front of a Python app' carries more design weight than the Python app itself.
Designing for All Three
Your team runs a small API on a single Python process listening on port 8000 on a single VM. Traffic has grown enough that one VM cannot keep up, & a security review flagged that the VM has a public IP & runs its own TLS certificate.
You decide to put a reverse proxy in front. Sketch the layout: where does DNS point, where does the certificate live, how does load reach the backends, & what changes about the original VM?
Swap a Component Without Anyone Noticing
Indirection Buys Freedom
An old computer-science adage holds: every problem can be solved by adding a layer of indirection (except the problem of too many layers of indirection). The reverse proxy is one of the most useful indirections in distributed systems.
What it buys you:
- Swappable backends. Move the application from Python to Go? Migrate from one datacenter to another? Roll out a new version with zero downtime? Each one happens behind a stable public address. Nothing changes for users.
- Independent scaling. The proxy tier scales on bandwidth & CPU at the TLS layer. The backend tier scales on application work. Each grows on its own axis because they live on different machines.
- Fault containment. A bad deploy on the backend does not knock out the public address. The proxy stays up; you push a fix or roll back; the world reconnects when the backend recovers.
- Cross-cutting concerns in one place. Rate limiting, geo-blocking, request logging, header rewriting, caching, response compression: all live on the proxy. Backend code stays focused on the application.
Without the proxy every one of these problems must live inside the application process. With the proxy they live at one layer that one team owns.
The cost: another layer to operate. Mature teams accept the cost because the proxy tier itself runs stateless & scales horizontally; replacing one proxy with two requires no coordination.
A Blue/Green Deploy Through the Proxy
Your team runs version 1 of the API on three backend VMs (blue pool) behind a reverse proxy. You want to deploy version 2 with the ability to roll back in under thirty seconds if something goes wrong.
You launch three new backend VMs (green pool) running version 2, side by side with the blue pool, but you do not yet route any traffic to them.
From Browser to Backend & Back
Follow One Request End to End
Trace a single HTTPS GET of https://api.example.com/users/42 through a reverse proxy in front of a backend pool.
Hop 1: DNS resolution. The browser asks a resolver for api.example.com. The resolver returns the proxy's public IP (say, 203.0.113.10). The browser opens a TCP connection to 203.0.113.10:443.
Hop 2: TLS handshake. The proxy presents its certificate for api.example.com. The browser validates the certificate, the two sides agree on a session key, & the encrypted channel opens.
Hop 3: HTTP request inside TLS. The browser sends GET /users/42 HTTP/1.1\nHost: api.example.com\n.... The proxy decrypts the request bytes.
Hop 4: Backend selection. The proxy consults its upstream pool for api.example.com & picks one backend (say 10.0.0.21:8000) using its load-balancing strategy.
Hop 5: Upstream request. The proxy opens (or reuses) a plain HTTP connection to 10.0.0.21:8000 & forwards the request. The proxy may rewrite headers along the way: add X-Forwarded-For: <client-ip>, set Host: correctly, strip hop-by-hop headers like Connection.
Hop 6: Backend processing. The backend application reads the request, queries its database, builds a JSON response.
Hop 7: Upstream response. The backend sends the response back to the proxy as plain HTTP.
Hop 8: Edge response. The proxy may rewrite or compress the response, encrypts it back through the TLS session, & sends it to the browser.
Hop 9: Connection lifecycle. The TLS session typically stays open for the next request (HTTP/2 multiplexes many requests on one connection). The proxy-to-backend connection often pools for reuse.
Every public web service follows some variant of this shape. Knowing the hops lets you reason about where latency accumulates, where logging belongs, & where a failure can hide.
Where Did the Time Go?
A user complains the API feels slow. You measure & find the request takes 850 ms end to end. Server logs on the backend show the application served the request in 40 ms. The proxy logs show the proxy spent 50 ms on its side of the work (TLS handshake + routing + response writing).
Design a Minimal Edge for a New Service
Synthesis
You have learned the difference between a forward & reverse proxy, the three jobs a reverse proxy handles at once, why hiding the origin pays dividends every time you need to change something, & how a request flows hop by hop through the edge.
Now apply it.
A small team plans to launch a new service called notes.example.com. Users will read & write personal notes. The team will run two backend VMs at launch & expects to scale to ten over the next year. They want HTTPS for users, gradual rollout for new versions, & no public exposure of backend IPs.
Where This Course Goes Next
Where This Course Goes Next
This lesson established the shape of the edge layer. Four more lessons in this course build on it:
- Stateless Horizontal Scaling: why a proxy tier (& the backends behind it) multiplies cheaply, & the math for sizing replica counts under surge.
- Ingress / Egress Separation: why a single proxy box that handles both incoming & outgoing traffic eventually fails in surprising ways, & how to split the layers.
- Failure Modes & Blast Radius: how a single config change cascades into an outage, & how to write blameless action items that prevent recurrence.
- Observability & Capacity: what to measure at the edge so you find out something is broken before users do.
Each lesson stands alone. Taken together they give you a working mental model of a web-scale fleet.
Companion lesson: geometry_of_proxies_and_origins recasts everything in this lesson as a directed graph & explores what graph theory tells you about a request path.
Well done. Onward.