Nginx vs Caddy vs Traefik: Performance, Config, and Use Cases Compared
A hands-on comparison of Nginx, Caddy, and Traefik reverse proxies. Benchmarks, configuration complexity, SSL handling, Docker integration, and real-world...
The Reverse Proxy Decision
Every web application needs a reverse proxy. The question is which one. Nginx, Caddy, and Traefik approach the problem differently, and the right choice depends on your infrastructure and team.
A reverse proxy terminates TLS, routes requests by hostname, and load-balances across backend services.
Nginx: The Battle-Tested Workhorse
Nginx has been the default reverse proxy for over 15 years. It handles massive scale, is extremely well-documented, and is the most performant option for static file serving.
# /etc/nginx/conf.d/app.conf
upstream api_backend {
least_conn;
server app1:3000 weight=5;
server app2:3000 weight=3;
server app3:3000 backup;
}
server {
listen 80;
server_name api.example.com;
return 301 https://api.example.com$request_uri;
}
server {
listen 443 ssl http2;
server_name api.example.com;
ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
# Security headers
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
# Gzip compression
gzip on;
gzip_types text/plain application/json application/javascript text/css;
gzip_min_length 1000;
# Rate limiting
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
location /api/ {
limit_req zone=api burst=20 nodelay;
proxy_pass http://api_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Timeouts
proxy_connect_timeout 5s;
proxy_read_timeout 30s;
proxy_send_timeout 30s;
}
location /static/ {
alias /var/www/static/;
expires 30d;
add_header Cache-Control "public, immutable";
}
}
Caddy: Automatic HTTPS, Zero Config
Get more insights on Cloud Infrastructure
Join 2,000+ engineers who get our weekly deep-dives. No spam, unsubscribe anytime.
Caddy's killer feature is automatic HTTPS. Point a domain at Caddy, and it obtains and renews TLS certificates from Let's Encrypt automatically. No certbot, no cron jobs, no manual renewal.
# Caddyfile
api.example.com {
reverse_proxy app1:3000 app2:3000 {
lb_policy least_conn
health_uri /health
health_interval 10s
}
encode gzip
header {
X-Frame-Options DENY
X-Content-Type-Options nosniff
Strict-Transport-Security "max-age=31536000; includeSubDomains"
-Server
}
log {
output file /var/log/caddy/api.log
format json
}
}
static.example.com {
root * /var/www/static
file_server {
precompressed gzip br
}
header Cache-Control "public, max-age=2592000, immutable"
}
# That's it. HTTPS is automatic. No certificate configuration needed.
Traefik: Docker-Native Discovery
Traefik auto-discovers services from Docker labels. No config files to update when you add or remove services.
# docker-compose.yml
services:
traefik:
image: traefik:v3.6
command:
- --providers.docker=true
- --providers.docker.exposedByDefault=false
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --certificatesresolvers.letsencrypt.acme.tlschallenge=true
- [email protected]
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
app:
image: my-app:latest
labels:
- "traefik.enable=true"
- "traefik.http.routers.app.rule=Host(`api.example.com`)"
- "traefik.http.routers.app.entrypoints=websecure"
- "traefik.http.routers.app.tls.certresolver=letsencrypt"
- "traefik.http.services.app.loadbalancer.server.port=3000"
# Rate limiting
- "traefik.http.middlewares.app-ratelimit.ratelimit.average=100"
- "traefik.http.routers.app.middlewares=app-ratelimit"
Performance optimization funnel: each layer of optimization compounds to dramatically reduce response times.
Performance Benchmarks
Tested with wrk (10 threads, 400 connections, 30 seconds) proxying to a simple JSON API:
| Metric | Nginx | Caddy | Traefik |
|---|---|---|---|
| Requests/sec | 52,400 | 38,200 | 34,800 |
| Latency (avg) | 7.6ms | 10.5ms | 11.3ms |
| Latency (p99) | 22ms | 31ms | 35ms |
| Memory usage | 12MB | 35MB | 30MB |
| CPU usage | 15% | 22% | 25% |
| Static files/sec | 85,000 | 62,000 | N/A |
Nginx wins on raw performance, especially for static files. Caddy and Traefik are comparable, with Caddy slightly ahead.
Configuration Complexity
Lines of config to achieve the same setup (reverse proxy + SSL + rate limiting + logging):
| Task | Nginx | Caddy | Traefik |
|---|---|---|---|
| Basic reverse proxy | 15 lines | 3 lines | 5 labels |
| SSL/TLS | 8 lines + certbot setup | 0 lines (automatic) | 3 lines |
| Rate limiting | 5 lines | 3 lines | 2 labels |
| Health checks | External (upstream) | 3 lines | Docker native |
| Add new service | Edit config + reload | Edit Caddyfile + reload | Add labels (auto) |
| Total config | ~40 lines | ~15 lines | ~12 labels |
Free Resource
Free Cloud Architecture Checklist
A 47-point checklist covering security, scalability, cost optimization, and disaster recovery for production cloud environments.
Feature Comparison
| Feature | Nginx | Caddy | Traefik |
|---|---|---|---|
| Automatic HTTPS | No (needs certbot) | Yes (built-in) | Yes (built-in) |
| Docker discovery | No (manual config) | Plugin | Native |
| K8s Ingress | Ingress Controller | Plugin | Native |
| Hot reload | nginx -s reload | caddy reload | Automatic |
| WebSocket | Yes | Yes | Yes |
| gRPC | Yes | Yes | Yes |
| HTTP/3 (QUIC) | Experimental | Yes | Yes |
| Lua scripting | Yes (OpenResty) | No | No |
| Plugin system | Modules (compile-time) | Plugins (build-time) | Plugins + Middleware |
| Memory footprint | ~10-15MB | ~30-40MB | ~25-35MB |
| Config format | Custom syntax | Caddyfile / JSON | YAML / Docker labels |
| Dashboard | Nginx Plus (paid) | No | Built-in (free) |
| Commercial support | Nginx Plus | Caddy Enterprise | Traefik Enterprise |
Real-time monitoring dashboard showing CPU, memory, request rate, and response time trends.
Our Recommendation
Choose Nginx when: You need maximum performance, you serve lots of static files, you need Lua scripting or OpenResty, your team already knows Nginx, or you are running bare-metal without containers.
Choose Caddy when: You want the easiest HTTPS setup, you are running non-Docker workloads, you want a simple config file, or you are a small team that wants minimal operational burden.
Choose Traefik when: You run Docker or Kubernetes, you add/remove services frequently, you want automatic service discovery from container labels, or you want a built-in dashboard.
At TechSaaS, we run Traefik for our Docker infrastructure because automatic service discovery from labels means zero config changes when we deploy new services. We also use Nginx (as nginx:alpine) for static site serving behind Traefik — our company website is built with Next.js static export served by an Nginx container with Traefik handling the routing. Best of both worlds: Traefik for routing, Nginx for static performance.
Related Service
Cloud Solutions
Let our experts help you build the right technology strategy for your business.
Need help with cloud infrastructure?
TechSaaS provides expert consulting and managed services for cloud infrastructure, DevOps, and AI/ML operations.
We Will Build You a Demo Site — For Free
Like it? Pay us. Do not like it? Walk away, zero complaints. You will spend way less than hiring developers or any agency.
No spam. No contracts. Just a free demo.