How do I schedule the Let's Encrypt certbot to automatically renew my certificate in cron?

100.6k views Asked by At

I've seen conflicting recommendations. From the eff.org docs:

if you're setting up a cron or systemd job, we recommend running it twice per day... Please select a random minute within the hour for your renewal tasks.

I've also seen recommendations for weekly jobs.

I'm not a cron expert, so I'd prefer an answer with detailed steps for setting up the cron job.

10

There are 10 answers

5
V-Q-A NGUYEN On BEST ANSWER

I recently (April 2018) installed and ran certbot (version 0.22.2) on an Ubuntu 16.04 server, and a renewal cron job was created automatically in /etc/cron.d/certbot.

Here's the cron job that was created:

# /etc/cron.d/certbot: crontab entries for the certbot package
#
# Upstream recommends attempting renewal twice a day
#
# Eventually, this will be an opportunity to validate certificates
# haven't been revoked, etc.  Renewal will only occur if expiration
# is within 30 days.
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

0 */12 * * * root test -x /usr/bin/certbot -a \! -d /run/systemd/system && perl -e 'sleep int(rand(3600))' && certbot -q renew

Please check this before putting a new Cron job.

Update (From @Hamish Downer's comment):

It's worth being aware that the above cron job won't run certbot renew if /run/systemd/system is present - this is because instead a systemd timer is running certbot - read more about certbot and systemd timers here.

3
Chapman Atwell On

So I settled on scheduling it to run once a day. First I tested auto-renew as the docs recommend:

sudo letsencrypt renew --dry-run --agree-tos

Then I updated the crontab:

sudo crontab -e

This is the line I added:

12 3 * * *   letsencrypt renew >> /var/log/letsencrypt/renew.log

This runs the renew everday at 3:12 am. I presume the docs recommend "a random minute within the hour" to distribute the load on the renew servers. So I suppose anything other than 0, 15, 30, or 45 is preferred.

I looked into randomizing the minute in the cron setting, like Jenkins allows you to do. On original EEF page is this Example:

0 0,12 * * * python -c 'import random; import time; time.sleep(random.random() * 3600)' && /usr/local/bin/certbot-auto renew

Finally, I tested the cron command using sudo bash:

sudo bash -c "letsencrypt renew >> /var/log/letsencrypt/renew.log"
2
ooo On

for renew every 2 month:

#nano /etc/cron.d/certbot    

30 03 01 */2 * echo "2" | certbot --nginx -v -d yourdomain.com
1
Flavio Oliveira On

To keep simple set a timer to validate automatically:

systemctl status certbot.timer
2
kub1x On

Ok. So being on Debian (or Ubuntu) with systemd I had probably the same problem like others - cron job not firing. I needed to make some extra steps and observations not mentioned elsewhere, so making separate answer for it.


In my case the /etc/systemd/system/ directory exists, so the job in /etc/cron.d/certbot stops at the initial test.

BUT the /etc/systemd/system/certbot.timer was a pointer to /dev/null. That means it is a masked timer. When I did systemd unmask certbot.timer the link was removed, but I had nothing to replace it with (tried locate certbot.timer but none was installed on my system). I could also still see the timer in systemd list-timers --all, but it was an emtpy file so removed that too using systemd disable certbot.timer. The service in /etc/systemd/system/certbot.service was completely absent.

So after actually cleaning all the certbot-related stuff from /etc/systemd/system/ I created the necessary files manually.

# /etc/systemd/system/certbot-renewal.service
[Unit]
Description=Certbot Renewal
[Service]
ExecStart=/usr/local/bin/certbot -q renew --post-hook "systemctl reload nginx"
# /etc/systemd/system/certbot-renewal.timer
[Unit]
Description=Run certbot twice daily

[Timer]
OnCalendar=*-*-* 00,12:00:00
RandomizedDelaySec=43200
Persistent=true

[Install]
WantedBy=timers.target

The timer file content comes from this answer.

I started and checked the whole thing by running:

sudo systemctl start certbot-renewal.timer
sudo systemctl enable certbot-renewal.timer
sudo systemctl list-timers --all
sudo journalctl -u certbot-renewal.service

Few more notes:

  • I have certbot in /usr/local/bin/certbot instead of /usr/bin/certbot (figured using which certbot), don't know why.
  • I'm using nginx, so need to reload it in the post-hook to take the renewed certs into account.
0
andruso On

Adding the following line to /etc/crontab runs renewal attempt daily on a random minute between 00:00 and approximately 16:40:

1  1    * * *   root    sleep ${RANDOM:0:3}m && /home/admin/certbot-auto renew --quiet --no-self-upgrade --authenticator webroot --installer apache -w /var/www/mywebroot

Works great for more than a year now.

The renew command itself may vary for you - I used webroot as it seemed most robust at that time.

0
Javeed Shakeel On

Normally while you run a certbot for any webserver in an Ubuntu 16.04 server it automatically creates a cron

#cat /etc/cron.d/certbot

0 */12 * * * root test -x /usr/bin/certbot -a \! -d /run/systemd/system && perl -e 'sleep int(rand(3600))' && certbot -q renew
5
Melroy van den Berg On

In Debian Jessie and up (incl. Ubuntu) cron is not executed for Certbot renewal. Instead the systemd timer is used.

UPDATE: When you're using Snap (which is the recommended install method of Certbot). Off the record: I don't like Snap.

Auto renew timer is located at: /etc/systemd/system/snap.certbot.renew.timer. Which has the content:

[Unit]
# Auto-generated, DO NOT EDIT
Description=Timer renew for snap application certbot.renew
Requires=snap-certbot-3566.mount
After=snap-certbot-3566.mount
X-Snappy=yes

[Timer]
Unit=snap.certbot.renew.service
OnCalendar=*-*-* 08:41
OnCalendar=*-*-* 14:01

[Install]
WantedBy=timers.target

As you can see the renew job service is called twice a day. Once ACME ARI extension is implemented this renew frequency might need to be increased in the future, but I digress.

Note: Do not try to modify these files, changes will be reverted back by a snap refresh.

And the service file /etc/systemd/system/snap.certbot.renew.service, that the timer is triggering, has the following content:

[Unit]
# Auto-generated, DO NOT EDIT
Description=Service for snap application certbot.renew
Requires=snap-certbot-3566.mount
Wants=network.target
After=snap-certbot-3566.mount network.target snapd.apparmor.service
X-Snappy=yes

[Service]
EnvironmentFile=-/etc/environment
ExecStart=/usr/bin/snap run --timer="00:00~24:00/2" certbot.renew
SyslogIdentifier=certbot.renew
Restart=no
WorkingDirectory=/var/snap/certbot/3566
TimeoutStopSec=30
Type=oneshot

See the status of the timer: systemctl status snap.certbot.renew.timer

When using the Nginx installer via certbot (certbot --nginx), the renew configuration files are located in the /etc/letsencrypt/renewal directory. These Certbot conf files contain information that the certificate(s) are deployed to the Nginx server and reload Nginx automatically when required:

authenticator = nginx
installer = nginx
server = https://acme-v02.api.letsencrypt.org/directory
key_type = ecdsa

On distros that might not have Snap (good!), the timer should be located at: /lib/systemd/system/certbot.timer. With the service: /lib/systemd/system/certbot.service

Which contains:

[Service]
Type=oneshot
ExecStart=/usr/bin/certbot -q renew
PrivateTmp=true

In order to list all the timers, execute the following command in the terminal:

systemctl list-timers

Hopefully Certbot is part of this:

Mon 2019-02-04 08:38:45 CET 9h left Sun 2019-02-03 15:25:41 CET 8h ago certbot.timer certbot.service

How-to install Certbot on a older Debian based distro (it may vary depending on your Linux distribution).

But within Debian Stretch for example you can install the back-port package of certbot via:

sudo apt-get install certbot -t stretch-backports

This will install the files I showed above for you automatically! And thus automatically schedule a certbot timer for you, which runs the service, which runs again the renew.

Manually running a renew is always possible via:

sudo /usr/bin/certbot renew

Can be forced via --force-renewal flag. For more info see the help text of renew:

/usr/bin/certbot --help renew

Files part of the certbot package (incl. but not limited by):

dpkg-query -L certbot
...
/lib/systemd/system/certbot.service
/lib/systemd/system/certbot.timer
...
0
TekOps On

I figured out how to make it run by cron on systems where the webserver could not be stopped/started by the certbot tool reliably or could not access the verification file because it is not in the webtree. In this case you do the initial setup of an offline initial installation and then renewals can be done by cron.

Here is my script and it is working in production:


#!/bin/bash

# get root apache process id
pid=`ps -ef |grep apache2 |grep root | egrep -v "grep" |awk '{print $2;}'`

echo "Found  Apache2  pid=($pid)\n"

# shut it down gracefully (our way)

# request shutdown
kill -TERM $pid

# wait 4 seconds
sleep 4

# no running .pid to remove

# show if it is still in memory
ps -ef |grep apache2 |egrep -v "grep"

# now get new  certificate
# request just certificate,  with this hostname, standalone server, non-interactive
# uncomment for real certificates, but make sure test certificate is  commented
#/usr/bin/certbot certonly --test-cert --standalone -n -d <your.server.tld> 2>&1
# uncomment for test certificates
#/usr/bin/certbot certonly --test-cert --dry-run --standalone -n -d <your.server.tld> 2>&1
/usr/bin/certbot renew --force-renewal --standalone -n 2>&1

# restart apache2 (we know it will report fail, but it will actually start it)
echo "starting apache2...\n"
/bin/systemctl start apache2 2>&1

# check if it's in memory...
npid=`ps -ef |grep apache2 |grep root | egrep -v "grep" |awk '{print $2;}'`

echo "Found New Apache2  pid=($npid)\n"

# if npid is empty try restarting again...
#/bin/systemctl restart apache2 2>&1

echo "done."
echo ""

I set up the cronjob as follows:


# stop apache2, forcibly renew every 3 weeks and then restart apache2
0 1 3,18 * *    /bin/touch /var/adm/ratglc_ssl_certbot.log; /home/tk/bin/ratglc 2>&1 >> /var/adm/ratglc_ssl_certbot.log

I do have other monitoring that alerts me if SSL stops working or the webserver does not come back online and so far neither of those things has happened. One thing-- systemctl reports apache2 "did not start" but it did and this script checks that. I write all output to a log for review/monitoring later.

It's not pretty but it works.

Thanks, David

1
dessalines On

None of these answers worked for me in 2023, because certbot cannot renew if nginx is running on port 80.

The following entry in the crontab works:

43 6 * * * sudo certbot renew --pre-hook "sudo systemctl stop nginx" --post-hook "sudo systemctl start nginx"