Proxies are traffic middlemen. Done right, they cut latency, reduce origin load, unlock security controls, and make failure boring. This article explains forward vs reverse proxies, shows how caching actually works, and provides copy-paste snippets to deploy them in the real world.

Stylized hero graphic with shield and arrows representing proxies
Proxies sit in the middle—on purpose.
TL;DR
  • Forward proxy: sits in front of clients. Common for office egress, content filtering, privacy, and CONNECT tunneling.
  • Reverse proxy: sits in front of servers. Terminates TLS, balances load, rewrites headers, caches responses, protects origins.
  • Caching: treat it as a hierarchy (browser → proxy/CDN → origin shield → origin). Use Cache-Control, validators (ETag/Last-Modified), and stale directives to keep pages fast even when backends wobble.

Forward vs reverse proxies (in one minute)

Forward proxies relay traffic on behalf of a client. The client (or its OS) is configured to send requests to the proxy, which then makes outbound connections to the public internet. Organizations deploy forward proxies for egress security, logging, filtering, bandwidth controls, and sometimes anonymity. In HTTP, a forward proxy may accept absolute-form URLs or tunnel TLS via CONNECT.

Reverse proxies represent an application to the outside world. Clients think they are talking to the website; the reverse proxy fans traffic out to many application servers, handles TLS, and implements performance policies like compression and caching. A CDN is a globe-spanning network of reverse proxies.

What a forward proxy does

  • Access control & filtering: block destinations, enforce auth, apply category or malware filters.
  • Identity & policy: tie traffic to user/host identity for audit. Inject headers (e.g., X-Authenticated-User) to help egress controls.
  • Privacy: mask client IP from destinations; rotate egress IPs.
  • Cost & bandwidth: cache common downloads, throttle heavy users, and prefetch updates.
  • TLS tunneling: with CONNECT, the proxy creates a TCP tunnel to a target host:port. Optional TLS interception (“break and inspect”) requires installing a private root CA on clients and should be narrowly scoped.

Example: minimal corporate forward proxy (Squid-like)

# Clients set http_proxy/https_proxy or a PAC file
# Allow internal subnets; require auth for egress
acl our_net src 10.0.0.0/8 192.168.0.0/16
http_access allow our_net
http_access allow authenticated_users
http_access deny all

# Cache large downloads for a short time
cache_dir aufs /var/spool/proxy 20000 16 256
refresh_pattern -i \.(msi|zip|deb|exe)$  4320  50%  10080

What a reverse proxy does

  • TLS termination & HTTP/2/3: manage certificates, enable modern protocols, and offload crypto from app servers.
  • Load balancing: distribute requests across many backends with health checks and circuit-breakers.
  • Header & URL normalization: add/remove headers, strip hop-by-hop fields, and canonicalize URLs.
  • Request shaping: rate limits, timeouts, body size limits, and slowloris protection.
  • Caching & edge logic: serve popular content from memory/disk; run small functions at the edge.
  • Security controls: WAF, bot rules, auth offload (OIDC), and IP reputation checks.

Example: reverse proxy with caching (Nginx)

proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=cdn_cache:512m max_size=20g inactive=60m use_temp_path=off;

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

  # TLS certs here

  location / {
    proxy_pass http://origin_pool;
    proxy_cache cdn_cache;
    proxy_cache_valid 200 301 302 30m;
    proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
    add_header X-Cache-Status $upstream_cache_status;
  }
}

How HTTP caching actually works

A cache stores a response and reuses it to satisfy later, equivalent requests. “Equivalent” means the same method, URL, and a compatible set of request headers when Vary is in play. Each cache entry has a freshness lifetime (its TTL). If an entry is fresh, the cache serves it immediately. If it’s stale, the cache can revalidate with the origin using validators or fetch a new copy.

