Most people use Caddy as their load balancer to great benefit. But sometimes you are running on a cloud service that does load balancing for you, and you find yourself running Caddy behind a load balancer. You might run 2 or 12 or 212 instances! No problem. Caddy is equipped to handle this.
When running Caddy behind a load balancer, there are some things to consider to ensure that certificate management is uninterrupted:
Configure the same storage.
When running multiple instances, you will want to make sure that each Caddy instance “acts as one” by configuring them with the same storage.
By default, Caddy uses the local file system. If running in multiple containers or VMs, this will result in different storage locations because each instance has a different disk.
There are a couple ways to get them to use the same storage. Choose the one that is best for you:
- Mount a shared network folder, and then configure Caddy’s
file_system
storage to use that root path. - Configure a different storage module, which is any of the
caddy.storage.*
modules on our site. (Note that many of these are developed by third parties.)
For example, if using a database for storage, make sure that all Caddy instances are configured to use the same database. If the file system, make sure they are configured to use the same root path (and the same disk!).
If the Caddy instances are using different storage, then they will likely not succeed when solving ACME challenges. If they use the same storage, they can solve the challenges collectively as a cluster. This is explained in our documentation. There is nothing else you have to do for them to collectively solve challenges: just configure the same storage.
It is easy to configure storage
- using JSON: JSON Config Structure - Caddy Documentation
- using Caddyfile: Global options (Caddyfile) — Caddy Documentation
Forward port 80 (HTTP).
This allows Caddy to obtain new certificates using the ACME HTTP challenge.
You must forward port 80, but behind the load balancer you can set the destination port to anything you want. Just make sure Caddy knows that the “HTTP port” is different. You can do this in the JSON’s http
app config as well as in the Caddyfile (with the http_port
global option).
Forward port 443 (TLS / HTTPS) – do not terminate TLS at the load balancer.
This allows Caddy to obtain new certificates using the ACME TLS-ALPN challenge. If TLS is terminated by the load balancer, then Caddy cannot use this challenge successfully, unless the TLS terminator is smart enough to proxy ACME challenges (unlikely, as I don’t know of any that do this).
If TLS termination cannot be avoided, the TLS-ALPN challenge will always fail and you should disable it in your config. However, Caddy’s underlying ACME library, acmez, is smart enough to learn which challenge is the most successful over time and it will quickly learn to prefer another challenge type.
If using Caddy as your load balancer, you can use the layer4 app to proxy TCP/UDP without terminating TLS.
You must forward port 443, but behind the load balancer you can set the destination port to anything you want. Just make sure Caddy knows that the “HTTPS port” is different. You can do this in the JSON’s http
app config as well as in the Caddyfile (with the https_port
global option).
Point your domains at your load balancer’s static IP
Set your domain’s A/AAAA records to your load balancer’s IP address. Or if your cloud service gives you a floating static IP, use that. The idea is that you want your domains to resolve to your load balancer so that it can decide which Caddy instances handle which requests.