As of recently, Let's Encrypt will let you have wildcard certificates, but you have to use the ACMEv2 API server and the DNS challenge. The DNS challenge requires adding a record to DNS with a validation token to allow LE to validate you have control over the domain.
There are a few ways to handle this. The simplest is to manually manipulate the DNS records to add the validation token every time the certificate comes up for renewal, which is 90 days. This is a bit cumbersome and prone to human error. It's therefore possible to automate this, and the
certbot ACME client comes with a bunch of plugins which allow you to hook into various DNS providers' management API's. However, if you're running your own nameserver (like me) and running nameserver software which doesn't support RFC2316 (which looks like everything apart from ISC Bind 9 from what I can tell), then this becomes slightly more involved.
certbot has an option for performing domain validation manually instead of using a plugin (such as the webroot plugin, which is the most useful one to me), and allows you to specify external hook programs to call to set up the authentication token and to clean up post-verification out of band. All you need to do is write some scripting to automate the DNS changes.
I use djbdns on my authoritative nameservers -- I have it set up like this:
Each nameserver has a
dns user which is dedicated to DNS management. The
dns user's home directory is
tinydns is configured to
/var/local/dns/tinydns, and look for its
data.cdb file there.
On the primary nameserver, there is a directory at
~dns/zone which has a file for each of my servers containing the DNS records pertaining to that server, a file with mail-related records for each of my domains and a file with the authority records for each of my domains.
Also on the primary, there's a script in
~dns/bin which concatenates all the files in
~dns/zone into the file
~dns/tinydns/data, changes directory to
~dns/tinydns and then runs
tinydns-data to compile the
data.cdb file. This script also pipes the contents of the concatenated data file over
ssh to the backup nameserver, which is then similarly compiled locally there.
Also of note is that my webserver and primary nameserver run on the same machine, which simplifies the automation of changing DNS records a lot. However, it wouldn't be overly difficult to adapt the scripting to call a script over
ssh to perform the updates instead.
So, I have the following script at
/root/scripts/letsencrypt-authenticator.sh, which adds the challenge record to the DNS:
#!/bin/bash -e basedir="/var/local/dns/zone" # directory with DNS data files dnsuser="dns" updatescript="/var/local/dns/bin/bootandpush.sh" # this script compiles data.cdb locally and pushes # the data file to the backup nameservers authdomain="$CERTBOT_DOMAIN" # domain for which validation is being performed authstring="$CERTBOT_VALIDATION" # string to be entered into DNS txtdomain="_acme-challenge.$authdomain" # label to insert record under, e.g. _acme-challenge.in-addr.xyz tinydnstxt="'$txtdomain:$authstring:5" # tinydns TXT record -- see the documentation at cr.yp.to filename=$(mktemp -u "$basedir/ACME_VALIDATION.XXXXXX") echo $tinydnstxt | sudo -u "$dnsuser" tee "$filename" > /dev/null sudo -u "$dnsuser" "$updatescript" sleep 5 # wait for the changes to settle
Then, I have this script at
/root/scripts/letsencrypt-cleanup.sh, which removes the challenge records:
#!/bin/bash -e basedir="/var/local/dns/zone" dnsuser="dns" updatescript="/var/local/dns/bin/bootandpush.sh" sudo -u "$dnsuser" rm -f $basedir/ACME_VALIDATION.* sudo -u "$dnsuser" "$updatescript"
Certificates can then be requested by running
certbot in manual mode, specifying the above scripts as the authentication and cleanup hooks:
# certbot certonly --manual --preferred-challenges=dns --server https://acme-v02.api.letsencrypt.org/directory \ --manual-auth-hook /root/scripts/letsencrypt-authenticator.sh \ --manual-cleanup-hook /root/scripts/letsencrypt-cleanup.sh -d '*.in-addr.xyz' -d in-addr.xyz