Forward vs Reverse Proxies: Direction Matters

Who Hired the Middleman?

A Proxy is just a server that sits between a Client and a Server. The difference depends on who owns it and who it protects.

1. Forward Proxy (The Client’s Agent)

  • Analogy: A Hollywood Agent. The Actor (Client) doesn’t talk to the Studio (Server) directly. The Agent talks for them.
  • Owner: The Client (or their company/ISP).
  • Goal: To protect the Client.
  • Use Cases:
    • VPN: Hides the Client’s IP address. The Server sees the Proxy’s IP.
    • Censorship Bypass: Access blocked sites through the proxy.
    • Content Filtering: Corporate firewalls blocking Facebook.
  • Direction: Outbound traffic (from Intranet to Internet).

2. Reverse Proxy (The Server’s Bodyguard)

  • Analogy: A VIP’s Bodyguard. You (Client) can’t talk to the VIP (Server) directly. You talk to the Bodyguard.
  • Owner: The Server (the website owner).
  • Goal: To protect the Server.
  • Use Cases:
    • Load Balancing: Distributing traffic across multiple servers.
    • Security: Hiding the backend Server’s IP to prevent direct attacks.
    • SSL Termination: Handling encryption so the backend doesn’t have to.
    • Caching: Serving static files (see CDNs).
    • API Management: Rate limiting and Auth (see API Gateway).
  • Direction: Inbound traffic (from Internet to Intranet).

Deep Dive: Security & TLS Fingerprinting

Reverse Proxies aren’t just dumb pipes. They are intelligent guards. One advanced technique they use is JA3 (TLS Fingerprinting).

  • The Problem: Bots can spoof User-Agent: Chrome. But their SSL handshake looks different (different cipher suites, extensions).
  • The Solution: The Reverse Proxy (e.g., Cloudflare) analyzes the raw packets of the “Client Hello” TLS message.
  • Result: It can identify that a client claims to be an iPhone but performs an SSL handshake like a Python script. BLOCK!

Deep Dive: The Sidecar Proxy (Service Mesh)

In modern Microservices (Kubernetes), we have a third type: The Sidecar. It is a Reverse Proxy attached to every single service instance.

  • Mechanism: It runs on localhost inside the same Pod as the application container.
  • The Magic: The application talks to localhost:8080, thinking it’s talking to another service. The Sidecar intercepts this, handles Service Discovery, Retries, Circuit Breaking, and mTLS (Mutual TLS), then forwards it to the destination Sidecar.

Why use a Sidecar?

It decouples Networking Logic from Business Logic.

  • Without Sidecar: Every Java/Python/Go service needs libraries for Retries, Circuit Breaking, and Tracing.
  • With Sidecar: The app code is simple. Envoy handles the complexity.

Example: Envoy Sidecar Config

This is how a Sidecar defines an “Upstream” (Backend) service.

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 10000 }
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match: { prefix: "/" }
                route: { cluster: service_google }
  clusters:
  - name: service_google
    connect_timeout: 0.25s
    type: LOGICAL_DNS
    # Comment: Envoy will resolve 'google.com' and LB across IPs
    load_assignment:
      cluster_name: service_google
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: google.com
                port_value: 443

Battle of the Proxies: Nginx vs HAProxy vs Traefik vs Envoy

Which tool should you use?

Feature Nginx HAProxy Traefik Envoy
Architecture Process-based (Workers) Event-driven (Single Process) Go-based (Single Binary) C++ Thread-based
Role Web Server + LB Pure LB Kubernetes Ingress Service Mesh Sidecar
Performance High Extreme (1M+ req/s) Medium (Go GC overhead) High
Hot Reload Process restart Seamless Automatic (Watches Docker) Seamless (xDS API)
Observability Basic (Logs) Good (Stats page) Good (Dashboard) Best in Class
Best For Static Files, Standard LB Edge TCP/HTTP LB Docker/K8s Ingress Microservices Mesh

[!TIP] Interview Tip: “I’d use Traefik for a simple Docker Swarm/K8s setup because it auto-discovers containers. I’d use Envoy if I need a complex Service Mesh with deep observability.”


Connection Pooling: The Hidden Performance Lever

Every time a Load Balancer forwards a request to a backend server, it must establish a TCP connection. This involves the 3-way handshake (SYN, SYN-ACK, ACK), which adds ≈1-3ms of latency.

The Problem: Thundering Connections

If your LB closes the connection after every request (No Keep-Alive), you pay the handshake cost for every single request.

Example:

  • 10,000 requests/sec
  • 1ms handshake per request
  • = 10 seconds of CPU time wasted just on handshakes

Solution: Connection Pooling

The LB maintains a pool of persistent connections to each backend server.

Mechanism:

  1. When a request arrives, the LB reuses an existing connection from the pool
  2. After the response, the connection goes back to the pool (not closed)
  3. Idle connections are reaped after a timeout (e.g., 60s)

Performance Impact: 5-10x reduction in latency for short requests.

Pool Sizing Formula

Pool Size per Backend = (Peak RPS × Avg Response Time) / Number of LB instances

Example:
- Peak: 5000 RPS
- Avg Response: 50ms (0.05s)
- LB instances: 2

Pool Size = (5000 × 0.05) / 2 = 125 connections per backend

Trade-off: Too large → wasted memory. Too small → connection starvation (requests queue).

HTTP Keep-Alive Configuration

# Nginx: Enable connection pooling to backends
upstream backend {
    server 10.0.1.10:8080;
    keepalive 128;  # Pool size
}

server {
    listen 80;
    location / {
        proxy_pass http://backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";  # Remove close header
    }
}

Interview Insight: AWS ELB automatically pools connections. Google Cloud LB uses a default pool of 100 connections per backend.


Interactive Demo: The Identity Switcher

Visualize the flow of traffic and who is being protected.

  • Forward Proxy Mode: Protects the User (Mask). The Internet doesn’t know who the User is.
  • Reverse Proxy Mode: Protects the Server (Shield). The User doesn’t know who the Server is.
  • Connection Pooling: Visualize the handshake overhead vs pooling.
  • Firewall Mode: The Reverse Proxy detects a threat (Bot) and BLOCKS it before it reaches the server.
👤
User
IP: 1.2.3.4
PROXY
IP: 55.55.55.55
👺
🌐
Internet
Sees IP: 55.55.55.55
Forward Proxy: The User is hidden. The Internet thinks requests are coming from the Proxy (55.55.55.55).

Summary

  • Forward Proxy: Client-side. For Anonymity (VPN).
  • Reverse Proxy: Server-side. For Scale and Security (Load Balancer).
  • See Network Fundamentals for more on Firewalls.