Install & Configure Certbot

Docker & Let's Encrypt

I have been playing with a few things of late. Mostly related to moving my site off GitHub and using my own domain. As part of that I am just toying with Let’s Encrypt. I have been doing this during my trial period with Linode.
Today I will document how I set up Let’s Encrypt using DNS as the preferred Challenge.

Assumptions

You already have Docker installed and running. If not, go seek and ye shall find. For myself. I used the Linode documentation here.

Generating your First Certificate

There are two challenge mechanisms. http or dns. For myself. I prefer dns. Since I have control of my domains. Though I think many opt for the http approach.

Get your Certbot image

The image is pretty easy to get. A simple docker pull command.

docker pull certbot/certbot

I am only using the standard certbot. There are a number of others, if you are using other supported dns services.
In both cases your certificates will end up in /etc/letsencrypt/live/[domain]/

http

To use the default approach you can run:

docker run -it --rm --name certbot \
          -v "/etc/letsencrypt:/etc/letsencrypt" \
          -v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
          certbot/certbot certonly

Follow certbot’s instructions and you should be good to go.

dns

I had to do a little digging around for this one. I found this answer on ServerFault. The command is:

certbot -d [host/domain] --manual --preferred-challenges dns certonly

A simple bit of adjustment for the docker command.

docker run -it --rm --name certbot \
          -v "/etc/letsencrypt:/etc/letsencrypt" \
          -v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
          certbot/certbot -d [domain] --manual --preferred-challenges dns certonly

Again simply follow certbot’s instructions and add the required TXT record to the domain’s zone file. Give DNS a little time to update. Or check using trusty dig. Once it’s showing up you can complete the process.

Setup Automated Renewals

According to Certbot.eff.org - Automated Renewal.

Run the following line, which will add a cron job to /etc/crontab:

SLEEPTIME=$(awk 'BEGIN{srand(); print int(rand()*(3600+1))}'); echo "0 0,12 * * * root sleep $SLEEPTIME && certbot renew -q" | sudo tee -a /etc/crontab > /dev/null

This basically generates a cron job which is run as root at midnight and midday with some one time random SLEEPTIME value. Example:

0 0,12 * * * root sleep 2169 && certbot renew -q

I decided to use this output as the template for my own crontab entry.

Why the SLEEPTIME

The randomly generated SLEEPTIME is so that not every certbot tries to renew certificates at the same time. So a simple approach to load distribution.

Script Certificate Renewal

I made a short script to make this command fit nicely in a crontab entry.

#!/bin/sh
docker run -it --rm --name certbot -v "/etc/letsencrypt:/etc/letsencrypt" -v "/var/lib/letsencrypt:/var/lib/letsencrypt" certbot/certbot renew -q

I simply named this renew.sh
Set the right permissions on the file.

chmod +x renew.sh

I have configured my normal account user to be able to run docker commands. So this crontab will be stored under my account and thus will not be run as root. For better security you could/should have another user that does not actually have a shell account do these tasks.


To keep things neat. I placed renew.sh under the directory letsencrypt so the full path to the command is $HOME/letsencrypt/renew.sh.

You can test the script works by first removing the -q at the end of the file and run the command directly in the shell.

$HOME/letsencrypt/renew.sh

Which should give you something like:

Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/[domain].conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Certificate not yet due for renewal

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
The following certificates are not due for renewal yet:
  /etc/letsencrypt/live/[domain]/fullchain.pem expires on 2021-10-04 (skipped)
No renewals were attempted.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

If that all looks good. Add the -q back to the end of the script.

Edit your Personal Crontab

Issue this command at the shell prompt:

crontab -e

And using the example crontab entry I added the following lines.

SHELL=/bin/sh
PATH=/usr/local/bin:/bin:/usr/bin
0 0,12 * * * sleep 2169 && $HOME/letsencrypt/renew.sh > /dev/null

Issues

If you have issues. You may have to do the following.

  • Use sudo to set things up.
  • Install the cron job as root. Use the command provided by Certbot.eff.org

Closing

Happy Certificate generating.


See also