I’ve recently started using subdomains for services I only access locally. I want Caddy to serve them through HTTPS so I don’t get annoying warnings about the connection being insecure, while blocking access from WAN just to be extra safe, which I cover here.

The thing is, port 80 is not forwarded on my router, which is required for the ACME HTTP-01 challenge. I also don’t want a DNS record for my private subdomains to appear publicly (I use the hosts file in my router to provide DNS resolution locally). EDIT: Certificate Transparency is a thing… Thank you Laurent!

A convenient solution is to use the ACME DNS challenge to get a wildcard certificate. Here’s how to do it with OVH.

Install Caddy with the OVH plugin

Install a custom build of Caddy with the OVH plugin. I went with the update-alternatives from source route after installing vanilla Caddy through my package manager, but there are several other ways to do it, more info on that page.

OVH API credentials

You now have to create OVH API keys from the dedicated admin page with the correct API permissions. According to the libdns GitHub repo, they are as follows for a single domain:

GET /domain/zone/ampho.fr/record
POST /domain/zone/ampho.fr/record

GET /domain/zone/ampho.fr/record/*
PUT /domain/zone/ampho.fr/record/*
DELETE /domain/zone/ampho.fr/record/*

GET /domain/zone/ampho.fr/soa
POST /domain/zone/ampho.fr/refresh

Once you have your API credentials, store them in a location where Caddy will be able to read them. I use a .env file in /etc/caddy/ and a service override as described in the Caddy documentation.

Here is what my .env file looks like. Change the endpoint according to your region.

OVH_ENDPOINT=ovh-eu
OVH_APPLICATION_KEY=xxxxxxxxxxxxxxxxx
OVH_APPLICATION_SECRET=xxxxxxxxxxxxxxxxx
OVH_CONSUMER_KEY=xxxxxxxxxxxxxxxxx

Don’t forget about the service override!

Caddyfile

You can now modify your Caddyfile to use the DNS challenge and serve all your subdomains with a wildcard certificate:

*.ampho.fr {
        tls {
                dns ovh {
                        endpoint {$OVH_ENDPOINT} # Variables from the .env file
                        application_key {$OVH_APPLICATION_KEY}
                        application_secret {$OVH_APPLICATION_SECRET}
                        consumer_key {$OVH_CONSUMER_KEY}
                }
        }

        #My service
        @subdomain host subdomain.ampho.fr
        handle @subdomain {
                reverse_proxy localhost:1234
        }
	...

Make sure to restart/reload Caddy to apply the changes. Check the service health with journalctl -xeu caddy.service. If it’s healthy, you’re done!