Headers that control caching

  • Cache-Control: the policy knob. Key directives include public/private, max-age, s-maxage (for shared caches like CDNs), no-store, no-cache (requires revalidation), must-revalidate, stale-while-revalidate, and stale-if-error.
  • Expires: legacy absolute timestamp; superseded by max-age but still honored.
  • Validators: ETag (an opaque fingerprint) and Last-Modified. A cache can send If-None-Match or If-Modified-Since; a 304 Not Modified response refreshes freshness without retransmitting the body.
  • Vary: declares which request headers make responses different variants (e.g., Accept-Encoding, Accept, DPR, custom AB-test cookie). Use sparingly to avoid cache fragmentation.

Freshness, staleness, and survival modes

Design for graceful degradation. With stale-while-revalidate, a reverse proxy serves a slightly stale entry immediately and refreshes it in the background. With stale-if-error, the cache can serve a stale copy when the origin is down or returns 5xx. This keeps pages alive during deploys and incidents.

Shared vs private caches

Browsers are private caches (per user). Proxies and CDNs are shared caches with many users behind them. Prefer s-maxage for policies aimed at shared caches without affecting browser behavior. Mark personalized or confidential responses as private or no-store.

Cache keys and normalization

The cache key defines uniqueness—usually scheme + host + path + query + selected headers. Normalize URLs (strip tracking params), unescape case, and trim irrelevant headers to improve hit rates. If your app requires many variants (e.g., language, device), consider surrogate keys: tag responses (e.g., Surrogate-Key: post:123 category:news) so you can purge by tag.

Purging & invalidation

  • Time-based: short max-age/s-maxage for rapidly changing pages; longer for assets with content hashes.
  • Event-based: explicit API to purge by URL or surrogate key on publish/update.
  • Soft purge: mark stale and rely on stale-while-revalidate to refresh quickly without stampedes.

A practical caching strategy

What to cache

  • Static assets: JS/CSS/fonts/images with hashed filenames. One year TTL, immutable.
  • API and HTML: cache safe GETs for seconds-to-minutes; enable background revalidation and serve-stale on errors.
  • Downloads: installers and packages at the forward proxy to save bandwidth.

What not to cache

  • Personalized responses (unless using key-segmented caches).
  • Non-idempotent methods (POST/PUT/PATCH/DELETE).
  • Sensitive data: mark no-store.
Diagram: browser → forward proxy → reverse proxy/CDN → origin; responses can be served from any cache
Any layer with a fresh copy can satisfy the request immediately.

Cache hierarchy & request coalescing

Layer caches to reduce origin load. The edge (reverse proxy) sits closest to users; a regional shield (“mid-tier”) sits between the edge and origin to absorb misses and collapse duplicate fetches. The shield turns hundreds of concurrent edge misses for the same URL into a single origin request.

Diagram of cache hierarchy: browser cache, forward proxy, CDN edge (reverse proxy), mid-tier shield, origin server
Hierarchy: browser → forward proxy → edge → shield → origin.

Implementation snippets

Varnish (reverse proxy) with stale controls

vcl 4.1;
backend default { .host = "origin"; .port = "80"; }

sub vcl_backend_response {
  if (beresp.status == 200) {
    set beresp.ttl = 5m;
    set beresp.grace = 30m;      # serve stale while revalidating
    set beresp.keep = 1h;        # keep even if not cacheable for 1h for collapsed reqs
  }
}

Nginx: origin shield & cache bypass

map $http_cache_control $bypass_cache {
  "~*no-cache" 1;
  default 0;
}

proxy_cache_background_update on;
proxy_cache_revalidate on;

location /api/ {
  if ($bypass_cache) { set $skip 1; }
  proxy_pass http://shield.example.net;
  proxy_cache cdn_cache;
  proxy_no_cache $skip;
  proxy_cache_bypass $skip;
}

