← All Posts
High Level Design Series · Building Blocks · Part 6

Proxies: Forward, Reverse, API Gateway

Every request in a modern system travels through at least one proxy before reaching its destination. Proxies are the traffic controllers of distributed systems — they sit between clients and servers, intercepting requests to add security, improve performance, and simplify architecture. Whether you’re designing a CDN, building a microservices platform, or answering a system design interview, understanding proxies is non-negotiable.

This post covers every proxy type you’ll encounter: forward proxies, reverse proxies, API gateways, sidecar proxies, and full service meshes. We’ll walk through real Nginx configs, Kong plugin setups, Envoy sidecar patterns, and Istio architecture — with interactive animations to solidify each concept.

What is a Proxy?

A proxy (from Latin procurator, “one who acts on behalf of another”) is an intermediary server that sits between a client and a destination server. Instead of the client talking directly to the server, the client talks to the proxy, and the proxy forwards the request onward.

Client ──▶ [ Proxy ] ──▶ Server │ │ │ sends request intercepts, receives the to proxy transforms, proxied request forwards

Why do proxies exist?

Proxies exist because direct client-to-server communication lacks control. In the real world, you need to:

Proxy vs Gateway vs Load Balancer

These terms overlap significantly. Here’s how they relate:

ConceptPrimary RoleOSI LayerExample
Forward ProxyClient-side intermediaryL7 (HTTP)Squid, corporate proxy
Reverse ProxyServer-side intermediaryL7 (HTTP)Nginx, HAProxy
Load BalancerDistribute traffic to backendsL4/L7AWS ALB/NLB, F5
API GatewaySingle entry for microservicesL7 (HTTP)Kong, AWS API GW
Sidecar ProxyPer-service network agentL4/L7Envoy, Linkerd-proxy

A reverse proxy is a load balancer if it distributes traffic. An API gateway is a reverse proxy with extra features. A sidecar proxy is a reverse proxy running per-service. The distinctions are about scope and responsibility, not fundamental architecture.

Forward Proxy

A forward proxy sits on the client side. The client explicitly configures its network stack to send requests through the proxy, and the proxy forwards them to the internet on the client’s behalf. The destination server sees the proxy’s IP address, not the client’s.

┌──────────────────────────────────────────────────────────┐ │ Client Network (Corporate / Private) │ │ │ │ Client A ──┐ │ │ Client B ──┼──▶ [ Forward Proxy ] ──▶ Internet ──▶ Server│ │ Client C ──┘ (Squid) │ │ │ └──────────────────────────────────────────────────────────┘ The forward proxy: • Hides client IPs from the server • Caches frequently accessed content • Filters/blocks certain URLs • Logs all outbound requests

Key characteristics

Use cases

🔒 Privacy / Anonymity

Mask your IP address. The server sees the proxy’s IP, not yours. VPN services are essentially encrypted forward proxies.

🚫 Content Filtering

Block access to social media, gambling, or malware sites. Schools and enterprises use this heavily.

🏢 Corporate Networks

All employee traffic goes through the proxy for monitoring, compliance, and bandwidth management.

📦 Caching

Cache frequently accessed static resources (JS, CSS, images) to reduce bandwidth and improve latency.

Forward proxy with Squid (config example)

# /etc/squid/squid.conf
http_port 3128

# Allow only internal network
acl internal_network src 10.0.0.0/8
http_access allow internal_network
http_access deny all

# Cache settings
cache_dir ufs /var/spool/squid 10000 16 256
maximum_object_size 100 MB

# Block social media
acl blocked_sites dstdomain .facebook.com .twitter.com .tiktok.com
http_access deny blocked_sites

# Logging
access_log /var/log/squid/access.log squid

Forward proxy vs VPN

FeatureForward ProxyVPN
OSI LayerApplication (L7)Network (L3)
EncryptionOptional (HTTPS CONNECT)Always (IPsec/WireGuard)
ScopeHTTP/HTTPS traffic onlyAll traffic (TCP, UDP, etc.)
Client configBrowser/app proxy settingsOS-level tunnel
PerformanceFaster (less overhead)Slightly slower (encryption)
Use caseWeb filtering, cachingFull network privacy

Reverse Proxy

A reverse proxy sits on the server side. Clients on the internet send requests to the reverse proxy’s public IP, and the proxy forwards them to the appropriate backend server. The client has no idea which backend actually handled the request.

