What Is a Reverse Proxy?
A reverse proxy is a server that sits between clients and your backend servers. It receives requests from clients, forwards them to the appropriate backend server, and returns the server's response to the client. From the client's perspective, it is communicating directly with the reverse proxy — it has no visibility into the backend servers.
This is the opposite of a forward proxy, which sits in front of clients (often used for internet access filtering or anonymization). A reverse proxy sits in front of servers.
Popular implementations: NGINX, HAProxy, Envoy, Caddy, and Apache HTTP Server with mod_proxy.
What a Reverse Proxy Does
SSL/TLS termination: the reverse proxy handles the HTTPS handshake and decrypts incoming requests. Backend servers receive plain HTTP, removing the CPU overhead of TLS from application code. The proxy re-encrypts traffic when forwarding to backends if required (mutual TLS).
Load balancing: distributing requests across multiple backend instances using round-robin, least-connections, IP hash, or weighted algorithms. The proxy tracks which backends are healthy via active health checks.
Caching: serving cached responses for frequently requested content without forwarding the request to the backend. Reduces origin load for static or infrequently-changing content.
Compression: gzip or Brotli compressing responses before sending to the client, reducing bandwidth consumption. Backend servers can serve uncompressed responses and let the proxy handle compression.
Request routing: routing different URL paths or subdomains to different backend services — /api/ to the API cluster, /static/ to an object store, / to the web server. This is how a single domain can front multiple backend services.
Security: hiding backend server IPs, blocking malicious IPs, enforcing rate limits, validating request headers, and providing a centralized point to apply WAF (Web Application Firewall) rules.
Reverse Proxy vs Load Balancer
The distinction is more architectural than technical — modern software (NGINX, HAProxy, Envoy) can do both simultaneously.
A load balancer's primary purpose is distributing traffic across multiple identical backend instances to scale and improve availability. You use a load balancer when you have multiple servers serving the same application.
A reverse proxy's primary purpose is providing a unified interface in front of backend services, regardless of how many instances exist. Even with a single backend server, a reverse proxy adds value: SSL termination, caching, security, and routing.
In practice: deploy a reverse proxy in front of every application, even with one backend instance. Upgrade it to also do load balancing when you scale to multiple instances. Many systems use both: a load balancer at the network edge (Layer 4, routing TCP connections) and an application-layer reverse proxy (Layer 7, understanding HTTP) behind it.
Layer 4 vs Layer 7 Proxying
Layer 4 proxy (transport layer): operates on TCP/UDP packets. Forwards connections without inspecting the payload. Extremely fast and low-latency because it does not parse HTTP. Can forward any TCP/UDP protocol. Uses the client's source IP and destination IP/port to make routing decisions. Cannot route based on URL paths or HTTP headers. Examples: AWS NLB, HAProxy in TCP mode.
Layer 7 proxy (application layer): understands HTTP/HTTPS. Can route based on URL paths, HTTP headers, cookies, and request body. Enables SSL termination, content-based routing, A/B testing, canary deployments, and request transformations. Higher CPU overhead than Layer 4 but enables far more sophisticated traffic management. Examples: NGINX, Envoy, AWS ALB, Cloudflare.
Typical production architecture: Layer 4 NLB in front for fast TCP fan-out across multiple Layer 7 proxy instances, which then route HTTP requests to backend application clusters.
Common Load Balancing Algorithms
Round robin: each new request goes to the next backend in a circular list. Simple, even distribution. Fails when backends have unequal capacity or when requests have unequal cost (a 10ms request vs a 10-second request both count as "one request").
Least connections: route to the backend with the fewest active connections. Better than round-robin when request duration varies significantly. Ensures overloaded backends receive fewer new requests.
Weighted round robin: assign each backend a weight proportional to its capacity. A backend with weight 3 receives 3× more requests than one with weight 1. Use when backends have different CPU/RAM capacities.
IP hash: hash the client's IP to a backend. The same client always hits the same backend (sticky routing). Useful for protocols that require session affinity and where storing sessions in a shared store is not feasible.
Least response time: route to the backend with the lowest average response time. Automatically avoids slow backends. Used by advanced proxies like NGINX Plus and Envoy.