# Caddy vs Nginx: Which Web Server and Reverse Proxy Should You Choose?

A practical comparison of Caddy and Nginx for HTTPS, reverse proxying, load balancing, caching and production deployment.

## Start with a real deployment

Suppose an app listens only on port 8080 on a Linux host. Users need a domain and HTTPS, while the app itself should stay off the public internet. Nginx or Caddy can become the entry point and forward requests to the app. They differ in configuration, certificate lifecycle, feature scope and operations. This article aims to match the tool to your environment, not name a universal winner.

## What happens between a browser and an app?

A browser resolves a domain with DNS and sends an HTTP request. A web server accepts requests and serves files. A reverse proxy sits on the server side, chooses a backend and returns its response. If an app listens on 127.0.0.1:8080, the proxy can be the only public entry point. HTTPS carries HTTP inside encrypted TLS; a certificate helps the browser verify the domain identity. Client-to-proxy and proxy-to-backend TLS are separate trust boundaries.

![What happens between a browser and an app?](/assets/img/articles/content/caddy-vs-nginx-web-server-reverse-proxy/caddy-vs-nginx-reverse-proxy-architecture.png)

## What Nginx does

Nginx is an event-driven web server and proxy. It can serve static files, terminate TLS, forward requests, distribute traffic and cache selected responses. It is common at website and API entry points, especially where teams already have mature operational patterns. Its architecture does not guarantee better speed for every workload. Nginx Open Source is distinct from NGINX Plus: the official active HTTP health check is commercial; OSS has passive upstream failure handling.

## What Caddy does

Caddy is a web server and proxy with a readable Caddyfile, automatic HTTPS and a local admin API. Reverse proxying, load balancing and health checks are core features. Public certificates require correct public DNS, reachable validation ports, bind permissions and persistent writable certificate storage. Restricted networks, DNS challenges or internal PKI may need additional setup. Official packages do not include every third-party module; check the deployed build.

## Compare the editions you will run

The capability table is edition-aware; commercial features are not attributed to OSS.

| Capability | Caddy 2.11.7 | Nginx OSS 1.30.6 |
| --- | --- | --- |
| Reverse proxy | Native reverse_proxy | proxy_pass |
| Automatic ACME TLS | Built in, subject to reachability/DNS/storage | Separate ACME client and renewal/reload |
| Active HTTP health checks | Built in | NGINX Plus feature |
| Passive upstream checks | Available | Available |
| Proxy response cache | No general built-in core cache | proxy_cache available |
| Static files | file_server | Built in |
| Third-party modules | Custom build; verify module list | Build/package dependent |

## Install on Ubuntu

Distribution and upstream repositories may ship different versions. This uses the official Caddy stable repository and Ubuntu Nginx package. For upstream Nginx, configure the signed nginx.org repository per its official instructions.

```text
# Caddy stable repository
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl gnupg
curl -1sLf https://dl.cloudsmith.io/public/caddy/stable/gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update && sudo apt install caddy

# Nginx from Ubuntu repository
sudo apt update && sudo apt install nginx
caddy version
nginx -v
```

## Equivalent reverse proxy configurations

Both examples proxy example.com to localhost:8080. Caddy attempts automatic HTTPS. The Nginx example assumes an ACME client or PKI has placed certificates at those paths. Run these separately: they cannot bind the same IP and port at once.

```text
# Caddyfile
example.com {
    encode zstd gzip
    reverse_proxy 127.0.0.1:8080
}

# Nginx server block, inside http {}
server {
    listen 443 ssl;
    server_name example.com;
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    location / {
        proxy_pass http://127.0.0.1:8080;
        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;
    }
}
```

![Equivalent reverse proxy configurations](/assets/img/articles/content/caddy-vs-nginx-web-server-reverse-proxy/caddy-vs-nginx-configuration-comparison.png)

## Certificate lifecycle

Caddy manages the usual ACME lifecycle, but DNS, firewall, storage, CA limits and log monitoring remain operational duties. A local localhost certificate is not a public certificate. With Nginx, an ACME client typically obtains certificates and Nginx must reload after renewal. Verify CA and hostname for HTTPS backends; disabling verification removes server identity checks.

![Certificate lifecycle](/assets/img/articles/content/caddy-vs-nginx-web-server-reverse-proxy/caddy-vs-nginx-https-certificates.png)

## Load balancing and health checks

Caddy reverse_proxy supports active health checks. Nginx OSS passively observes real request failures; the active HTTP health_check directive belongs to NGINX Plus. A /healthz endpoint should report readiness without exposing sensitive information. Retrying a payment without idempotency can duplicate an operation.

