Yesterday I finally ticked something off my todo list that'd been on there for a while - I added proper HTTPS support to this site, powered by Let's Encrypt.
For those interested in how things work:
Exactly how I got it all working can be seen in my website repo, where this entire site and it's deployment scripts are kept, but here's the gist of it:
I decided to use
dehydrated instead of the official Let's Encrypt client to
generate the certificates.
dehydrated is ~1000 lines of
bash and only requires things like
curl, and a few other programs that any UNIX system should already have. It takes a
config file and a list of domains. Once those are in place running it from
cron is easy.
The ACME protocol that Let's Encrypt uses to verify domain ownership requires the web server to
respond to certain requests. This check makes sure that only someone with control over the domain
can generate a cert for it. To allow those requests to return the files generated by
a location rule in the Nginx config was added.
Initially there were problems with the first time generating certs. Since the certs didn't exist yet, Nginx was failing to start (and therefore causing the domain validation to fail). The solution was to make two sets of configs. An HTTP set, and an HTTPS set. During the renewal process, the HTTPS configs are tried, and if running Nginx fails, it falls back to the HTTP set. Switching between HTTP and HTTPS configs is done by modifying a symlink.
When all set up, this makes both generating a cert for the first time and renewing a cert as easy as
deploying the site. For continual, automated renewals, a monthly
cron job was added. With the
expiry of certs being 90 days, this should be frequent enough that the certs should never expire.