Engineering Notes
Home/Networking & Web/HTTP/Proxy and Reverse Proxy
Networking & Web · HTTP

Proxy and Reverse Proxy

A forward proxy acts for clients; a reverse proxy acts for servers. Same mechanism, opposite direction. See what reverse proxies do, how the backend loses the client's IP, and how to trust X-Forwarded-For safely.

🌐 Networking & Web● Intermediate⏱ 6 min read▶ 2 interactive🛠️ 2 exercises🎤 5 interview Q&As

🎯 What you'll learn

  • Forward vs reverse proxies
  • What reverse proxies do: TLS, routing, caching, buffering
  • Losing the real client and forwarding headers
  • Proxy chains, trust, and the API gateway pattern

📚 Before you start

1Same Mechanism, Opposite Direction

A proxy is any intermediary that sits between a client and a server, forwarding requests and responses on someone's behalf. "Forward proxy" and "reverse proxy" describe the exact same relaying mechanism — the only difference is which side it's hiding:

text
FORWARD PROXY  (hides the CLIENT from the server)

  Client A  --\
  Client B  ---> [ Forward Proxy ] ---> Server
  Client C  --/

  The server sees ONE proxy IP. It has no idea which of A/B/C actually asked.


REVERSE PROXY  (hides the SERVER(s) from the client)

                              /--> Backend 1
  Client ---> [ Reverse Proxy ]---> Backend 2
                              \--> Backend 3

  The client sees ONE proxy IP/domain. It has no idea which backend actually answered.

A forward proxy is configured and known to the client (corporate egress filtering, a VPN, an anonymizing proxy) and is typically invisible to the server. A reverse proxy is configured and known to the server operator (nginx, an API gateway, a CDN edge) and is typically invisible to the client, who believes they're talking directly to "the site."

A forward proxy sits on the client side and controls outbound traffic, while a reverse proxy sits in front of servers handling TLS, load balancing and caching
A forward proxy sits on the client side and controls outbound traffic, while a reverse proxy sits in front of servers handling TLS, load balancing and caching

2What a Reverse Proxy Actually Does

A reverse proxy is rarely just a dumb relay — it's usually doing several jobs at once, all invisibly to the client:

ResponsibilityWhat it means
TLS terminationclient's HTTPS connection ends at the proxy; proxy-to-backend traffic may be plain HTTP on a trusted internal network
Load balancingspreads requests across multiple backend instances (round-robin, least-connections, etc.)
Routingsends /api/* to one backend, /* (everything else) to another, based on path or Host
Cachingcan serve a cached response itself without ever forwarding to a backend (see 05-caching_and_compression)
Compressioncan compress an uncompressed backend response before it reaches the client
Rate limiting / authcan reject or throttle requests before a backend ever sees them
nginx
# nginx reverse proxy: path-based routing to two backends, one upstream
upstream api_backend {
    server 10.0.0.11:4000;
    server 10.0.0.12:4000;   # load-balanced across both
}

server {
    listen 443 ssl;
    server_name northwind.dev;

    location /api/ {
        proxy_pass http://api_backend;
    }

    location / {
        proxy_pass http://10.0.0.20:3000;   # web app backend
    }
}

3The Problem: the Backend Loses the Real Client

Once a reverse proxy is in the path, every request the backend receives has the proxy's own IP as its TCP source address — from the backend's point of view, every request looks like it came from the same one machine:

text
Client (203.0.113.7) -> Reverse Proxy (10.0.0.1) -> Backend

Backend's connection info: remote address = 10.0.0.1  (the proxy, not the client!)

This breaks anything that depends on the real client IP: per-IP rate limiting, geolocation, abuse logging, "last login IP" — all of it, unless the proxy explicitly forwards the original information in headers.

4Forwarding Headers

http
X-Forwarded-For: 203.0.113.7
X-Forwarded-Proto: https
X-Forwarded-Host: northwind.dev
Via: 1.1 nginx-edge-01
HeaderCarries
X-Forwarded-Forthe original client IP (and, if there are multiple proxies in a chain, a comma-separated list, oldest first)
X-Forwarded-Protowhether the original client connection was http or https — matters because TLS is often terminated at the proxy, so the backend's own connection may be plain http even though the real client used https
X-Forwarded-Hostthe Host header the client originally sent, in case the proxy rewrites it before forwarding
Viaa general-purpose "this passed through proxy X" trace header, standardized (unlike the X-Forwarded-* family, which is a de facto convention, not an RFC standard — the standardized replacement is Forwarded, e.g. Forwarded: for=203.0.113.7;proto=https, though X-Forwarded-* remains far more common in practice)

A backend must be explicitly configured to read X-Forwarded-For (or Forwarded) instead of the raw TCP source address wherever it wants the real client's IP — this is not automatic, and most web frameworks default to trusting the raw socket address only.

5Proxy Chains and Trust

X-Forwarded-For can accumulate multiple hops:

http
X-Forwarded-For: 203.0.113.7, 10.0.0.1, 10.0.0.2
                  ^ original    ^ proxy 1  ^ proxy 2 (closest to backend)

Each proxy in the chain is supposed to append its own view of the previous hop's address rather than overwrite the header — which means the leftmost value is only trustworthy if every proxy in the chain is trusted to append correctly and never forge it. A client can freely send their own fabricated X-Forwarded-For header on the original request; a correctly configured edge proxy should strip or overwrite any client-supplied value before appending the real connecting IP, otherwise the backend ends up trusting attacker-controlled input for exactly the kind of decision (rate limiting, geo-restriction, abuse blocking) this header exists to support.

6The API Gateway Pattern

When a reverse proxy fronts multiple independent backend services behind one public domain, it's commonly called an API gateway — the routing responsibility from section 2 becomes the primary job:

text
Client -> https://northwind.dev/*

  /            -> web app backend
  /api/*       -> REST API backend
  /ws/*        -> WebSocket backend (see note below)
  /admin/*     -> internal admin backend, extra auth enforced at the gateway

A single public domain and a single TLS certificate front several independently deployable services, each of which can be scaled, deployed, or replaced without the client ever knowing the topology changed. WebSocket traffic needs explicit proxy support for the Upgrade/Connection: upgrade handshake (a plain HTTP reverse-proxy config that doesn't forward these headers will silently break WebSocket connections while ordinary HTTP routes through it fine).

⚠️ Common Pitfalls

  1. Confusing forward and reverse proxy direction. The mechanism is identical; only "which party is anonymized" differs — mixing them up leads to configuring the wrong side's trust boundary.
  2. Trusting X-Forwarded-For without stripping client-supplied values first. Any client can send a fake X-Forwarded-For on the original request; only the edge proxy's own appended value is trustworthy, and only if every proxy in the chain enforces this.
  3. Forgetting X-Forwarded-Proto. A backend that redirects or generates absolute URLs based on its own (often plain-HTTP) connection to the proxy can emit http:// links even though the real client is on https://, causing mixed-content errors or redirect loops.
  4. Not forwarding Upgrade/Connection headers for WebSocket routes. Ordinary HTTP traffic works fine through a proxy misconfigured this way, masking the bug until a WebSocket-dependent feature is tested.
  5. Logging or rate-limiting on the raw TCP source address instead of the forwarded client IP. Every request appears to come from the proxy, making per-client analysis meaningless without reading the forwarding headers.

📋 Quick Reference

text
Forward proxy  -> hides the CLIENT from the server; configured by/known to the client
Reverse proxy  -> hides the SERVER(s) from the client; configured by/known to the server operator

Reverse proxy jobs: TLS termination, load balancing, routing, caching, compression, rate limiting

X-Forwarded-For    -> original client IP (comma-separated chain if multiple proxies)
X-Forwarded-Proto  -> http/https of the ORIGINAL client connection (TLS may be terminated upstream)
X-Forwarded-Host   -> original Host header, if rewritten before forwarding
Via                -> standardized hop trace; Forwarded is the standardized alternative to X-Forwarded-*

Only trust X-Forwarded-For if every hop strips/overwrites client-supplied values before appending
API gateway -> reverse proxy fronting multiple independent backend services on one public domain

🧠 Key takeaways

  • Forward proxy: clients → proxy → internet (egress control). Reverse proxy: internet → proxy → your servers.
  • Reverse proxies do TLS termination, routing, load balancing, caching, compression, buffering, rate limiting.
  • Backends see the proxy's IP; pass X-Forwarded-For/Proto/Host or the standard Forwarded header.
  • Trust forwarding headers only from known proxies, counting hops from the right.

🎤 Interview Q&A

Questions interviewers ask about this topic. Answer out loud first, then open a card to compare.

Q1What's the difference between a forward proxy and a reverse proxy?core▾

A forward proxy acts for clients (corporate egress proxy, filtering, anonymity): servers see the proxy. A reverse proxy acts for servers (Nginx, Envoy, HAProxy, CDNs): clients talk to it and it forwards to backends.

Follow-ups interviewers ask
  • Is a load balancer a reverse proxy? An L7 load balancer is one.
Q2What can a reverse proxy do for you?core▾

TLS termination, load balancing, caching, compression, rate limiting, authentication, request routing by path/host, serving static files, adding security headers, and hiding backend topology.

Follow-ups interviewers ask
  • Example Nginx use? Terminate TLS and route /api to app servers and / to static files.
Q3What's an API gateway compared with a reverse proxy?core▾

A reverse proxy with API-specific features: authentication/authorization, rate limiting per client, request transformation, API keys, analytics and developer portal integration (Kong, AWS API Gateway, Apigee).

Follow-ups interviewers ask
  • Risk of a gateway? Becoming a bottleneck or a place for business logic it shouldn't hold.
Q4What headers should a reverse proxy add?core▾

X-Forwarded-For (client IP), X-Forwarded-Proto (original scheme), X-Forwarded-Host, or the standard Forwarded, plus request IDs. Backends must trust these only from the proxy.

Follow-ups interviewers ask
  • Why does the app need X-Forwarded-Proto? To build correct redirect URLs and enforce HTTPS behind TLS termination.
Q5What is HTTP request smuggling?senior▾

When a front-end proxy and back-end server disagree on where a request ends (conflicting Content-Length and Transfer-Encoding), an attacker can smuggle a hidden request, bypassing controls or poisoning caches. Mitigate by normalizing/rejecting ambiguous requests and using HTTP/2 end to end.

Follow-ups interviewers ask
  • Which header combination is classic? CL.TE or TE.CL mismatches.

🛠️ Practice exercises

Each exercise is a file in this topic folder. Code exercises are self-checking: run them and make the checks pass.

✅ Check yourself

Answer the questions — feedback is instant.

1. A corporate proxy filtering employees' web access is a…
Acts for clients.
2. XFF: 1.2.3.4, 203.0.113.9 arrives through one trusted proxy. The real client is…
Leftmost is client-controlled.
3. Why does the backend need X-Forwarded-Proto?
TLS ended at the proxy.
4. An API gateway is essentially…
Specialized reverse proxy.