Handling Vary, compression, and device hints

  • Compression: enable Brotli/gzip at the reverse proxy. Vary on Accept-Encoding so caches keep compressed/uncompressed variants straight.
  • Device & density: if you vary images by DPR, width, or MIME type, prefer URL-based negotiation (/img/hero@2x.webp) or respond with the same URL but include Content-DPR and vary on DPR. Avoid exploding the variant space.
  • Language: consider ?lang=en instead of Vary: Accept-Language to prevent cache fragmentation.

Observability: know your hit rates

Emit per-request headers such as X-Cache: HIT/MISS, Age, and whether the response was served stale. Sample logs with the cache key and whether a revalidation occurred. Track hit ratio and, more importantly, byte hit ratio (what truly reduces bandwidth). Build alerts for sudden drops or increases in revalidation traffic.

Security considerations

  • Isolation: a reverse proxy is part of your perimeter. Minimal packages, automatic patching, and locked-down egress.
  • Cookie handling: strip or encrypt cookies at the edge; set HttpOnly/Secure/SameSite.
  • Header sanitation: remove X-Forwarded-* from clients; set your own consistent chain (Forwarded or X-Forwarded-For).
  • Request smuggling & split handling: standardize on HTTP/1.1 or strict HTTP/2 parsing at boundaries; upgrade backends when possible.
  • TLS interception: in forward proxies, keep “break and inspect” to high-risk destinations only and ensure consent and compliance.

Common failure modes and fixes

Cache stampede

Many edges miss at once and hammer the origin. Fix with request coalescing (only one origin fetch per key), randomized TTL jitter, and stale-while-revalidate.

Cache poisoning

Attackers manipulate Vary or query params to inject harmful content. Fix with strict header allow-lists, normalized cache keys, and a WAF.

Auth leaks

Shared caches serve personalized responses. Fix by marking auth pages private, no-store and separating static from dynamic paths.

Double-cache surprises

Browsers and the edge cache disagree. Observe Age and Cache-Control in responses; use s-maxage for shared caches and conservative max-age for browsers.

Encoding mismatches

Serving compressed responses to clients that don’t support them. Fix by honoring Accept-Encoding and keeping variants separate.

Bypass tunnels

Forward proxy rules allow CONNECT to unmonitored ports. Fix with allow-listed destinations and TLS SNI inspection.

Checklist for production

  • Define cacheable routes and TTLs; instrument X-Cache headers.
  • Normalize cache keys; avoid variant explosion.
  • Enable stale-while-revalidate and stale-if-error.
  • Implement shield tier and request collapsing.
  • Set limits and timeouts near the client; keep origins simple.
  • Handle purge events and deploys without downtime.

Deployments & tool choices

HAProxy excels at L4/L7 load balancing with lean performance. Nginx is a versatile reverse proxy with solid caching and HTTP/3 support. Varnish leads for advanced caching logic via VCL. Envoy brings modern observability, gRPC, and dynamic configuration (great in service meshes). Squid remains a workhorse forward proxy. Traefik simplifies container-native routing with automatic certificate management.

  • If you need edge logic with caching, consider Varnish or Nginx plus a CDN tier.
  • For service-to-service meshes, Envoy is a safe pick.
  • For corporate egress, Squid or a managed secure web gateway works well.

Testing and debugging caching

# Inspect response caching signals
curl -I https://example.com/ | sed -n '1,20p'

# Force revalidation with validators
curl -H "If-None-Match: <etag>" -I https://example.com/

# See what the browser stored (Chrome)
# DevTools > Network > Disable cache (unchecked), look for Age, Cache-Control, Vary

FAQ

Is a CDN the same as a reverse proxy? A CDN is a globally distributed network of reverse proxies. Many sites also run a reverse proxy inside their cloud/VPC as an internal front door in addition to a CDN.

Do forward proxies help my website’s end users? Not directly. They benefit the organization running the proxy (security, bandwidth, policy). End-user performance is dominated by reverse proxies and CDNs.

Can I cache HTML safely? Yes—when it’s the same for many users. Keep personalized content behind APIs or edge includes, use short TTLs, and enable stale-while-revalidate.

Last updated Aug 20, 2025.