Caddy instead of Nginx with ACME API for LE SSL

We are currently using StoneMax GitHub - stonemax/acme2: Another PHP client for acme protocal (version 2) implementation, used for generating letsencrypt's free ssl certificates. ACME V2 package to generate Let’s Encrypt SSL certificates for all our customers. We incorparate it into our own Laravel PHP App with a separate package.

This works reasonably well. But we are however considering moving the whole process to its own server. Therefore we have been looking into options for this. Many Docker like options out there, but those do not interest us as we are perfectly fine using our Nginx web server together with the database server and possibly later on a Redis server. So we prefer a non Docker solution.

  • Am I correct to assume that Caddy could be used as a reverse proxy to generate the LE SSL certificates for us and automatically like let’s say Traefik?
  • If a new customer books a site and domain via us via our DNS API does Caddy offer options to add that new domain to a “list” for a new Let’s Encrypt SSL certificate to be generated?
  • Is there any documentation on migration from Nginx to Caddy for LE SSL Certificate generation?

Welcome around, Jasper! Good to see you again here of all the places :smiley:

  • Yes, Caddy will fetch the LE certificates automatically, manage renewals, and do the OCSP stapling for you all on its own.

  • If you’re using Caddy v1, once you update the Caddyfile with the new site and send USR1, it will fetch the certificates for the sites. If you hop onto Caddy v2, which is currently in beta, you can use its REST API to load/amend the config with the new sites.

  • Currently there isn’t such documentation, but it isn’t complex to configure Caddy to handle the certificate generation. It will default to HTTPS, unless configured to something contrary (disable HTTPS, no qualified domain name, listening on port 80 only, or explicitly providing the certs instead of relying on Caddy to manage them). Are you trying to retain old certificates from before or just concerned about the complexity of the configuration of certificate management automation?


Hi Mohammed! Yeah, funny to “meetup” this way again after all this time. Good to see you are keeping up the good work!

The REST API looks really interesting for updating the domains. We would be dealing with many subdomains such automation is really useful.

ohDear App and TLS directive

Saw that Freek uses a similar setup for the Laravel based app Ohdear though I do think he used the old version:

We catch every https:// URL that makes it to this server. The tls directive is then used to instruct Caddy to issue Let’s Encrypt certificates automatically, in case it doesn’t yet have a certificate.

Because we don’t want to try to issue a certificate for every domain that connects to us (that might trigger our Let’s Encrypt rate limits) , we use Caddy’s ask feature to callback to Oh Dear! and ask if that domain is allowed to be issued a certificate.

Caddy does this by firing a GET request to our URL. If that returns an HTTP/200 , it’s allowed to continue. The URLs look like this.

On Demand TLS

So he updates a status page or file with latest domains and lets Caddy check this file it seems. And does so using

tls {

and talks about that on demand TLS. This also looks really useful.

Some more Questions

  • Can Caddy take care of all this Let’s Encrypt SSL generation and serve as a load balancer / reverse proxy at the same time?

  • Also saw that there DNS plugins to do DNS challenges as well. Too bad TransIP or InternetX are not part of this as of yet. Would have been useful to us though we can do http challenges as well of course. Any templates for this?

1 Like

I think yes, they’re probably on v1.

Yes, it can certainly do that. The directive for reverse proxy (proxy in v1, and reverse_proxy in v2) can take multiple upstreams. The supported load balancing policies are:

I see TransIP available in the repo but not listed on the website. The workaround is to build Caddy from source yourself after plugging in the TransIP DNS challenge package. The config then is something like:

tls {
   dns transip

Then pass the secret values in the environment variables TRANSIP_ACCOUNTNAME, TRANSIP_PRIVATEKEYPATH. As for InternetX, it needs to be supported upstream in the go-acme/lego package first.

That was all for Caddy v1. For v2, DNS challenge is supported, but no DNS-challenge-provider plugins have been implemented yet. I’m not familiar with that part of the code yet nor am I familiar with the upstream go-acme/lego package to judge how complex is it to implement those 2 DNS providers into Caddy 2.


This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.