In a previous blog I wrote about how to get started with Let's Encrypt certificates and auto-renewing them. Free certificates are awesome and auto-renewal is even better, but I wasn't quite satisfied with the renewal process so I decided to improve it.


Getting started

If you aren't already using Let's Encrypt (LE) and want the joys of certificate auto-renewal you can refer to my previous blog, Getting started with Let's Encrypt!, to get up and running. I'm not using the official Let's Encrypt client but the problem I wanted to solve is present whether you use acme_tiny like I do or the official LE client.

Let's Encrypt Logo


The problem

LE issues certificates with a 90 day validity which offers a few benefits and isn't something to be concerned about when you can automatically renew them. Both my guide and the official LE documentation advise an automatic renewal every 30 days. This is easy enough to setup with a cronjob called on a specific date every month like I do on the 1st and means that certificates will be renewed well within their validity period. The only thing I didn't like about this approach was that there are only 2 opportunities to renew the certificate before it expires and this didn't seem very robust. The script is called on the 1st of the month and could fail for any number of reasons. Maybe my server was having some down time, I couldn't establish a connection to LE or perhaps LE are having problems and the certificate issuance fails. This means I only have 1 more shot at renewing my certificate, on the 1st of the following month, before it will expire prior to the next renewal.


Let's Encrypt Smart Renew

I've created a little script to solve this problem that's really basic but it adds a check to see how long the certificate has left before it expires. You can set the remaining validity period you'd like the certificate to be renewed below, say 7 days until expiration, and the script won't try to renew your certificate unless that criteria is met. This means you can call the script much more frequently, like every hour, and it won't matter because the certificate won't be renewed unless there is less than 7 days worth of validity left. This means you won't hit any of the rate limits on certificate issuance but if a renewal does fail for any reason it will only be an hour until the next attempt instead of a month! If you do call the script every hour and set it to renew once the certificate has less than 7 days of validity left, you have 168 chances to renew before the certificate expires rather than 2 compared to the default setup. Of course, you can set the script to renew the certificate once it has less than 60 days of validity left and continue to renew monthly but with a much greater reliability.


You can find the script here on GitHub, pull requests welcome!


Update

Thanks to James Jones for pointing out on Twitter that the official LE client does have an option to hold back from renewing the certificate unless it's needed.


The documentation he pointed me towards also advises that renewal scripts should be called daily, but my current understanding is that would result in you breaching the rate limits set out here.

We recommend running renewal scripts at least daily, at a random hour and minute. This gives the script many days to retry renewal in case of transient network failures or server outages.


This would definitely be a problem if, like me, you issue several certificates for different subdomains of the same parent domain at different times. My demo site https://hpkp.scotthelme.co.uk needs to have it's own certificate to work properly but the issuance of a certificate to that subdomain counts towards my limit of 5 certificates in a 7 day rolling period for the scotthelme.co.uk domain.