Caddy reverse proxy: when it is the right choice for scaling infrastructure
Caddy automates load balancing, health checking, and TLS in one process. Learn when it fits your scaling needs and when to pair it with a dedicated load balancer.
Caddy automates what takes separate tools in traditional setups. It handles automatic HTTPS provisioning and renewal, dynamic configuration without restart, and built-in load balancing across upstreams. For infrastructures serving hundreds of services through a single reverse proxy layer, Caddy cuts operational complexity significantly. For clusters that need geographic failover or traffic shaping based on user location, a dedicated load balancer upstream of Caddy is the right architectural choice.
Evaluating Caddy means understanding not what it is, but what role it plays. In 2026, many teams run Caddy successfully at scale. Therefore, understanding its boundaries and strengths helps you decide whether it is the right reverse proxy for your infrastructure. This guide walks through the mechanisms, the scenarios where Caddy excels, and the patterns where you need a different tool instead.
What Caddy reverse proxy does differently from traditional choices#
Caddy was built with one principle: every web server should have automatic HTTPS, configuration as code, and dynamic reloading without restart. This design philosophy sets Caddy apart from choices like nginx or HAProxy, which treat those concerns as separate problems to solve outside the server itself.
Caddy's documentation, updated 17 September 2026, describes the reverse proxy directive as "proxying requests to one or more backends with configurable transport, load balancing, health checking." That sentence names three concerns. Transport, distribution, and health are traditionally split across modules and external tools. In Caddy, they are unified operations in one configuration block.
Caddy was designed around automation. It assumes the infrastructure running it can reload configuration on changes, that TLS certificates are provisioned automatically, and that upstreams come and go as services scale. Unlike nginx, which assumes a static configuration, Caddy assumes a dynamic one. Because of that assumption, load balancing and health checking work differently inside the proxy than they do in traditional tools.
How Caddy reverse proxy implements load balancing and health checks#
Caddy includes six built-in load balancing policies. Random, least request, least connection, URI hash, header-based, and cookie-based selection all work alongside automatic health checking that removes upstreams when they stop responding. Caddy's documentation, updated 17 September 2026, describes each policy and shows the range of what the reverse proxy directive supports:
| Policy | Behavior |
|---|---|
| random | BehaviorRandomly selects an upstream |
| least_request | BehaviorSelects upstream with fewest requests |
| least_conn | BehaviorSelects upstream with fewest connections |
| uri_hash | BehaviorHashes URI to select consistent upstream |
| header | BehaviorUses header value to select upstream |
| cookie | BehaviorUses cookie value for session persistence |
Least request and least connection policies work by tracking in-flight requests or open connections. When a new request arrives, Caddy picks the upstream with the fewest. Hash policies (URI hash and header-based) guarantee that the same logical client always routes to the same upstream, without leaving the proxy layer. Cookie-based selection uses a cookie value to make the choice, letting an application itself decide the routing key.
Automatic health checking works with all six policies. When Caddy is configured with upstreams, it sends health check probes on an interval you set. An upstream that fails a set number of consecutive probes is marked unhealthy and taken out of the pool; the health_fails setting on the reverse_proxy directive controls that number, and its documented default is one. When it recovers, Caddy adds it back. All of this happens without restart, without reloading the configuration, and without deploying new code.
Many topologies benefit from these policies and health checking. A fleet of identical backend services, a cluster of database replicas, or a pool of application servers behind one reverse proxy all work with only Caddy's built-in mechanisms. A platform in 2026 serving 500 microservices across 3 data centers needs to distribute traffic and handle service failures. Caddy can do both with only the reverse proxy directive.
Health checking in Caddy runs in parallel, so the interval controls the frequency of probes, not the total checking cost. A health check every 10 seconds on 100 upstreams means 10 probes per second, always. That pace is often fast enough. When it is not, the answer is not a different reverse proxy but a dedicated load balancer that specializes in handling that volume. Caddy stays focused on its role as the proxy, not the orchestrator of health checks at massive scale.
The worked example shows the scaling story. A platform with 500 microservices and a 10-second health check interval generates 50 health check requests per second. That is manageable for one Caddy instance. When your health check frequency or upstream count increases, you have two choices: increase the health check interval (slower failure detection) or add a dedicated load balancer upstream of Caddy that handles the health checking itself.
Probes per second
500 / 10 s = 50.0Probes per hour
180,000Probes are negligible next to the traffic#
2.4% of trafficAt 500 upstreams and a 10 second interval the proxy sends 50.0 probes a second, 180,000 an hour, against 2,000 requests a second of traffic. Lengthening the interval cuts the probes and slows failure detection by the same factor; the trade is yours to make, and the numbers above are the only inputs to it.
| upstream services | 500 (the post’s example platform) |
|---|---|
| health check interval | 10 s |
| probes per second | 500 / 10 = 50 |
| probes per hour | 50 x 3,600 = 180,000 |
| traffic | 2,000 requests a second |
| probe share | 50 / (50 + 2,000) = 2.4% |
What Caddy reverse proxy automates at scale#
Caddy automates two operations that cost the most in traditional setups. TLS certificate provisioning and dynamic configuration are both built into the proxy.
TLS certificates used to require manual renewal before expiry. Certificate authorities like Let's Encrypt automated provisioning, but adoption took time. Caddy, since its earliest versions, assumed automatic HTTPS and integrated Let's Encrypt provisioning. Not for one certificate, but for any number of domains. Caddy's homepage, read on 17 September 2026, says the server is designed to manage certificates reliably at the scale of hundreds of thousands of sites, a figure Caddy states about itself, not an independent measurement.
That scale matters in production. In a setup where the proxy does not own certificates, you plug in a separate tool like certbot, run renewals on a schedule, and reload the configuration. Caddy owns the whole lifecycle: provisioning, renewal, and rotation. An infrastructure serving 500 services through Caddy pays once for that automation. An infrastructure running 500 proxy instances that each renew their own certificates pays the cost 500 times over, with each renewal touching 500 processes.
Configuration changes without restart are the second automation. In nginx, a configuration change requires validation, signaling the process, and waiting for in-flight requests to finish. New requests wait until the reload completes. The reload takes seconds or minutes depending on your configuration size. Caddy assumes configuration can change constantly. Upstreams appear and disappear as services scale. It applies changes to new requests immediately without waiting for in-flight requests to finish. That assumption is built into its architecture from the start, in 2026 and since its earliest versions.
A practical example: your Kubernetes cluster has 100 services. One fails. The orchestrator removes it from the service registry. Caddy reads the updated registry and removes that backend from its pool within seconds. A request in-flight to the failed backend finishes naturally; new requests immediately route to a healthy backend. No configuration reload, no process signal, no waiting. That speed of response is what makes Caddy suitable for dynamic infrastructure.
By contrast, in nginx you would have to validate syntax, signal the process with nginx -s reload, wait for existing requests to finish, and then new requests can route to the updated pool. In a cluster with dozens or hundreds of services changing constantly, that workflow becomes a significant operational burden. Caddy removes that burden entirely by making dynamic configuration a core feature rather than an afterthought.
The combination of automatic TLS and configuration-as-code sets Caddy apart. Where nginx and HAProxy are tools you configure once and then maintain, Caddy is a tool you integrate with a configuration engine: your orchestrator, your service mesh, your application platform. It does the proxying; something else does the automation.
When to choose Caddy over nginx or HAProxy#
Caddy's strengths emerge in certain scenarios. You are running a single reverse proxy layer for many services (hundreds of backends) and want to update routing and health checks without restarting. Caddy handles that. You need TLS automation for many domains without managing separate certificate renewal tooling. Caddy removes that burden. Your services come and go as part of deployment (containerized workloads scaling up and down). Caddy's dynamic configuration fits that pattern.
nginx is the choice when you depend on its module ecosystem or on configuration your team already runs in production. HAProxy is the choice when you need stateful load balancing: session persistence across multiple proxy instances, geographic distribution, and traffic shaping expressed in its own configuration language. Throughput and memory differ by workload and version; measure them on your own traffic before letting either decide.
Caddy's case is not raw speed or feature count. It is simpler to operate when your infrastructure is dynamic. Configuration is cleaner. Operational surface is smaller. Assumptions about automation are baked in, not bolted on. For teams running Kubernetes or Nomad, that simplicity pays for itself every day.
Deployment patterns that work well with Caddy#
Caddy excels in deployment scenarios where configuration is generated and services come and go. In Kubernetes clusters, Caddy becomes an ingress controller that uses the cluster's own API to discover backends. When a pod starts, Kubernetes updates Caddy's configuration automatically. When a pod dies, Caddy removes it from the pool without manual intervention. That pattern eliminates a whole class of operational work.
Container orchestration platforms like Nomad follow a similar pattern. Services register themselves when they start. Caddy watches the service registry and updates upstreams as services scale up or down. The entire lifecycle of service discovery and upstream management happens without touching Caddy's configuration manually.
Static deployments with service mesh sidecars also benefit from Caddy. When every application has a sidecar proxy, Caddy can route to sidecars by name. Service mesh controllers update Caddy's routing rules as services are deployed or removed. The pattern works because Caddy's configuration reloads are fast and do not interrupt in-flight requests.
Long-lived infrastructure with static upstreams (a small number of backend servers that do not change) is where Caddy's automation becomes overhead. If your upstreams never change, nginx or HAProxy is the better fit. They have less complexity and faster request handling when they do not need to check for configuration changes.
When not to choose Caddy reverse proxy#
There are three clear cases where a different tool is the better choice.
First, when you need geographic load balancing across data centers. Requests to your service land in New York and Tokyo. You want Tokyo traffic routed to a Tokyo data center while New York traffic stays local. That is not Caddy's job. A global load balancer (Cloudflare, AWS Global Accelerator, or a dedicated geographic load balancing service) handles that role. Caddy sits inside a data center and distributes traffic to upstreams in that location only.
Second, when you need session affinity across multiple Caddy instances. You run three Caddy reverse proxies in a cluster, and a client must always hit the same one so that their session state is consistent. Caddy cannot enforce that by itself. A dedicated load balancer in front of your Caddy cluster would sticky-route based on client IP or a cookie. Caddy can do that sticky routing internally, but not across a Caddy cluster.
Third, when you need compatibility with infrastructure that expects HAProxy-specific directives or behavior. Some platforms and tools are tightly coupled to HAProxy's configuration language. If your deployment tooling depends on HAProxy-specific syntax, switching to Caddy requires changing more than the reverse proxy layer.
In all three cases, the answer is not "use something else entirely." The answer is "add a load balancer upstream of Caddy." A global load balancer routes traffic to Caddy clusters by geography. A local load balancer routes traffic to a Caddy cluster by affinity. Both patterns work well and are deployed in production today.
Where Caddy reverse proxy fits in your infrastructure#
Caddy reverse proxy handles load balancing, health checking, and TLS automation in one process. That combination is right for infrastructures where services are numerous but managed by automation. Configuration can be generated and applied dynamically. It reaches its limits when you need distributed state, geographic intelligence, or stateful routing.
For an infrastructure using Kubernetes, Nomad, or another orchestrator, Caddy fits as the ingress layer. It is the reverse proxy that routes traffic from the outside world into your cluster. Your orchestrator updates Caddy's upstreams as services scale. Caddy distributes traffic and checks health. No separate tools needed.
For an infrastructure built on static configuration and long-lived servers, nginx or HAProxy is the better fit. They assume configuration is set and stable, and they excel in that context.
Start with the post on what belongs at the edge for architectural patterns of reverse proxies and edge placement. Caddy fills different patterns than traditional setups. If you are building HTTP servers, the fundamentals in the Node.js HTTP server guide apply to how Caddy handles connections. To understand how frontend infrastructure works when served through reverse proxies, the React rendering on Cloudflare post shows the patterns Caddy connects to.
When you are building and maintaining reverse proxy infrastructure as part of your platform, the DevOps engineering and backend engineering services at Atyantik help you design and implement patterns that fit your scale and your team's operational model.