Skip to content

HAProxy vs Nginx vs Traefik

Choosing between HAProxy, Nginx, and Traefik — what each is genuinely best at, where they overlap, and the decision criteria we apply for client deployments.

The three reverse proxies engineers reach for most often — HAProxy, Nginx, Traefik — solve overlapping problems with different design centers. Pick the wrong one and you fight the tool for years. This article is the decision matrix we apply when standing up a client environment: what each is genuinely best at, where they overlap, and the criteria that decide which one fits a workload.

How to verify

If you inherited a proxy you didn’t choose, identify it and its role:

ss -ltnp | grep -E ':(80|443)\b'
ps auxf | grep -E 'haproxy|nginx|traefik'
which haproxy nginx traefik 2>/dev/null
cat /etc/haproxy/haproxy.cfg /etc/nginx/nginx.conf /etc/traefik/traefik.yml 2>/dev/null | head -50

The presence of traefik.yml and a process named traefik is unambiguous. Both HAProxy and Nginx live in their own conf files; the directory structure is the giveaway (/etc/haproxy/ vs /etc/nginx/).

Decision

The decision turns on five questions: traffic profile, configuration style, ecosystem integration, observability needs, and operator skillset.

  1. HAProxy — best when:

    • Pure performance matters at the L4/L7 edge. HAProxy is the fastest of the three for raw TCP and HTTP/1.1 forwarding.
    • You need real load balancing — weighted, dynamic, with stick-tables and peer replication.
    • mTLS, advanced ACLs, content switching, rate limiting via stick-tables are first-class.
    • Hot reload with zero dropped connections is required (master-worker model).
    • The runtime API gives you live operational control (disable servers, swap certs, change weights) without reload.
    • Stick tables provide stateful in-process counters for sessions, rate limits, and gpc.
    • You are willing to maintain a config file under change control.

    Less ideal when: you want auto-discovery from Docker labels or Kubernetes annotations (HAProxy has the Kubernetes Ingress Controller and the Data Plane API, but they are heavier than Traefik’s native discovery).

  2. Nginx — best when:

    • You are serving static content, handling many small files, doing fastcgi to PHP-FPM, or proxying to one or two upstreams.
    • The reverse-proxy role is secondary to web-serving.
    • You need rich URL rewriting, sophisticated cache control with proxy_cache, or many small per-location overrides.
    • The team already knows Nginx config syntax (Nginx is ubiquitous; most ops engineers have written server { location { } } blocks).
    • You want a single binary that handles TLS, static serving, FastCGI, and reverse proxy in one config.

    Less ideal when: you need true load balancing with health checks, dynamic backends, rate limiting beyond the basic limit_req module, or in-process state across requests. Nginx Plus has these, but it is commercial.

  3. Traefik — best when:

    • Containers are first-class. Traefik discovers services from Docker labels, Kubernetes CRDs, Consul, Nomad, AWS ECS — zero config file rewrites for routing changes.
    • Let’s Encrypt auto-provisioning is a non-negotiable.
    • The team wants a single binary with a dashboard, metrics endpoint, and dynamic config out of the box.
    • You operate a microservice topology where service identity changes frequently (deploys, autoscaling).

    Less ideal when: you need raw L4 performance, deterministic config under Git, complex ACLs, or stick-table state. Traefik improved a lot but still trails HAProxy at the high-throughput edge.

Side-by-side

ConcernHAProxyNginxTraefik
L4 (TCP) load balancingFirst-classstream moduleYes, but limited
L7 (HTTP) routingFirst-classFirst-classFirst-class
Hot reload, no dropped connectionsYes (master-worker)Yes (workers)Yes
Dynamic backend discoveryStatic + Data Plane APIStatic + commercial PlusNative (Docker, K8s, Consul)
Let’s Encrypt built-inNo (use certbot)No (use certbot)Yes
Runtime API for opsYes (admin socket)Commercial Plus onlyDashboard + API
Rate limitingStick-tables (rich)limit_req (basic)Middleware
Stick sessionsYes (cookie + tables)Yes (sticky cookie)Yes (sticky cookie)
mTLS client certYesYesYes
Static file servingNoFirst-classNo
Performance at edgeHighestHighGood
Config complexityMedium-highMediumLow (auto-discovery)
ObservabilityStats page + PrometheusStatus module + commercialDashboard + Prometheus
Learning curveHigherLowerLowest

How we choose for clients

The decision tree we use:

  • Edge of a multi-region or clustered platform, public APIs, strict performance budget? HAProxy.
  • Public website that mixes static assets, PHP-FPM, and a few proxied paths? Nginx (with HAProxy in front if multi-region).
  • Container platform (Docker Compose, Kubernetes) where services come and go? Traefik (or HAProxy with the K8s Ingress Controller if performance dominates).
  • Mixed: an Nginx for the website + HAProxy in front for HA and routing. Common in our deployments; the two coexist gracefully.

We rarely run only Traefik for high-traffic public APIs. We rarely run only Nginx as a load balancer for clustered apps. HAProxy is the default at the public edge for clients with non-trivial traffic.

Operational notes

  • All three support graceful reload, but only HAProxy makes runtime operations (drain a server, swap a cert) trivial without reload.
  • Nginx’s proxy_pass is the most flexible at URL rewriting; HAProxy’s http-request set-path is less expressive but covers 95% of cases.
  • Traefik’s dashboard is convenient but should never be public-facing without authentication; the same caution applies to HAProxy’s stats page and Nginx’s stub_status.
  • Migrating from one to another is painful — config syntax, observability tooling, runbooks all change. Get the choice right at the start.
  • Hybrid deployments (HAProxy → Nginx, or Traefik → HAProxy) add a hop but let each tool play to its strengths. This is common in production.

Stack Harbor picks the proxy that matches the workload. For clients running clustered applications where performance and operational control matter most, HAProxy sits at the edge. For containerized platforms where services come and go, Traefik often goes in. Nginx handles website-shaped workloads. We document the choice and its rationale in the operating playbook — this is what we ship as part of Managed Operations so the next engineer who inherits the environment knows why, not just what.