backend / protocols / nginx / 14_alternatives_comparison.md

Nginx vs Alternatives

6 interview angles 7 min read source

Nginx vs Alternatives

Comparison interviewers reach for: Apache, Caddy, Traefik, Envoy, HAProxy. Each fits a different operational style. Pick by feature requirements + ops model, not benchmarks (most are within a small constant factor of each other on common workloads).

At a glance

Tool Best at Config style Auto-TLS Service-mesh When to pick
nginx reverse proxy, static, general HTTP text file (custom syntax) with certbot plugin basic the default — known, fast, ubiquitous
Apache (httpd) shared hosting, .htaccess, mod_php text + per-dir overrides mod_md no legacy or PHP shared hosting
Caddy small deploys, auto-TLS Caddyfile or JSON built in no “I want HTTPS in 1 line of config”
Traefik docker / k8s with dynamic backends label-based, reads docker/k8s API built in yes container-heavy, dynamic environments
Envoy service mesh, observability YAML / xDS API with cert manager core component k8s service mesh (Istio/Consul/AWS App Mesh)
HAProxy L4/L7 load balancing, raw TCP text file with external acme.sh no maximum-throughput LB, especially L4

Apache — the elder

Apache nginx
Concurrency prefork (process per request), worker (threads), event (closer to nginx) event-driven
Config per-directory .htaccess overrides central config only
Modules huge, including mod_php running PHP in-process smaller, all compiled-in (no runtime modules in OSS)
Perf at high concurrency OK with event MPM, behind nginx in practice excellent

Apache’s .htaccess (per-directory configs read on each request) is a big part of its identity — convenient for shared hosting where each user uploads their own. Nginx doesn’t have this; config is centralized.

Most modern PHP deploys: nginx + php-fpm (FastCGI). Apache + mod_php is increasingly rare.

Caddy — config minimalism + auto-HTTPS

api.example.com {
    reverse_proxy localhost:8000
}

That’s a complete production-ready config: HTTPS via Let’s Encrypt automatically, HTTP/2, sensible defaults. Caddy obtains and renews certs without certbot, without a cron job, without thinking.

Caddy nginx
Auto-HTTPS yes, default needs certbot
Config declarative, terse imperative-feeling, verbose
HTTP/3 built in nginx 1.25+
Module ecosystem growing huge
Performance competitive slightly faster on bulk static
Ops familiarity growing universal

Pick Caddy for: small services, anything where the team values config simplicity, dev environments, side projects. nginx wins for: large infrastructures where the team already knows it cold.

Traefik — for dynamic backends

Traefik reads service definitions from Docker labels, Kubernetes annotations, Consul, etc. Backends register/deregister automatically — no config reload needed.

# docker-compose.yml
services:
  api:
    image: myapp
    labels:
      - "traefik.http.routers.api.rule=Host(`api.example.com`)"
      - "traefik.http.routers.api.tls.certresolver=letsencrypt"
Traefik nginx
Auto-discovery Docker, k8s, Consul, file static config; needs reload to update upstreams
Auto-HTTPS yes needs certbot
Dashboard built-in web UI none in OSS
Performance competitive at moderate scale wins at very high RPS
Ops complexity higher (state) lower (stateless)

Pick Traefik for: container-heavy environments where pods come and go constantly. nginx for: static or slowly-changing backend lists.

Envoy — service mesh proxy

Envoy is what powers Istio, Linkerd 2, AWS App Mesh, Consul Connect. Designed for sidecar deployments next to every service.

Envoy nginx
Config YAML / xDS gRPC API text file
Dynamic config first-class via xDS reload-only in OSS (NGINX Plus has API)
Observability rich metrics, tracing, access logs by default basic; needs add-ons
Service mesh core component not designed for it
HTTP/2, gRPC, HTTP/3 first-class also supported, less mature historically
Resource use higher lower
Learning curve steep gentle

Envoy is overkill as a single edge proxy. It shines as a sidecar where every microservice needs the same observability + routing primitives.

For a Python team running 5 services, nginx + Prometheus is fine. For 500 services with mTLS everywhere, Envoy via Istio.

HAProxy — load balancer focus

