Networking admin · Part 10 of 12

Reverse proxies, the front door pattern

May 14, 20257 min read#networking#operations#networking-admin

Reverse proxies, the front door pattern

A reverse proxy sits in front of your real servers, taking incoming requests from the public internet and passing them to your backend. Almost every serious web service in 2026 has one. Most users have no idea they exist.

This article explains what they are, why they're useful, and the patterns they enable.

Forward vs reverse

The word "proxy" is overloaded. Two main flavors:

Forward proxy. Sits between users and the internet, on the user's side. Users configure their browsers to go through the proxy. The proxy makes requests on the user's behalf. Used for content filtering, anonymity, caching, corporate networks. The destination doesn't know the user is using a proxy.

Reverse proxy. Sits between users and a service, on the service's side. Users connect to the proxy, thinking it's the service. The proxy forwards requests to the real backend. The user doesn't know the proxy exists.

We're talking about reverse proxies. Public-facing services use them.

The basic pattern

Without a reverse proxy:

request

routes by hostname, path,
or header

also handles

User
browser, app, etc

Reverse proxy
nginx, HAProxy, Envoy

Backend 1
app.example.com

Backend 2
api.example.com

Backend 3
cdn-origin.example.com

TLS termination
caching
rate-limiting
auth gate
logging

With a reverse proxy:

User → public internet → Reverse proxy → Application server

The reverse proxy is the public face. The application server might be on a private network, unreachable from the outside.

This indirection enables many things.

Things reverse proxies do

The list is longer than people realize:

TLS termination. Proxy handles HTTPS. The backend speaks plain HTTP. Reduces CPU load on backends, simplifies certificate management (one place to renew certs).

Load balancing. Proxy distributes requests across multiple backend servers. We have a dedicated article on this.

Caching. Proxy stores frequent responses, serves them without bothering the backend. Reduces backend load.

Compression. Proxy compresses responses before sending to users.

Rate limiting. Proxy rejects excessive requests from individual IPs before the backend has to handle them.

Authentication offload. Proxy validates auth tokens, passes only authenticated requests to backends.

WebSocket and HTTP/2 termination. Proxy translates between protocol versions, letting backends speak whichever protocol they prefer.

Header manipulation. Proxy adds, removes, or rewrites HTTP headers.

URL rewriting. Proxy maps public URLs to internal endpoints. https://api.example.com/v2/users might become http://internal-user-service:8080/users.

Security filtering. Proxy enforces WAF rules, blocks suspicious patterns before they reach backends.

Logging. Proxy logs requests centrally, regardless of backend.

That's a lot. Hence the popularity.

Common reverse proxy software

nginx. The world's most-deployed web server, used heavily as a reverse proxy. Battle-tested, fast, configurable. The "default" choice for most setups.

HAProxy. Specialized for load balancing and high concurrency. Less Swiss-army-knife than nginx; more focused. Widely used in front of large web infrastructures.

Apache HTTPD with mod_proxy. Older but still widely used. Often where legacy setups live.

Envoy. Modern reverse proxy designed for microservices. Heavily used in container-based architectures (Kubernetes, service meshes).

Caddy. Modern, automatic HTTPS, simple config. Popular for small to mid sites.

Traefik. Container-native, auto-discovers services in Docker / Kubernetes. Popular for ops-light setups.

Each has its sweet spot. nginx is the safe default. HAProxy if load balancing is the primary need. Caddy if simplicity is the goal.

A simple nginx example

A common reverse proxy config:

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

What this does:

  • Listens on port 443 (HTTPS).
  • Handles TLS termination with the specified cert.
  • Forwards all requests to a backend on 127.0.0.1:8080 (plain HTTP).
  • Passes useful headers so the backend knows the original host, the real client IP, and the original protocol.

The backend application doesn't need to handle HTTPS, doesn't see external traffic directly, and can be on a private network.

The X-Forwarded-For pattern

A subtle but important detail: backends usually want to know the real client IP, not the proxy's IP.

When the proxy forwards a request, the TCP source IP from the backend's perspective is the proxy's. So the backend needs another mechanism to learn the original client.

The convention: the proxy adds an X-Forwarded-For header containing the client's IP. The backend reads this header to determine the client.

For chains of proxies, X-Forwarded-For is a comma-separated list:

X-Forwarded-For: 192.0.2.42, 198.51.100.5