┌──────────────────────────────────────────────────────────────┐ │ Server Infrastructure │ │ │ │ ┌──▶ Backend Server 1 (10.0.1.1) │ │ Internet ──▶ [ Reverse ] ┼──▶ Backend Server 2 (10.0.1.2) │ │ Clients Proxy └──▶ Backend Server 3 (10.0.1.3) │ │ (Nginx) │ │ │ └──────────────────────────────────────────────────────────────┘ The reverse proxy: • Hides backend server IPs from clients • Distributes load across backends • Terminates TLS (clients talk HTTPS, backends talk HTTP) • Caches static content • Compresses responses (gzip/brotli)

Key characteristics

Use cases in depth

⚖️ Load Balancing

Distribute requests across multiple backends using round-robin, least-connections, IP hash, or weighted algorithms.

🔒 SSL/TLS Termination

Handle expensive TLS handshakes at the proxy, so backends only deal with plain HTTP internally.

📦 Response Caching

Cache static assets and API responses. Reduces backend load by 80%+ for read-heavy workloads.

🚗 Compression

Gzip or Brotli compress responses before sending to clients, reducing bandwidth by 60-80%.

🛡️ Security Shield

Hide internal topology, block malicious requests, rate limit by IP, add security headers (CORS, CSP, HSTS).

🌐 A/B Testing & Canary

Route a percentage of traffic to a new version while the rest goes to the stable version.

Forward vs Reverse Proxy — Request Flow

Nginx as a reverse proxy — complete config

# /etc/nginx/nginx.conf
worker_processes auto;

events {
    worker_connections 4096;
    multi_accept on;
}

http {
    # ── Upstream backend pool ──
    upstream api_backend {
        least_conn;                    # Least-connections algorithm
        server 10.0.1.1:8080 weight=3;  # 3x traffic
        server 10.0.1.2:8080 weight=2;  # 2x traffic
        server 10.0.1.3:8080 weight=1;  # 1x traffic
        server 10.0.1.4:8080 backup;    # Only used when others are down

        keepalive 64;                  # Persistent connections to backends
    }

    # ── Response caching ──
    proxy_cache_path /var/cache/nginx levels=1:2
                     keys_zone=api_cache:10m max_size=1g
                     inactive=60m use_temp_path=off;

    # ── Gzip compression ──
    gzip on;
    gzip_types application/json text/plain text/css application/javascript;
    gzip_min_length 256;
    gzip_comp_level 5;

    # ── Rate limiting ──
    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/s;

    server {
        listen 443 ssl http2;
        server_name api.example.com;

        # ── TLS termination ──
        ssl_certificate     /etc/ssl/certs/api.example.com.pem;
        ssl_certificate_key /etc/ssl/private/api.example.com.key;
        ssl_protocols       TLSv1.2 TLSv1.3;
        ssl_ciphers         ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
        ssl_prefer_server_ciphers on;

        # ── Security headers ──
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header X-Frame-Options "DENY" always;

        # ── API routes ──
        location /api/ {
            limit_req zone=api_limit burst=50 nodelay;

            proxy_pass http://api_backend;
            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;

            # Connection reuse
            proxy_http_version 1.1;
            proxy_set_header Connection "";

            # Timeouts
            proxy_connect_timeout 5s;
            proxy_send_timeout 30s;
            proxy_read_timeout 30s;

            # Caching GET responses
            proxy_cache api_cache;
            proxy_cache_valid 200 10m;
            proxy_cache_valid 404 1m;
            proxy_cache_use_stale error timeout updating;
            add_header X-Cache-Status $upstream_cache_status;
        }

        # ── Static assets ──
        location /static/ {
            root /var/www;
            expires 30d;
            add_header Cache-Control "public, immutable";
        }

        # ── Health check endpoint ──
        location /health {
            access_log off;
            return 200 "OK";
        }
    }

    # ── HTTP → HTTPS redirect ──
    server {
        listen 80;
        server_name api.example.com;
        return 301 https://$host$request_uri;
    }
}

HAProxy as a reverse proxy

# /etc/haproxy/haproxy.cfg
global
    maxconn 50000
    log stdout format raw local0

defaults
    mode http
    timeout connect 5s
    timeout client  30s
    timeout server  30s
    option httplog
    option forwardfor     # Adds X-Forwarded-For header