HAProxy is the load-balancing specialist. Less feature-rich on the edge (no built-in cache, weaker static file serving), but the LB feature set is deep.

HAProxy nginx
L4 (TCP) load balancing excellent OK (stream block)
L7 (HTTP) load balancing excellent, deep stats excellent
Static file serving minimal excellent
Reverse proxy with caching minimal excellent
Active health checks yes, built-in NGINX Plus only
Stick tables (session affinity, rate limiting state) rich basic
Config text DSL text DSL (different)

Pick HAProxy for: pure load balancing with rich health-check requirements (Postgres, MySQL, Redis pools). Pick nginx for: L7 reverse proxy + static + cache + TLS termination.

Some teams: HAProxy for L4 in front, nginx for L7 behind it. Or both standalone for different purposes.

Cloud-managed alternatives

Cloud Equivalent Notes
AWS ALB L7 LB + TLS + WAF managed; can replace edge nginx
AWS NLB L4 LB for non-HTTP, very high throughput
AWS CloudFront CDN + edge for global static + edge cache
GCP Cloud Load Balancer L7/L4 managed equivalent
Azure Application Gateway L7 LB + WAF managed equivalent
Cloudflare CDN + WAF + edge proxy sits in front of any origin

A common modern shape: Cloudflare/CloudFront edge → ALB → nginx (or skip nginx, ALB straight to app pods). Each layer adds features and cost; skip ones you don’t need.

When you’d skip nginx entirely

  • Containerized k8s deploy with ingress controller — the ingress is your nginx (often literally ingress-nginx), but you don’t write its config directly; you write Ingress resources.
  • Heroku / Fly.io / Railway — the platform terminates TLS and routes to your container. No nginx needed.
  • AWS App Runner / Fargate behind ALB — ALB is the edge.
  • Static site on Netlify / Vercel / S3+CloudFront — no origin server at all.

For any of these, the nginx knowledge still applies (config concepts map), but you may never run a standalone nginx process.

Why nginx is still the default

  • Lightweight, predictable, well-documented.
  • One binary, one config file, easy to reason about.
  • Battle-tested for 15+ years.
  • Skills transfer across companies.
  • Performs at the level most teams need without tuning.

The alternatives shine in specific scenarios but introduce more moving parts. Nginx is the “sensible default” choice unless you have a specific reason to deviate.

Common interview confusions

  • “Caddy is faster than nginx because of Go.” — measurably similar on most workloads. Caddy’s selling point is config + auto-TLS, not raw speed.
  • “Envoy can replace nginx.” — yes technically, but the ops model is different. Envoy expects dynamic config from a control plane (xDS); standalone Envoy with static YAML is awkward.
  • “HAProxy and nginx do the same thing.” — overlap heavily, but HAProxy is a load balancer with proxy features; nginx is a web server / proxy with LB features. Different center of gravity.
  • “You always need nginx in front of Gunicorn.” — in self-managed VMs, yes. In containerized cloud platforms, often not — the platform’s LB does the job.

Interview angle

  • “When would you pick Caddy over nginx?” — small deploys, dev environments, any time auto-HTTPS and config minimalism matter more than maximum throughput or ecosystem familiarity.
  • “Traefik vs nginx for a containerized app?” — Traefik for dynamic discovery (services come and go); nginx for stable upstream lists. Traefik integrates natively with Docker labels / k8s annotations; nginx needs templating and reloads.
  • “Why do service meshes use Envoy?” — designed for dynamic config via xDS API, sidecar deployment, rich observability, mTLS as a first-class feature. Nginx isn’t designed for the per-pod-sidecar pattern.
  • “HAProxy vs nginx for load balancing?” — HAProxy has deeper LB features (active health checks, stick tables, richer stats). Nginx is simpler when you also need TLS, caching, and static serving in the same component.
  • “Does nginx still matter in cloud-native deployments?” — yes, often inside the cluster (ingress-nginx is the most common k8s ingress controller). The skill transfers to ALB / CloudFront / Caddy / Envoy concepts.
  • “Apache vs nginx today — which would you pick?” — nginx for almost any new project. Apache for legacy environments using .htaccess-driven configs or mod_php shared hosting.