The original client is first; each subsequent proxy appends. The backend trusts whichever it considers reliable.

The PROXY protocol is a binary alternative that conveys client IP at the TCP layer, without modifying HTTP. Used when the backend isn't HTTP (e.g., game servers behind a proxy).

What "real client IP" loses without X-Forwarded-For

Without the header (or PROXY protocol):

  • Backends see all requests as coming from the proxy's IP.
  • Geographic logging is wrong.
  • IP-based rate limiting is wrong.
  • Login attempts all appear to come from one IP, defeating most fraud detection.

This is why setting up X-Forwarded-For correctly is essential.

The proxy and backend often talk over a private network. But on shared infrastructure, you might:

  • Use a private VLAN.
  • Use Tailscale or WireGuard.
  • Use mutual TLS (mTLS) so backend only accepts connections from the legit proxy.

For high-security environments, mTLS between proxy and backend is best. For ordinary deployments, a private network is usually enough.

CDN as a reverse proxy

A CDN is a globally-distributed reverse proxy with caching. Cloudflare, Fastly, Akamai all reverse-proxy your site.

From the user's perspective:

  • They connect to a CDN edge.
  • The edge handles TLS.
  • The edge serves cached content if available.
  • Otherwise, fetches from your origin (a backend), caches, returns.

This is just a reverse proxy with extra steps (geographic distribution, caching, edge logic).

The lesson: "reverse proxy" and "CDN" aren't different things. CDNs are a specific deployment of reverse proxies at scale.

When you might not need a reverse proxy

For some setups:

  • Small internal services where one server handles everything.
  • Direct UDP-based protocols (most games) where reverse proxies don't naturally fit.
  • Specific protocols (some legacy databases) that don't tolerate proxying.

For these, direct access to the backend is fine. The reverse-proxy pattern is mostly for HTTP-based services.

For game servers specifically, the analog of a reverse proxy is more often a TCP/UDP proxy like Velocity (for Minecraft) or BungeeCord, which forward traffic without the HTTP-specific features of nginx.

A real-world architecture

A modern web service might look like:

request

routes by hostname, path,
or header

also handles

User
browser, app, etc

Reverse proxy
nginx, HAProxy, Envoy

Backend 1
app.example.com

Backend 2
api.example.com

Backend 3
cdn-origin.example.com

TLS termination
caching
rate-limiting
auth gate
logging

Each layer adds something. The CDN handles distant users efficiently. The load balancer distributes across reverse proxies. The reverse proxies provide TLS termination, caching, and routing. The application servers run the actual logic.

This looks excessive but each layer earns its keep. Removing any one degrades the service.

Edge cases and gotchas

A few things that catch people:

HTTP/2 to HTTP/1.1 backend. The proxy speaks HTTP/2 to clients (faster) but might use HTTP/1.1 to backends (simpler). Most proxies handle this transparently.

WebSocket upgrades. Proxies must explicitly support WebSocket. nginx does, with the right config (proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";).

Connection limits. Proxies sit between potentially thousands of clients and a small number of backends. They must manage many TCP connections efficiently. nginx handles this well; older Apache HTTPD setups can struggle.

Sticky sessions. Some applications require a user's requests to go to the same backend (session state isn't shared). Proxies support sticky sessions via cookies or IP-based routing.

Health checks. Proxies periodically check backend health. Unhealthy backends are removed from rotation. Misconfigured health checks can flap (alternating between healthy and unhealthy), causing instability.

Conclusion

Reverse proxies are the front door of modern web services. They handle TLS, caching, load balancing, rate limiting, security filtering, and more. Most users never know they exist.

For developers and admins, the reverse proxy is one of the most useful patterns to deploy. A simple nginx in front of a single backend solves many practical problems at once: TLS termination, security, basic caching, logging.

For larger setups, the proxy scales horizontally and becomes the integration point for CDNs, load balancers, and security tooling.

If you're running a web-based service without a reverse proxy, you're probably missing easy wins. If you're running one and don't know what you're getting, this article is a useful reference.

Coming up

We've talked about reverse proxies and mentioned load balancing. The next article digs into load balancing in detail: L4 vs L7, the algorithms, and the architectural considerations.


Hosting your game server with AndroHost means we handle most of what's in this post for you automatically: tier sizing, SRV records, off-site backups, DDoS protection.

Browse plans·More posts·Discord