Updating HTTPS certificates with cron

This article shows how to keep SSL-certs up to date with cron and certbot-auto. You should read it if you:

  • use certbot-auto (not certbot) for managing certs,
  • fed up with renewing certificates and
  • don't want to forget to renew certificates on production server and lose your job :)
  • want to learn how to use cron

Note: cerbot comes with automatic certs renewal by default. Learn more about differences between certbot and certbot-auto in the paragraph below.

About Certbot & Certbot-auto

Certbot / certbot-auto is a free, open-source software tool for managing SSL-certificates, to be precise - Let’s Encrypt certificates. certbot and certbot-auto are both used with the same purpose, but there are some differences:

Differences between certbot and certbot-auto


certbot certbot-auto
installed using package-manager installed manually
has automatic certs renewal by default automatic certs renewal should be set up manually
updated only when repo has a new version updates itself before each run (if necessary)

Certbot installation


  • visit main Certbot page
  • choose your web-server, e.g. nginx
  • choose your distro, e.g. Debian 8
  • follow the instructions

About Cron

Cron is a *nix tool for running user-defined scheduled tasks — crontabs, also known as cron-jobs / cron-configs. Name crontab stands for "cron time table". cron can be used for backuping, pinging hosts, updating SSL-certificates (our case), etc. We suggest to read this tutorial to learn cron basics.

Crontabs format

Crontabs contain lines with schedules in following format:

minute(s) hour(s) day(s)_of_month month(s) day(s)_of_week user command

Note: crontabs in /var/spool/cron/crontabs don't have "user" field:

minute(s) hour(s) day(s)_of_month month(s) day(s)_of_week command

Crontab example:

22 11,23 * * * root /usr/local/sbin/certbot-auto renew --post-hook "systemctl reload nginx" 2>&1 1>/var/log/certbot-auto.cron

This means every day at 11:22 AM and 11:22 PM root user invokes /usr/local/sbin/certbot-auto renew --post-hook "systemctl reload nginx" 2>&1 1>/var/log/certbot-auto.cron.

Useful command parts:

  • 2>&1 — redirecting stderr to stdout
  • 1>/var/log/certbot-auto.cron — redirecting stdout to /var/log/certbot-auto.cron file with rewriting

Read more about streams redirecting in *nix systems in article.

Environment variables

It's possible to set environment variables for the crontab. For example:

PATH=/sbin:/bin:/usr/sbin:/usr/bin:$PATH
22 11,23 * * * root /usr/local/sbin/certbot-auto renew --post-hook "systemctl reload nginx" 2>&1 1>/var/log/certbot-auto.cron

Cron runs command with it's own set of environment variables. PATH doesn't contain nginx binary path so we need to set it manually.

If we don't update PATH accordingly, then /var/log/letsencrypt/letsencrypt.log will contain following:

NoInstallationError("Could not find a usable 'nginx' binary. Ensure nginx exists, the binary is executable, and your PATH is set correctly.",)

Cron files

|- /
  |- /etc
    |- /cron.d          // Directory for files in cron format. See "Crontab format" paragraph.
      |- certbot_renew  // Our crontab for running certbot-auto.
    |- crontab          // System-wide crontab which runs shell-scripts from cron.hourly / cron.daily / etc.
    |- /cron.hourly     // Directory for shell-scripts to be run every hour by root (see /etc/crontab to find out the exact time).
      |- program.sh     // Our shell-script to be run every hour.
    |- /cron.daily      // Directory for shell-scripts to be run every day by root (see /etc/crontab to find out the exact time).
    |- /cron.weekly     // Directory for shell-scripts to be run every week by root (see /etc/crontab to find out the exact time).
    |- /cron.monthly    // Directory for shell-scripts to be run every month by root (see /etc/crontab to find out the exact time).
  |- /var/spool/cron
    |- /crontabs        // Directory for files in crontab format without "user" field. See "Crontab format" paragraph.
      |                 // Files inside are created and edited using the "crontab" util. See "Crontab util" paragraph.
      |- user1          // Crontab to be run by user1.
      |- user2          // Crontab to be run by user2.
      |- ...

Crontab util

/var/spool/cron/crontabs directory contains users' crontabs. /var/spool/cron/crontabs/user is created when user adds the first job using crontab -e.