frontend http_front
    bind *:443 ssl crt /etc/ssl/api.pem
    default_backend api_servers

    # Route based on path
    acl is_api path_beg /api/
    acl is_ws  path_beg /ws/
    use_backend api_servers   if is_api
    use_backend ws_servers    if is_ws

backend api_servers
    balance leastconn
    option httpchk GET /health
    server s1 10.0.1.1:8080 check weight 3
    server s2 10.0.1.2:8080 check weight 2
    server s3 10.0.1.3:8080 check weight 1

backend ws_servers
    balance source        # Sticky sessions for WebSocket
    server ws1 10.0.2.1:8080 check
    server ws2 10.0.2.2:8080 check

Forward vs Reverse proxy: summary

DimensionForwardReverse
Sits onClient sideServer side
Client knows?Yes (configured)No (transparent)
Server knows?NoYes (via X-Forwarded-For)
HidesClient identityServer identity & topology
DirectionOutbound (private → internet)Inbound (internet → private)
Common usePrivacy, filtering, cachingLoad balancing, TLS, security
ExamplesSquid, corporate proxyNginx, HAProxy, Caddy

API Gateway

An API Gateway is a reverse proxy on steroids. It serves as the single entry point for all client requests in a microservices architecture, handling cross-cutting concerns that would otherwise be duplicated across every service.

┌──▶ User Service (/api/users) Mobile App ──┐ │ ┌──▶ Order Service (/api/orders) Web App ──┼──▶ [API Gateway] ──┼──▶ Payment Service (/api/payments) Partner API ──┘ │ ├──▶ Inventory Service (/api/inventory) └──▶ Notification Svc (/api/notify) The gateway handles: ✓ Authentication & Authorization ✓ Rate Limiting ✓ Request Routing ✓ Response Aggregation ✓ Request/Response Transformation ✓ Circuit Breaking ✓ Logging & Metrics ✓ API Versioning

Core features

🔐 Authentication

Validate JWT tokens, OAuth2 flows, or API keys at the gateway. Services never handle auth themselves.

⚡ Rate Limiting

Enforce per-user, per-IP, or per-API-key rate limits. Protect backends from abuse and DDoS.

🔌 Request Routing

