Networking and API Design for System Design

Proxy vs Reverse Proxy

Load balancers, CDNs, API gateways, and service meshes are all built on proxy concepts. Understanding forward vs reverse proxies unlocks how traffic actually flows through a system.


The Concept Explained

A proxy is an intermediary that receives a request and forwards it on. The forward/reverse distinction is entirely about which side it acts for:

Forward proxy: acts for the CLIENT
   clients ──> [proxy] ──> the whole internet
   The client knows the proxy exists. Servers see the proxy's address.

Reverse proxy: acts for the SERVER
   the whole internet ──> [proxy] ──> your servers
   The client thinks the proxy IS the server. Servers see the proxy's address.

The pattern: a forward proxy sits at the edge of a client network and serves many clients reaching many destinations. A reverse proxy sits at the edge of a server network and serves many clients reaching your destinations.

KEY CONCEPT

The reason this distinction matters more than it first appears: almost every piece of infrastructure between your users and your code is a reverse proxy wearing a specific name. A load balancer is a reverse proxy that distributes. A CDN is a geographically distributed reverse proxy that caches. An API gateway is a reverse proxy that enforces policy (Lesson 3.1). A service mesh sidecar is both directions at once. Understanding the primitive means understanding all of them.


How It Works

Forward proxies

The client is configured to send requests through it. Uses, roughly in order of how often they appear in a design discussion:

  • Egress control. All outbound traffic funnels through one point where it can be allow-listed, logged, and inspected. This is how organizations enforce which external services their systems may reach.
  • Corporate filtering and compliance. Blocking categories, logging access, applying policy.
  • Shared caching. Historically significant, largely obsolete now that nearly all traffic is TLS-encrypted and cannot be cached by an intermediary without breaking the encryption.
  • Source address consolidation. All requests appear to come from one address, which is what makes partner IP allow-lists workable (Lesson 1.2).

The security case worth naming: an egress proxy is the standard mitigation for server-side request forgery. If your webhook delivery workers can only reach the internet through a proxy that refuses private address ranges and cloud metadata endpoints, a user-registered malicious URL cannot reach your internal network (Lesson 5.4). This is a much stronger control than validating URLs in application code, because it cannot be bypassed by a DNS record that changes after validation.

Reverse proxies

The client has no idea it exists; it connects to what it believes is the server. This is where the majority of your infrastructure lives:

  • TLS termination. Decrypt once at the edge, so everything behind it can read, route, cache, and log (Lesson 1.4).
  • Load balancing. Distribute across a pool with health checks.
  • Caching. Serve repeated responses without touching origin servers.
  • Compression. gzip or brotli applied centrally rather than in every service.
  • Routing. Path, host, or header-based dispatch to different backends.
  • Security. WAF rules, rate limiting, request size limits, bot filtering, absorbing volumetric attacks before they reach origin.
  • Protocol translation. HTTP/3 at the edge, HTTP/1.1 to legacy backends. Or REST in, gRPC out (Lesson 2.7).

That last one is quietly valuable: your edge can adopt modern protocols without touching a single backend service.

The chain in a real request

A production request typically passes through several reverse proxies, each doing one job:

browser

  ├─ corporate forward proxy       (some enterprise networks)

  ├─ CDN edge                      reverse proxy: cache, TLS termination, DDoS absorption
  ├─ WAF                           reverse proxy: request inspection and filtering
  ├─ load balancer                 reverse proxy: distribute across zones, health checks
  ├─ API gateway                   reverse proxy: authn, rate limits, routing (Module 3)
  ├─ ingress controller            reverse proxy: cluster entry, path routing
  ├─ mesh sidecar                  proxy: mTLS, retries, circuit breaking

  └─ your service

Two things follow that are worth saying in an interview.

Each hop adds latency. Single-digit milliseconds each, and six hops is not nothing, and every one is a component that can fail or be misconfigured. Chains accumulate through organizational history as much as design, and asking "does each of these still earn its place?" is a legitimate senior question.

Each hop is a place where the client's identity gets lost. By the time the request reaches your service, the source address is the previous proxy's. This leads directly to the next section.

X-Forwarded-For, and why it is a security decision

Because each proxy replaces the source address, the original client address is preserved in a header:

X-Forwarded-For: 203.0.113.5, 198.51.100.10, 10.0.0.7
                 ^ original     ^ CDN          ^ load balancer

Each proxy appends the address it saw. The leftmost entry is nominally the real client.

