← Learn··Updated 31 May 2026·5 min read

What a reverse proxy actually does

A reverse proxy is the single front door that sits in front of your backends — clients only ever talk to it. This explains routing, TLS termination, load balancing, caching, and how it differs from a forward proxy.

Networking
#networking
#reverse-proxy
#http
#ai-assisted

level:Beginner

If you run more than one web service, sooner or later you hit the same wall: both want port 443, both want a certificate, and the public internet only gives you one IP address. A reverse proxy is the standard answer. It is one of those pieces of infrastructure that sounds intimidating and turns out to be simple once you see the shape of it. This article explains what a reverse proxy is, why you would put one in front of your services, and what it actually does on each request — before you touch any config file.

What a reverse proxy is

A reverse proxy is a server that sits in front of one or more backend services and handles every inbound request on their behalf. A client — a browser, a mobile app, another service — connects to the proxy, never directly to the backend. The proxy reads the request, decides which backend should handle it, forwards it there, waits for the response, and relays that response back to the client.

The key idea is that the client only ever talks to the proxy. As far as the visitor's browser is concerned, the proxy is the website. The real services can live on different machines, on private addresses, in containers, or down an encrypted tunnel — the client neither knows nor cares. This indirection is the whole point: it lets you change, move, scale, or hide the backends without the client ever noticing.

ℹ️ Note — "Proxy" just means a stand-in that acts on someone else's behalf. The "reverse" part is about who it stands in for, which is exactly what the next section pins down.

Forward proxy vs reverse proxy

Both are proxies — an intermediary that requests pass through — but they sit at opposite ends of the conversation and serve opposite owners.

A forward proxy sits in front of clients. It acts on behalf of the people making requests. A company might route all employee browsers through a forward proxy to filter or log outbound traffic; a VPN or Tor works in this family. The proxy knows who you are; the destination websites do not know the proxy exists — they just see traffic arriving.

A reverse proxy sits in front of servers. It acts on behalf of the services receiving requests. The clients do not know the proxy is there — they think they are talking directly to the website. The backends are the ones being represented and protected.

The difference is purely directional: a forward proxy hides the client from the server, a reverse proxy hides the servers from the client.

flowchart LR
    subgraph Forward["Forward proxy — acts for clients"]
        C1[Client] --> FP[Forward<br/>proxy] --> I1((Internet<br/><i>any site</i>))
    end
    subgraph Reverse["Reverse proxy — acts for servers"]
        I2((Internet<br/><i>any client</i>)) --> RP[Reverse<br/>proxy] --> B1[Your<br/>backends]
    end

Same machine in the middle, but the forward proxy fronts the clients and the reverse proxy fronts the servers.

What a reverse proxy actually does

On its own, "forwarding requests" sounds pointless. The value is in everything the proxy can do while it forwards. Here are the jobs a reverse proxy typically takes on.

A single public entry point

This is the foundation everything else builds on. Instead of exposing each service to the internet directly — each needing its own port, its own certificate, its own hardening — you expose one thing: the proxy. It listens on the standard ports (80 and 443) and is the only process facing the public. Your backends listen on private addresses or local ports that nothing outside can reach. One door to defend, one place to apply logging, rate limits, and access rules.

Routing by hostname and path

A single proxy can serve many sites. It inspects each request — chiefly the Host header (the hostname the browser asked for) and sometimes the URL path — and forwards it to the matching backend.

  • app.example.dev goes to the app server on :8080
  • api.example.dev goes to the API service on :9000
  • example.dev/images/... goes to a static file server

All three hostnames resolve to the same public IP and hit the same proxy. The proxy is what tells them apart. This is how one small server can host dozens of distinct sites.

TLS termination

HTTPS connections are encrypted with TLS. Terminating TLS means the proxy is the place where that encryption ends: the client opens an encrypted connection to the proxy, the proxy decrypts the request, and the onward trip to the backend happens over a network you already trust (localhost, a private LAN, or an encrypted tunnel). The backends can speak plain HTTP and never deal with certificates at all.

This centralises certificate management. Instead of installing and renewing a certificate on every service, you manage them in one place. Some proxies automate this end to end — see Caddy: reverse proxy and automatic HTTPS for a proxy that obtains and renews Let's Encrypt certificates on its own.

💡 Tip — Because TLS terminates at the proxy, the backend no longer sees the client's real IP or the original protocol directly. Reverse proxies fix this by adding headers like X-Forwarded-For and X-Forwarded-Proto so the backend can still know who connected and whether it was HTTPS.

Load balancing

When one backend is not enough, you run several identical copies and let the proxy spread requests across them. The proxy picks a backend for each request — round-robin, least-connections, or another policy — and can run health checks so it stops sending traffic to an instance that has stopped responding. To the client it is still one address; behind it, the proxy is quietly balancing the load and routing around failures.

Caching and compression

A reverse proxy can store copies of responses it has already fetched and serve them again without bothering the backend — useful for content that does not change on every request. It can also compress responses (gzip, Brotli) before sending them, so the proxy does that CPU work once at the edge instead of in every backend. Both reduce backend load and speed up the client.

⚠️ Warning — Caching is powerful and easy to get wrong. Cache something user-specific or private by accident and you can serve one user's page to another. Only cache responses you are sure are safe to share, and respect the backend's cache-control headers.

Putting it together

Here is the shape of a typical setup: visitors arrive at one public address, the proxy terminates TLS and routes by hostname, and each request lands on the right backend.

flowchart TD
    V((Visitor<br/><i>browser</i>)) -->|HTTPS :443| RP[Reverse proxy<br/>TLS terminates here]
    RP -->|app.example.dev| A[Web app<br/>:8080]
    RP -->|api.example.dev| B[API service<br/>:9000]
    RP -->|/static/*| C[Static files<br/>:8081]

One public entry point; the proxy decrypts, inspects the request, and forwards it to the matching backend over the private network.

Common reverse proxies

Several mature tools do this job. They overlap heavily; the differences are in configuration style and where they shine.

  • Caddy — simple config, automatic HTTPS out of the box. The easiest place to start; covered in Caddy: reverse proxy and automatic HTTPS.
  • Nginx — the long-standing default. Extremely fast and battle-tested, also widely used as a plain web and static-file server. Configuration is more manual.
  • Traefik — built for dynamic, container-native environments. It discovers backends automatically from Docker labels or Kubernetes resources rather than from a static file, which is why it is the default ingress controller in k3s.
  • HAProxy — focused on high-performance load balancing, including raw TCP, not just HTTP. Common in front of large clusters.

Where this fits in practice

A reverse proxy shows up in two places in the homelab world, and both are worth seeing:

  • At the edge, on a public server, as the single front door to everything you self-host. The Expose your homelab to the internet track builds exactly this, with Caddy terminating TLS and forwarding into a private tunnel.
  • Inside a cluster, as the ingress layer. In Kubernetes the reverse proxy is the ingress controller; Routing into k3s from the edge shows Traefik playing the in-cluster reverse proxy that fans requests out to services, and Kubernetes ingress with Traefik goes deeper on how those routing rules are defined.

Once you have the mental model — one front door, routing by hostname, TLS terminating at the edge, backends hidden behind it — every one of those tools is just a different way of writing down the same idea.