by Cesare Rocchi

How to auto-renew a Let's Encrypt certificate (and get notifications about it)

tags: ssl

Let’s Encrypt was still in beta when I started Podrover so I preferred to avoid any risk.

Now I am building Affiliator and Let’s Encrypt is not in beta anymore. Plus I like the “always be learning” spirit, so I gave it a shot.

I didn’t pick it because it’s free. I am not a fan of free. The beauty of Let’s Encrypt is that it comes as a binary program that you can run in the shell. This means:

  • no more need to access a website to download obscure files
  • no more need to find (or remember) where to put those files on your server

I am sold.

On my server I installed Let’s Encrypt

> sudo apt-get update
> sudo apt-get install letsencrypt

And then ran

sudo letsencrypt certonly -a webroot --webroot-path=/affiliator/public -d 

I was prompted to enter an email address. Let’s Encrypt is nice and will warn you via email a few weeks before the certificate expires. The command generated all the files into


Then I configured Nginx.

server { 
  listen                 443;
  ssl                    on;
  ssl_certificate        /etc/letsencrypt/live/;
  ssl_certificate_key    /etc/letsencrypt/live/;

I was ready to call it a day when a smart neurone bumped into another smart neurone, generating the question: what about certificate renewal?

Renewing a certificate

Commercial certificates usually last at least one year. The renewal involves again logging into a website, downloading obscure files and placing them in the right place. With Let’s Encrypt the renewal is easy peasy:

sudo letsencrypt renew

This will find expired certificates on the machine, and renew them if needed. But there’s a catch. At the moment a Let’s Encrypt certificate lasts exactly 90 days. Here’s the discussion about why. A few weeks before the expiration date Let’s Encrypt will send you a reminder via email. Every time you’ll need to:

  • ssh into the machine
  • renew the certificate
  • restart the web server

If you have just one machine it’s feasible. If you have ten or more, you’ll be doing the process above every 2-3 days. Not nice. The solution: automation!

Auto-renewing certificates

You could solve with a simple cron

0 2 * * 2 /usr/bin/letsencrypt renew >> /var/log/letsencrypt-renewal.log

This runs the script every two weeks and with a second cron you could restart the web server. But I like to stay up to date with what happens on my machines. I already have a bunch of scripts that build some reports and send them to a private Slack room. So I built another script that notifies me when the renewal of the SSL is attempted and if it is successful.

I could have used a bash script, but my machines have Ruby already installed so I took advantage of that.

#!/usr/bin/env ruby

require 'slack/poster'

result = `sudo letsencrypt renew`
poster =
poster.send_message "Result is #{result}"

When cron executed this script in Slack I saw

Result is 

meaning that the output of the command was not stored in the variable.

The catch is in to the sudo statement. If you run this script in a shell you’ll be prompted for a sudo password, and you don’t want that when a script is meant to be run by cron.

Luckily there’s a pretty nice solution. When you define the rules for sudoers (users with sudo permissions) you can also declare exceptions for certain scripts.

I use Ubuntu so I added this to /etc/sudoers

myuser ALL=NOPASSWD: /usr/bin/letsencrypt

This means

Don’t ask for a sudo password even if this script contains commands that would usually require a sudo password

Now the rest is easy. Schedule it once a week and you are set.

0 0 1,8,15,22 * * /bin/bash -l -c '/path/to/'

NOTE: the web server will keep on using the old certificate until you restart it. I didn’t automate this step yet, because I want to see how well this solution works.

It’s true, software developers should have sysadmin experience.

Let me know what’s your solution to this problem. I am curious.