Route /api/users/* to User Service, /api/orders/* to Order Service. Path-based, header-based, or weighted.

🔄 Transformation

Transform requests (add headers, rewrite paths) and responses (filter fields, rename keys) without touching service code.

📋 Response Aggregation

Combine responses from multiple services into a single response. Mobile app gets one API call instead of five.

💥 Circuit Breaking

Stop sending traffic to a failing service. Return cached or fallback responses instead of cascading failures.

API Gateway — Request Processing Pipeline

API Gateway vs simple reverse proxy

FeatureReverse Proxy (Nginx)API Gateway (Kong/Envoy)
Request routing✔ Path-based✔ Path, header, method, query param
Load balancing✔ Round-robin, least-conn✔ + Consistent hashing, canary
TLS termination
Authentication❌ Basic only✔ JWT, OAuth2, OIDC, API keys
Rate limiting✔ Basic (req/s per IP)✔ Per-user, per-route, sliding window
Request transformation❌ Limited header rewrite✔ Full body/header/query transformation
Response aggregation✔ Combine multiple service responses
Circuit breaking✔ With fallback responses
Plugin ecosystemLimited modulesRich plugin marketplace
Admin APIConfig file reloadREST API for dynamic config
ObservabilityAccess logsDistributed tracing, Prometheus metrics

Kong API Gateway — config example

# kong.yml — declarative configuration

_format_version: "3.0"

services:
  - name: user-service
    url: http://user-svc.internal:8080
    routes:
      - name: user-routes
        paths: ["/api/v1/users"]
        methods: ["GET", "POST", "PUT", "DELETE"]
        strip_path: false

  - name: order-service
    url: http://order-svc.internal:8080
    routes:
      - name: order-routes
        paths: ["/api/v1/orders"]
        strip_path: false

plugins:
  # ── Global JWT Authentication ──
  - name: jwt
    config:
      claims_to_verify: ["exp"]
      header_names: ["Authorization"]

  # ── Rate limiting per consumer ──
  - name: rate-limiting
    config:
      minute: 100
      hour: 5000
      policy: redis
      redis_host: redis.internal

  # ── Request size limiting ──
  - name: request-size-limiting
    config:
      allowed_payload_size: 10   # MB

  # ── Response transformation ──
  - name: response-transformer
    service: user-service
    config:
      remove:
        headers: ["X-Internal-Id", "X-Debug-Info"]
      add:
        headers: ["X-Api-Version:v1"]

  # ── Prometheus metrics ──
  - name: prometheus
    config:
      per_consumer: true
      status_code_metrics: true

  # ── Circuit breaker (via custom plugin or upstream config) ──

consumers:
  - username: mobile-app
    jwt_secrets:
      - key: mobile-app-key
        algorithm: HS256
        secret: "{vault://env/MOBILE_JWT_SECRET}"

  - username: partner-api
    jwt_secrets:
      - key: partner-key
        algorithm: RS256
        rsa_public_key: "{vault://env/PARTNER_PUBLIC_KEY}"

Popular API gateways compared

GatewayLanguagePlugin ModelBest For
KongLua (OpenResty)Lua/Go pluginsGeneral purpose, enterprise
AWS API GatewayManaged serviceLambda authorizersAWS-native, serverless
EnvoyC++Wasm/Lua filtersHigh performance, service mesh
TraefikGoMiddleware chainKubernetes-native, auto-discovery
APISIXLua (OpenResty)Lua/Wasm pluginsHigh throughput, etcd config
Zuul 2JavaFiltersNetflix/Spring ecosystem

Sidecar Proxy

A sidecar proxy is a small proxy process deployed alongside every service instance. Instead of a single centralized gateway, every service gets its own personal proxy that handles networking concerns. The application code doesn’t even know the sidecar exists — it just sends requests to localhost.

┌─────────────────────────────── Pod / Container Group ──┐ │ │ │ ┌──────────────┐ ┌───────────────┐ │ │ │ Application │ ──────▶ │ Sidecar Proxy│ ──▶ Network │ │ (your code) │ ◀────── │ (Envoy) │ ◀── Network │ └──────────────┘ └───────────────┘ │ │ localhost:8080 localhost:15001 │ │ │ │ App sends to localhost → Sidecar intercepts via │ │ iptables rules and handles all networking │ └────────────────────────────────────────────────────────┘

What the sidecar handles

Envoy as a sidecar — config snippet

# envoy.yaml — sidecar configuration
static_resources:
  listeners:
    - name: inbound
      address:
        socket_address: { address: 0.0.0.0, port_value: 15006 }
      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
                stat_prefix: inbound
                route_config:
                  virtual_hosts:
                    - name: local_service
                      domains: ["*"]
                      routes:
                        - match: { prefix: "/" }
                          route: { cluster: local_app }
                http_filters:
                  - name: envoy.filters.http.router
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

    - name: outbound
      address:
        socket_address: { address: 0.0.0.0, port_value: 15001 }
      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
                stat_prefix: outbound
                route_config:
                  virtual_hosts:
                    - name: order_service
                      domains: ["order-svc.internal"]
                      routes:
                        - match: { prefix: "/" }
                          route:
                            cluster: order_service
                            retry_policy:
                              retry_on: "5xx,connect-failure"
                              num_retries: 3
                              per_try_timeout: 2s
                http_filters:
                  - name: envoy.filters.http.router
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

  clusters:
    - name: local_app
      connect_timeout: 1s
      type: STATIC
      load_assignment:
        cluster_name: local_app
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address: { address: 127.0.0.1, port_value: 8080 }

    - name: order_service
      connect_timeout: 5s
      type: STRICT_DNS
      lb_policy: ROUND_ROBIN
      circuit_breakers:
        thresholds:
          - max_connections: 1024
            max_pending_requests: 1024
            max_retries: 3
      load_assignment:
        cluster_name: order_service
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address: { address: order-svc.internal, port_value: 8080 }
Why “sidecar”? The name comes from the motorcycle sidecar — a secondary passenger compartment attached to the main vehicle. The proxy rides alongside your service, sharing the same lifecycle (deployed together, scaled together, terminated together).

Service Mesh

A service mesh is what you get when you deploy sidecar proxies to every service in your system and connect them with a centralized control plane. It’s a dedicated infrastructure layer for handling service-to-service communication.

┌─────────────────── Control Plane (Istiod) ───────────────────┐ │ │ │ ┌─────────┐ ┌──────────┐ ┌──────────┐ │ │ │ Pilot │ │ Citadel │ │ Galley │ │ │ │ (config)│ │ (certs) │ │ (config │ │ │ │ │ │ │ │ valid.) │ │ │ └────┬────┘ └────┬─────┘ └────┬─────┘ │ │ │ │ │ │ │ xDS API cert push config push │ └───────┼──────────────┼───────────────┼───────────────────────┘ │ │ │ ┌───────▼──────────────▼───────────────▼──── Data Plane ───────┐ │ │ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ │ │ App A │ │ App B │ │ App C │ │ │ │ + Envoy ◄──┼─mTLS─┼──► Envoy ◄┼─mTLS─┼──► Envoy │ │ │ │ sidecar │ │ sidecar │ │ sidecar │ │ │ └────────────┘ └────────────┘ └────────────┘ │ │ │ └──────────────────────────────────────────────────────────────┘

Data plane vs control plane

AspectData PlaneControl Plane
What is it?All the sidecar proxies (Envoy instances)Management software (Istiod)
HandlesActual network traffic between servicesConfiguration, certificates, policies
On the request path?Yes — every request passes throughNo — only configures the data plane
Performance impact~1ms per hop latencyNone on request latency
Failure modeSidecar dies → service can’t communicateControl plane dies → sidecars keep working with last known config

Istio components (unified as Istiod)

Istio traffic management example

# VirtualService — canary deployment (90/10 split)
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: order-service
spec:
  hosts:
    - order-svc.internal
  http:
    - route:
        - destination:
            host: order-svc.internal
            subset: stable
          weight: 90
        - destination:
            host: order-svc.internal
            subset: canary
          weight: 10
      retries:
        attempts: 3
        perTryTimeout: 2s
        retryOn: "5xx,connect-failure"
      timeout: 10s
---
# DestinationRule — define subsets + circuit breaker
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: order-service
spec:
  host: order-svc.internal
  trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 1024
      http:
        h2UpgradePolicy: DEFAULT
        maxRequestsPerConnection: 100
    outlierDetection:
      consecutive5xxErrors: 5
      interval: 30s
      baseEjectionTime: 30s
      maxEjectionPercent: 50
  subsets:
    - name: stable
      labels:
        version: v1
    - name: canary
      labels:
        version: v2

When to use a service mesh

Use a service mesh when:
  • You have 10+ microservices with complex inter-service communication
  • You need zero-trust security (mTLS everywhere)
  • You want uniform observability without instrumenting every service
  • You need advanced traffic management (canary, fault injection, mirroring)
  • Multiple teams deploy independently and need consistent networking policies
Do NOT use a service mesh when:
  • You have fewer than 5 services — the operational complexity isn’t worth it
  • Your team doesn’t have Kubernetes expertise
  • Latency requirements are sub-millisecond (each sidecar hop adds ~1ms)
  • A simpler API gateway already solves your problems

Service mesh landscape

MeshData PlaneControl PlaneNotes
IstioEnvoyIstiodMost popular, feature-rich, complex
Linkerdlinkerd2-proxy (Rust)CustomSimpler, lighter weight, k8s-only
Consul ConnectEnvoy or built-inConsulWorks outside k8s, HashiCorp ecosystem
CiliumeBPF (kernel-level)CustomNo sidecar needed, highest performance

TLS/SSL Termination

TLS termination is the process of decrypting TLS-encrypted traffic at a specific point in your architecture. Where you choose to terminate TLS has significant implications for security, performance, and operational complexity.

Option 1: Terminate at the Load Balancer / Reverse Proxy

Client ──HTTPS──▶ [Load Balancer] ──HTTP──▶ Backend Servers (TLS terminated) Pros: Simple, centralized cert management, offloads crypto from backends Cons: Traffic between LB and backends is unencrypted (vulnerable in the internal network)

TLS Client → Load Balancer    Plain HTTP Load Balancer → Backend

Option 2: TLS Passthrough (terminate at the service)

Client ──HTTPS──▶ [Load Balancer] ──HTTPS──▶ Backend Server (TCP passthrough) (TLS terminated) Pros: End-to-end encryption, LB never sees plaintext Cons: LB can't inspect HTTP (no L7 routing), each backend needs certs

TLS Client → Load Balancer → Backend (end-to-end encrypted)

Option 3: TLS Re-encryption (terminate + re-encrypt)

Client ──HTTPS──▶ [Load Balancer] ──HTTPS──▶ Backend Server (TLS terminated (re-encrypted with + re-encrypted) internal cert) Pros: L7 features + internal encryption, defense in depth Cons: Double TLS overhead, two sets of certificates to manage

TLS (public cert) Client → LB    TLS (internal cert) LB → Backend

Option 4: mTLS everywhere (service mesh)

Client ──HTTPS──▶ [Gateway] ──mTLS──▶ Sidecar ──▶ Service A ──mTLS──▶ Sidecar ──▶ Service B │ mTLS between all services Pros: Zero-trust, automatic cert rotation, identity-based auth Cons: Operational complexity, requires service mesh infrastructure

TLS Client → Gateway    mTLS Service ↔ Service (mutual certificate verification)

TLS termination strategy comparison

StrategySecurityPerformanceComplexityBest For
At LB (HTTP backend)★★★★★★★★★★★★Internal/trusted networks
TLS Passthrough★★★★★★★★★★★★Compliance (e.g., PCI DSS)
Re-encryption★★★★★★★★★Defense in depth
mTLS (service mesh)★★★★★★★★Zero-trust microservices

Nginx TLS configuration (best practices)

server {
    listen 443 ssl http2;
    server_name api.example.com;

    # Modern TLS config (Mozilla Intermediate)
    ssl_certificate     /etc/ssl/certs/fullchain.pem;
    ssl_certificate_key /etc/ssl/private/privkey.pem;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:
                ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;

    # OCSP stapling for faster TLS handshakes
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/ssl/certs/chain.pem;
    resolver 8.8.8.8 8.8.4.4 valid=300s;

    # Session resumption (reduces handshake overhead)
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;   # Disable for perfect forward secrecy

    # HSTS
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

    location / {
        proxy_pass http://backend;
    }
}

Proxy in System Design Interviews

Proxies come up in almost every system design interview. Here’s exactly when and how to bring them up.

When to mention proxies

Rule of thumb: If your system has more than one server, you need a reverse proxy or load balancer. If you have microservices, you need an API gateway. If you have 10+ microservices, mention service mesh as a possibility.

The proxy progression in interviews

Architecture ScaleProxy LayerWhat to Say
Single server None needed “For now, one server is enough. As we scale, we’ll add a reverse proxy.”
Multiple servers Reverse proxy / LB “I’ll put Nginx/ALB in front for load balancing, TLS termination, and health checks.”
Microservices (3-10) API Gateway “An API gateway handles auth, rate limiting, and routing so each service doesn’t duplicate that logic.”
Many microservices (10+) API Gateway + Service Mesh “For internal communication, a service mesh with mTLS gives us zero-trust security and observability without code changes.”

How proxies fit in architecture diagrams

┌── CDN (CloudFront/Akamai) │ Caches static assets, terminates TLS at edge │ Users ──▶ DNS ──▶ CDN ──▶ Load Balancer (Nginx/ALB) │ TLS termination, health checks, rate limiting │ ┌─────▼────────────────────────────┐ │ API Gateway (Kong) │ │ Auth │ Rate Limit │ Routing │ └──┬──────────┬──────────┬─────────┘ │ │ │ ┌────▼──┐ ┌────▼──┐ ┌────▼──┐ │User │ │Order │ │Payment│ │Service│ │Service│ │Service│ │+Envoy │ │+Envoy │ │+Envoy │ └───┬───┘ └───┬───┘ └───┬───┘ │ │ │ ┌───▼────────▼─────────▼───┐ │ Service Mesh (mTLS) │ │ Observability, retries │ └───────────────────────────┘

Common interview questions involving proxies

🔍 Design a URL Shortener

Reverse proxy for load balancing + caching the redirect lookups at the proxy layer.

🔍 Design Twitter

API gateway for auth + rate limiting. CDN (reverse proxy) for media. Service mesh for internal comms.

🔍 Design a Chat System

Reverse proxy with WebSocket support. Sticky sessions or connection-level load balancing.

🔍 Design an E-Commerce Platform

API gateway aggregates product + pricing + inventory into one response for the product page.

Key phrases for interviews

Key takeaways