Users can't manualy edit files in /var/spool/cron/crontabs. There is the crontab util for managing user's crontab. Frequently used options:

  • crontab -e runs user's crontab editor.
  • crontab -l displays user's crontab.

Note: crontab -l doesn't show crontabs from /etc/cron.*

Crontab syntax check

crontab doesn't allow to save a crontab with syntax errors:

"/tmp/crontab.5E7FV8/crontab":23: bad hour
errors in crontab file, can't install.
Do you want to retry the same edit? (y/n)

Syntax errors in /etc/cron.d crontabs can be found in logs (See "Logs" paragraph).

Permissions

You should ensure that the /etc/cron.d/<your_crontab_name> permissions are set to -rw-r--r-- and owner is set accordingly to the crontab content.

Example /etc/cron.d/certbot_renew contents:

22 11,23 * * * root /usr/local/sbin/certbot-auto renew --post-hook "systemctl reload nginx" 2>&1 1>/var/log/certbot-auto.cron

ls -l /etc/cron.d/certbot_renew output:

-rw-r--r-- 1 root root 179 Sep 11 09:48 /etc/cron.d/certbot_renew

Note: other permissions may cause errors as described in "Bad permissions" paragraph in this article.

Logs

Logs of crontabs reloading and syntax checking can be found using:

  • sudo cat /var/log/syslog | grep cron in Debian
  • sudo cat /var/log/cron in CentOS

Example output:

Aug 27 11:17:01 corpglory cron[935]: (*system*certbot_renew) RELOAD (/etc/cron.d/certbot_renew)
Aug 27 11:17:01 corpglory CRON[11475]: (root) CMD (   cd / && run-parts --report /etc/cron.hourly)
Aug 27 11:23:01 corpglory cron[935]: (*system*certbot_renew) RELOAD (/etc/cron.d/certbot_renew)
Aug 27 11:33:01 corpglory cron[935]: (*system*certbot_renew) RELOAD (/etc/cron.d/certbot_renew)
Aug 27 11:33:21 corpglory crontab[12935]: (root) LIST (root)
Aug 27 11:35:01 corpglory cron[935]: (*system*certbot_renew) RELOAD (/etc/cron.d/certbot_renew)
Aug 27 11:43:01 corpglory cron[935]: (*system*certbot_renew) RELOAD (/etc/cron.d/certbot_renew)
Aug 27 12:17:01 corpglory CRON[5383]: (root) CMD (/usr/local/sbin/certbot-auto renew --post-hook "systemctl reload nginx" 2>&1 1>/var/log/certbot-auto.cron)

Certbot debug logs are located in /var/log/letsencrypt directory.

Logs of the latest certbot_renew crontab run are located in /var/log/certbot-auto.cron.

Example output:

The following certs are not due for renewal yet:
  /etc/letsencrypt/live/example.com/fullchain.pem expires on 2019-10-14 (skipped)
  /etc/letsencrypt/live/example.com/fullchain.pem expires on 2019-10-10 (skipped)
  /etc/letsencrypt/live/example.com/fullchain.pem expires on 2019-11-17 (skipped)
  /etc/letsencrypt/live/example.com/fullchain.pem expires on 2019-10-14 (skipped)
Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/example.com/fullchain.pem (success)
  /etc/letsencrypt/live/example.com/fullchain.pem (success)
  /etc/letsencrypt/live/example.com/fullchain.pem (success)
  /etc/letsencrypt/live/example.com/fullchain.pem (success)

HTTPS certs

It's recommended to run certbot-auto renew twice a day to ensure that HTTPS certs are actual.

We have /etc/cron.d/certbot_renew crontab for this purpose:

PATH=/sbin:/bin:/usr/sbin:/usr/bin:$PATH
22 11,23 * * * root /usr/local/sbin/certbot-auto renew --post-hook "systemctl reload nginx" 2>&1 1>/var/log/certbot-auto.cron

certbot-auto renew will be executed every day at 11:22 AM and 11:22 PM. certbot-auto renews certificates only when it's necessary and reloads nginx after renewing.

You can change schedule of certbot-auto invocation by editing the file:

sudo vim /etc/cron.d/certbot_renew

Changes are reloaded automatically.

Result

We can be sure that HTTPS certificates on our Debian 8 servers are always actual. Thanks to cron and certbot.

Links