Let's Automate Let's Encrypt

Create a script for renewal (I placed it in/root/update_keys.sh) with these contents:


#!/bin/bash

mkdir -p /tmp/letsencrypt/www

ADMIN_EMAIL=admin@example.com
HOSTNAME=$(hostname)

OUTPUT="$((docker run --rm -i --name letsencrypt \
    -v /etc/letsencrypt:/etc/letsencrypt \
    -v /tmp/letsencrypt/www:/var/www \
    quay.io/letsencrypt/letsencrypt:latest renew) 2>&1)"

if [[ $? -eq 0 ]]; then
    echo "${OUTPUT}" | grep -q "No renewals were attempted"
    if [[ $? -eq 0 ]]; then
        # all certificates have more than 30 days left -
        # nothing to do
        exit 0
    fi
    echo "${OUTPUT}" | tr -Cd '[:print:]\n' \
        | mail -s "${HOSTNAME}: Let's Encrypt keys renewal -
         ↪success" "${ADMIN_EMAIL}"
    else
        echo "${OUTPUT}" | tr -Cd '[:print:]\n' \
            | mail -s "${HOSTNAME}: Let's Encrypt keys renewal -
             ↪failed, exit code $?!" "${ADMIN_EMAIL}"
        exit 1
    fi

    # test config, reload if successful
    /usr/sbin/nginx -t &> /dev/null
    if [[ $? -ne 0 ]]; then
        echo 'please fix configfile problem' \
            | mail -s "${HOSTNAME}: nginx unable to reload"
             ↪"${ADMIN_EMAIL}"
        logger "nginx has errors - not reloaded"
    else
        service nginx reload
        logger "nginx reloaded"
    fi

    rm -rf /tmp/letsencrypt

Remember to assign proper access rights:


sudo chmod u+x /root/update_keys.sh

And create a crontab entry:


sudo crontab -e

with a line like this:


17 2 * * * /root/update_keys.sh

That will trigger execution of this update script at 2:17 every day. The update script will check whether your certificates have more than 30 days left, and if they don't, it will attempt to renew all expiring certificates. Are you wondering why I used 2:17 am? Well, there is a simple explanation for that: almost everybody else did not. Most people, when creating cron jobs, use some simple value like 1:00 am, 2:00 am, 3:30 am, 4:15 pm and so on, and that is a really, really bad choice if your cron job is supposed to talk to an external service, because that means the service will experience maximum loads every once in a while. It is bad for the service, and it is not good for you; the chance of getting a timeout is significantly higher if you send a request during these peak loads.

So, for this job, please, please do not use an even value, and do not use my value; use some random value instead, and everything will be fine.

As you can see, Let's Encrypt managed to make the full automation of certificate maintenance possible. If you are using it right, it just works—and it's free.

______________________

Andrei Lukovenko is a longtime Linux user, command-line fanboy, automation aficionado.