How to Choose a Reverse Proxy: nginx, HAProxy, Envoy, Caddy, or Traefik
AppSec · practitioner · 9 min read · last reviewed 2026-08-23
All five mainstream reverse proxies will work. Choose on operating model, meaning where configuration comes from, not on benchmark numbers you will never hit.
TL;DR
- Choose a reverse proxy on operating model, meaning where configuration comes from and who is involved when it changes, because all five options are fast enough that your application will be the bottleneck first.
- Caddy if you want automatic HTTPS and the shortest config; Traefik if the container platform should be the source of truth for routing; Envoy if a control plane will drive it continuously.
- nginx remains the safe default at 31.4% of identified web servers (W3Techs, August 2026), because every failure mode you will hit is already documented by someone else.
- HAProxy is the right answer when load balancing is the job rather than a side effect, with five-year LTS branches and a runtime API that avoids config reloads.
- The criterion nobody puts in comparison tables is advisory hygiene: request smuggling comes from two parsers disagreeing, so minimize proxy hops and keep every hop current.
For most teams, all five of the mainstream reverse proxies will work, and the choice matters far less than the internet suggests. Choose on operating model, meaning where configuration comes from and who has to be involved when it changes. That decision will outlive any performance difference between them.
Which reverse proxy should you choose?
Find the row that describes how your team already works.
| Configuration should come from | Choose | Why |
|---|---|---|
| A short file, and HTTPS should handle itself | Caddy | Automatic certificates with no extra daemon and no cron job |
| The container platform, automatically | Traefik | Reads Docker and Kubernetes and builds routes from labels |
| Another program, continuously | Envoy | The xDS APIs exist so a control plane can drive it |
| A reviewed file, tuned by hand, at high volume | HAProxy | The deepest health checking, queueing, and statistics |
| A reviewed file, and you want the boring option | nginx | The largest body of production experience of any proxy |
If none of those rows is obviously yours, use nginx. It is the default for a reason: at 31.4% of identified web servers (W3Techs, August 2026), every problem you hit has been hit before and written up by someone else.
What a reverse proxy actually does for you
A reverse proxy sits in front of your application, accepts requests on its behalf, and decides what reaches it. Because it is the one point every request passes through, it is where you get a single chance to apply a rule to everything.
The jobs it takes off your application:
- TLS termination. One place holds the certificates, one place gets the renewal right.
- Routing. One domain in front, several services behind, decided by hostname or path.
- Load balancing. Requests spread across backends, with unhealthy ones taken out.
- Caching and compression. Work your application does not repeat.
- Rate limiting and security headers. A rule applied to every endpoint, including the one somebody forgot about.
- Authentication. Increasingly, identity checked before the request reaches application code at all.
That concentration is also the risk. A misconfiguration at the proxy is universal too, and if the origin servers are still reachable directly, the whole boundary is decorative. Restrict the origins to accept traffic only from the proxy, or you have built a gate with no fence.
The five, and who each one is for
nginx
The default. It runs on modest hardware, its configuration is a declarative file that reviews cleanly in a pull request, and one syntax covers reverse proxying, static files, caching, and plain TCP proxying. What you give up is automatic HTTPS, which becomes a separate moving part you own, and dynamic backends, which need the commercial NGINX Plus or a workaround. Track mainline 1.31.4 or stable 1.30.4.
HAProxy
Choose it when load balancing is the job rather than a side effect. Its health checking, connection queueing, and per-backend statistics are the most thorough here, and the runtime API lets you drain a server without a config reload, which matters during deploys. The long-term support branches are maintained for five years, which is unusually serious for infrastructure you do not want to keep re-platforming. Current stable is 3.4.3, released 29 July 2026.
Envoy
The only one of the five designed to be configured by a program rather than a person. Its xDS APIs stream routes and endpoints to the running proxy with no reloads, which is why it became the data plane inside Istio, Consul, and most Kubernetes gateway implementations. Hand-writing static Envoy YAML is a miserable experience and is not how the project intends you to use it. If you are not prepared to run a control plane, you are taking on the complexity without the payoff.
Caddy
Obtains and renews TLS certificates automatically, with no additional components and no configuration. That single property removes the most common self-inflicted outage in small deployments, which is a certificate nobody was watching. It ships as one static Go binary, so deployment is a file copy and upgrading is a file replacement. The cost is ecosystem size: at 0.7% of identified web servers, fewer people have already written up your unusual problem.
Traefik
Reads your container platform and builds its own routing table from it. Add a label to a Docker service or an Ingress resource in Kubernetes and the route exists, with a certificate, without anyone editing a proxy config. Outside a container platform it loses most of that advantage while keeping its two-tier static-plus-dynamic configuration model, which is the wrong trade. Current is 3.7.11 on the v3 line.
The selection criterion nobody lists: advisory hygiene
Here is a criterion worth more than any feature comparison: how current can you actually keep this thing, and how does the project handle security advisories?
The class of bug that matters most for a proxy is HTTP request smuggling. It happens when the proxy and the backend disagree about where one request ends and the next begins, which lets an attacker prepend content onto another user's request. Two 2026 examples show the shape:
- CVE-2026-33555, published 13 April 2026, in HAProxy's HTTP/3 parser. It failed to verify that the body length received matched the announced content length when a stream closed with an empty-payload frame. Affects 2.6.0 through 3.3.5, fixed in 3.3.6.
- CVE-2026-6324, published 29 May 2026, an unsigned-to-signed conversion error in libsoup's chunked-body reader, exploitable specifically when a libsoup application sits behind a proxy that is not libsoup.
Neither is really a flaw in "the proxy". Both are two parsers disagreeing. Three consequences follow:
- Minimize hops. Every extra proxy in the chain is another parser that can disagree with its neighbour.
- Keep every hop current. A distribution package three years behind is the usual way teams stay exposed to bugs fixed upstream long ago.
- Prefer a proxy your team will actually upgrade. A single static binary gets upgraded. A hand-tuned config nobody wants to touch does not.
There is also a governance dimension. In February 2024, core nginx developer Maxim Dounin forked the project as freenginx, stating on the nginx development mailing list that F5 had overridden the project's own security policy by forcing a security release for bugs in experimental HTTP/3 code. freenginx is still actively released, with mainline 1.31.3 in July 2026. This changes nothing operational about nginx today. It matters only if independent open-source governance is a stated requirement in your procurement process, and it is better to know now than to be asked later.
What to do next
- For the architecture behind all of this, including how reverse and forward proxies differ and where each sits in Zero Trust, read Proxies Explained.
- For a ranked comparison of these five with pricing and honest weaknesses, see Top 5 Reverse Proxies for 2026.
- If your question is actually about outbound traffic rather than inbound, you want a forward proxy instead.
Key takeaways
- If no row of the decision table is obviously yours, use nginx and move on to a problem that matters more.
- A reverse proxy in front of origins that are still directly reachable is decoration, not a boundary. Restrict the origins.
- Hand-writing static Envoy YAML means you took on the complexity and skipped the payoff. Bring a control plane or choose something else.
- Automatic HTTPS is worth more than any performance difference to a team with nobody watching certificate expiry.
- Every additional proxy hop is another parser that can disagree with its neighbour about where a request ends. Keep the chain short and deliberate.
- The nginx governance split matters only if independent open-source governance is a procurement requirement, but you should know about it before you are asked.
Frequently asked questions
- What is the difference between a reverse proxy and a load balancer?
- A load balancer distributes traffic across several backend servers. A reverse proxy sits in front of backends and can do many things, of which load balancing is one: it also terminates TLS, routes by host or path, caches, compresses, and enforces authentication. Every load balancer here is a reverse proxy, but plenty of reverse proxies sit in front of one backend and balance nothing.
- Is nginx still the right default in 2026?
- For most teams, yes. It runs 31.4% of identified web servers as of August 2026, so its failure modes are thoroughly documented, and it is undemanding on resources. The two reasons to look elsewhere are automatic HTTPS, where Caddy is simply better, and dynamic service discovery, where Traefik and Envoy are built for it and nginx is not.
- Do I need a reverse proxy if my application already serves HTTPS?
- Often yes. A reverse proxy gives you one place to terminate TLS, one place to enforce rate limits and security headers, and the ability to change what is behind a URL without touching DNS. If you run exactly one process on one host and expect that to stay true, you can reasonably skip it.
- Which reverse proxy is easiest to operate with containers?
- Traefik, because it reads the container platform directly and builds routes from Docker labels or Kubernetes resources with no manual configuration. Envoy reaches the same outcome through a control plane, which is more capable and more work to run. Both remove the config-edit step from your deploy process.
- How does my proxy choice affect HTTP request smuggling?
- Less than your patch level does. Smuggling happens when two hops disagree about where a request ends, so the root causes are mismatched parsers and outdated software rather than a particular vendor. CVE-2026-33555 in HAProxy and CVE-2026-6324 in libsoup are both 2026 examples of the same class.
Related
Vendor comparisons
Sibling guides