```text
# Caddy active checks
example.com {
    reverse_proxy 10.0.0.11:8080 10.0.0.12:8080 10.0.0.13:8080 {
        lb_policy round_robin
        health_uri /healthz
        health_interval 10s
        health_timeout 2s
        health_fails 3
        health_passes 2
    }
}

# Nginx OSS passive failure handling
upstream app_pool {
    server 10.0.0.11:8080 max_fails=3 fail_timeout=10s;
    server 10.0.0.12:8080 max_fails=3 fail_timeout=10s;
    server 10.0.0.13:8080 max_fails=3 fail_timeout=10s;
}
server { listen 8080; location / { proxy_pass http://app_pool; } }
```

![Load balancing and health checks](/assets/img/articles/content/caddy-vs-nginx-web-server-reverse-proxy/caddy-vs-nginx-load-balancing.png)

## Security and production operations

Restrict backend ports to the proxy, protect private keys and never expose Caddy’s admin API publicly. If a CDN is in front, trust client IP headers only from known proxies. Logs must not contain tokens, sensitive cookies or private bodies. Select backend TLS according to network and data boundaries; untrusted paths require encryption and identity verification.

## Measure your workload

There is no universal speed ratio. TLS, payloads, connections, compression, cache, logging, network and backend behavior all affect results. Under equivalent settings, measure throughput, p95/p99 latency, errors, CPU and memory, including long requests and backend failure/recovery.

## Which one fits your environment?

For a small new service prioritizing simple configuration and automated HTTPS, Caddy is a sensible starting point. For a mature Nginx fleet, proxy-cache/static-serving requirements or established operational practices, keeping Nginx is reasonable. If you need active checks in Nginx, evaluate Plus or another layer. Do not migrate solely for shorter config.

![Which one fits your environment?](/assets/img/articles/content/caddy-vs-nginx-web-server-reverse-proxy/caddy-vs-nginx-which-one-to-choose.png)

## Plan a controlled migration

Inventory hosts, paths, headers, body limits, timeouts, WebSockets, cache, rate limits, trusted IPs and certificate renewal. Validate on staging or a separate port; test auth, uploads, backend failure, client IP and renewal. Keep the previous config and rollback plan, and move listeners deliberately.

## Frequently asked questions

Does Caddy always get a public certificate? No; DNS, port reachability and persistent storage must permit it. Does Nginx OSS include active HTTP checks? The official module is in Plus. Which is faster? Measure equivalent workloads. Can they coexist? On separate ports/layers, but not the same IP:port.

## Related articles

[HAProxy vs Nginx](/articles/haproxy-vs-nginx-load-balancer-reverse-proxy)
[Nginx reverse proxy for multiple domains](/articles/nginx-reverse-proxy-multiple-domains-single-ip-443)

## Official references

Versions checked 24 October 2026: Caddy 2.11.7 and Nginx Open Source stable 1.30.6. Distribution packages can differ; verify installed versions.

[Caddy release](https://github.com/caddyserver/caddy/releases/tag/v2.11.7)
[Caddy install](https://caddyserver.com/docs/install)
[Caddy automatic HTTPS](https://caddyserver.com/docs/automatic-https)
[Caddyfile](https://caddyserver.com/docs/caddyfile)
[Caddy reverse proxy](https://caddyserver.com/docs/caddyfile/directives/reverse_proxy)
[Caddy API](https://caddyserver.com/docs/api)
[Nginx news](https://nginx.org/en/news.html)
[Nginx docs](https://nginx.org/en/docs/)
[Nginx proxy module](https://nginx.org/en/docs/http/ngx_http_proxy_module.html)
[Nginx upstream module](https://nginx.org/en/docs/http/ngx_http_upstream_module.html)
[NGINX Plus health checks](https://docs.nginx.com/nginx/admin-guide/load-balancer/http-health-check/)
[Nginx packages](https://nginx.org/en/linux_packages.html)
[ACME RFC 8555](https://www.rfc-editor.org/rfc/rfc8555)

- [Caddyfile](/downloads/caddy-vs-nginx-web-server-reverse-proxy/Caddyfile)
- [nginx-reverse-proxy.conf](/downloads/caddy-vs-nginx-web-server-reverse-proxy/nginx-reverse-proxy.conf)
- [nginx-load-balancer.conf](/downloads/caddy-vs-nginx-web-server-reverse-proxy/nginx-load-balancer.conf)
- [caddy-load-balancer.Caddyfile](/downloads/caddy-vs-nginx-web-server-reverse-proxy/caddy-load-balancer.Caddyfile)
- [docker-compose-caddy.yml](/downloads/caddy-vs-nginx-web-server-reverse-proxy/docker-compose-caddy.yml)
- [docker-compose-nginx.yml](/downloads/caddy-vs-nginx-web-server-reverse-proxy/docker-compose-nginx.yml)
- [caddy-nginx-comparison-checklist.md](/downloads/caddy-vs-nginx-web-server-reverse-proxy/caddy-nginx-comparison-checklist.md)
- [migration-nginx-to-caddy.md](/downloads/caddy-vs-nginx-web-server-reverse-proxy/migration-nginx-to-caddy.md)
- [nginx-compose.conf](/downloads/caddy-vs-nginx-web-server-reverse-proxy/nginx-compose.conf)