Here is the trap, and it is a real vulnerability rather than a nuisance: this header is trivially spoofable. A client can send its own X-Forwarded-For with any value, and a naive proxy chain simply appends to it. If you take the leftmost value as truth, an attacker sets it to whatever they like and defeats every control keyed on client address: IP rate limiting (Lesson 3.2), IP allow-lists, geographic blocking, and abuse attribution.

The correct handling: count from the right, not the left. You know how many proxies you operate. If there are two, the client address is the third entry from the right, and everything to the left of that is attacker-supplied text. Most proxies and frameworks expose a "trusted proxy count" or "trusted proxy CIDRs" setting for exactly this, and configuring it is not optional if any security control depends on client address.

WARNING

A rate limiter keyed on the leftmost X-Forwarded-For value provides no protection at all: the attacker sends a different value on every request and each one looks like a distinct client. Every entry to the left of your own trusted proxies is data the client controls, so it must be treated as untrusted input, not identity.

For L4 proxies that cannot add HTTP headers (because they never parse HTTP), the PROXY protocol serves the same purpose, prefixing the connection with the original address details.

L4 versus L7, and what each can do

The layer a proxy operates at determines its capabilities (Lesson 1.1):

L4 proxyL7 proxy
SeesAddresses, ports, bytesFull HTTP requests
Can route onDestination and portPath, host, headers, method
Can cacheNoYes
Can terminate TLSOptionally, or pass throughYes, generally required
Balances gRPC properlyNo (Lesson 2.7)Yes, per stream
OverheadVery lowHigher, parses every request

The gRPC row is the one that produces real incidents: an L4 proxy pins a long-lived multiplexed HTTP/2 connection to a single backend, so all traffic lands on one instance while the rest idle.

TLS passthrough forces this choice: a proxy that cannot decrypt cannot route on paths or cache, which means end-to-end encryption and edge intelligence are mutually exclusive at any given hop.

Sidecars: both at once

A service mesh sidecar is the interesting hybrid. Every service instance gets a proxy alongside it that intercepts all traffic:

  • For inbound requests it is a reverse proxy: terminating mTLS, enforcing policy, reporting metrics.
  • For outbound requests it is a forward proxy: adding mTLS, applying retries, timeouts, and circuit breaking.

This is what lets a mesh add encryption, retries, and observability to services without changing their code, and it is why the sidecar model dominates east-west traffic while gateways dominate north-south (Lesson 3.1).


System Design Implications

  • Naming the proxy type clarifies the design. Saying "a reverse proxy at the edge terminating TLS and routing by path, with a forward proxy controlling egress" is more precise than "we put nginx in front."
  • Every reverse proxy hop is a policy opportunity and a failure point. Caching, security, and routing at the edge protect origins; each hop also adds latency and an outage mode.
  • Egress proxying is a security control, not just plumbing. It is the durable answer to SSRF and to third-party data exfiltration.
  • Proxy chains lose client context by default. Forwarded headers restore it, and only if you configure trust correctly.
  • Where you terminate TLS determines what every proxy downstream can do. This one decision cascades through your entire edge architecture.

Tradeoffs and Decision Framework

More layers versus fewer. Each adds capability, latency, and operational surface. Chains grow by accretion, and consolidating them is usually available and rarely prioritized.

L4 versus L7. L4 for raw throughput and protocol-agnostic forwarding. L7 whenever you need content-based decisions, caching, or correct handling of multiplexed protocols.

Terminate versus passthrough. Terminating gives every edge capability. Passthrough gives end-to-end confidentiality and blinds the edge.

Managed versus self-hosted edge. A managed CDN or WAF brings global presence and attack absorption with less control and per-request cost. Self-hosted proxies give full control and are components you operate.


Common Mistakes

Trusting the leftmost X-Forwarded-For value. Client-supplied, so every control keyed on it is bypassable.

Not configuring a trusted proxy count. Same failure, arrived at through default settings.

L4 balancing in front of gRPC or HTTP/2. Traffic concentrates on one backend.

Expecting an L4 proxy to route on paths. It never sees them.

Assuming TLS passthrough still allows caching or routing. It cannot read the request.

Confusing the directions. A "proxy" in a security review usually means egress control; a "proxy" in a performance discussion usually means the reverse proxy at your edge. Ambiguity here causes real miscommunication.

Accumulating hops nobody owns. Latency and failure modes added by history rather than by decision.

Relying on application-level URL validation for SSRF. DNS can change after the check; an egress proxy enforces it at request time.


INTERVIEW QUESTION

Explain the difference between a forward proxy and a reverse proxy. Where does each fit in a system architecture?