145

Is this correct way to set cron for renewal of Let's Encrypt cert in Apache2 ? I use Ubuntu 16.04.

@monthly letsencrypt renew && service apache2 reload
Michael Hampton
  • 237,123
  • 42
  • 477
  • 940
user3448600
  • 1,449
  • 2
  • 12
  • 12
  • 9
    As one of the answers states below, certbot v0.19.0 (and maybe some earlier) already create a crontab entry @ `/etc/cron.d/certbot` – xgMz Oct 29 '17 at 17:40
  • Also, the certbot apache plugin with the tls-sni validation will reload apache as part of the validation procedure after the new certificate has been retrieved. – xgMz Oct 29 '17 at 17:47
  • 2
    There is an answer below that is very important for new installs (as of JAN 2019), certbot automatically adds system timer and cron job schedule so the cron setup is not needed on your part. – Cory Robinson Feb 09 '19 at 14:51

12 Answers12

211

Monthly is not frequent enough.

This script should run at least weekly, and preferably daily. Remember that certs don't get renewed unless they are near to expiration, and monthly could cause your existing certs to occasionally be expired already before they get renewed.

The name of the program is certbot, which was renamed from letsencrypt. If you are still using letsencrypt, you need to update to the current version.

Aside from those issues, it's about the same as my cron jobs.

43 6 * * * certbot renew --post-hook "systemctl reload nginx"

Note: in 18.04 LTS the letsencrypt package has been (finally) renamed to certbot. It now includes a systemd timer which you can enable to schedule certbot renewals, with systemctl enable certbot.timer and systemctl start certbot.timer. However, Ubuntu did not provide a way to specify hooks. You'll need to set up an override for certbot.service to override ExecStart= with your desired command line, until Canonical fixes this.

warren
  • 17,829
  • 23
  • 82
  • 134
Michael Hampton
  • 237,123
  • 42
  • 477
  • 940
  • I can just run `crontab -e` and paste `@daily certbot renew && systemctl reload apache2` and it will work, right? I am not so experienced with Linux. I don't know how to test this cron jobs. – user3448600 Jul 20 '16 at 00:45
  • @user3448600 You may wish to read http://serverfault.com/q/449651/126632 – Michael Hampton Jul 20 '16 at 01:23
  • 6
    What time window is "near to expiration"? – Andre Figueiredo May 11 '17 at 18:49
  • @AndreFigueiredo In my testing the certificate auto renews about a month before the certificate expires. I couldn't tell if it is exactly 30 days (i suspect it is). – glaux Jun 21 '17 at 13:47
  • I suppose for apache it will be `43 6 * * * certbot renew --post-hook "service apache2 reload"` ?! – Meloman Sep 14 '17 at 12:02
  • 17
    It may be better to user `--renew-hook` instead of `--post-hook`, to only restart if the cert is successfully renewed. – mwfearnley Oct 06 '17 at 09:27
  • Also, make sure the renew command actually works when run as a cronjob, not just in the terminal, because the cronjob will probably use a different $PATH (https://stackoverflow.com/a/11148907/446106). Check the output in /var/log/letsencrypt. Or fully specify the path of the command if in doubt. – mwfearnley Oct 06 '17 at 09:29
  • 2
    I read to use ```--deploy-hook``` instead of ```--renew-hook```, but I'm not sure if it matters. Is it necessary to reload apache? I thought that the python-certbot-apache package does this for us when needed. – snapfractalpop Oct 11 '17 at 06:17
  • 13
    For apache/httpd, `certbot renew` will just work™ – aairey Oct 25 '17 at 11:39
  • @glaux Indeed: **cat /etc/cron.d/certbot** says ** Renewal will only occur if expiration is within 30 days.** – vitsoft Nov 13 '17 at 20:51
  • Thanks a lot for mentioning the 18.04 changes. I had my certificates renew automatically but couldn't find the cron job anywhere and I wasn't sure if I did that manually or not. Now I know how it works and how to check it if needed. – Luxian Aug 18 '18 at 19:43
  • 1
    I just wanted to add, rather than overriding ExecStart to reload nginx, just add an ExecStartPost line to certbot.service to reload your webserver after it's done: `ExecStartPost=/usr/sbin/service nginx reload`. Worked for me! – J.D. Mallen Dec 15 '18 at 06:16
  • 1
    @J.D.Mallen Using `ExecStartPost=` is a good idea. Why didn't I think of that? But be aware that the `service` command is deprecated; it won't be around forever. Switch to the corresponding `systemctl` commands. – Michael Hampton Dec 15 '18 at 15:51
  • 2
    You do not have to override service. You can put executable script with "systemctl reload nginx" into /etc/letsencrypt/renewal-hooks/post/100-reload-nginx – Vital Belikov Jul 12 '19 at 08:27
  • On Centos 7 the certbot package provides a `certbot-renew` service which you can enable start using `systemctl enable certbot-renew` and `systemctl start certbot-renew`. You can add post-hooks and other options by editing `/etc/sysconfig/certbot`. – n.abing Aug 19 '19 at 04:51
  • 1
    @n.abing The service is a oneshot; you need to enable `certbot-renew.timer` instead. – Michael Hampton Aug 19 '19 at 05:23
  • @MichaelHampton Yes, you're right. – n.abing Aug 20 '19 at 07:47
  • Let's Encrypt in the past has recommended running such a script *twice daily*. Such frequency is not necessary to prevent expiration, but rather, to ensure that in the case a certificate is revoked, it will be replaced quickly. There is a security risk to updating less frequently, in the scenario that a certificate is compromised and revoked. – cazort Sep 09 '21 at 20:08
  • @VitalBelikov Just to be clear - yes: If you want "global" renewal hooks for all certs. But, you can also add hooks to `/etc/letsencrypt/renewal/(CERTNAME).conf` - This has advantage of using a different pre and/or post-hook on different certificates. (Say you have domain that handles mail. Another that handles web. Sure you could restart all services/daemons involved each time, but for more granularity, use `./renewal/{certname}.conf`. For more see https://gist.github.com/bmatthewshea/f6a66ddb2e52ccdbc905aed73d9ca59c (step #4) – B. Shea Mar 18 '22 at 15:44
  • 1
    @snapfractalpop Your mention made me notice the difference between them. `--renew-hook` command won't be executed when issuing the cert but it will do in the next renewal. `--deploy-hook` command will be executed when issuing the cert and in the next renewal it will be executed too. https://community.letsencrypt.org/t/argument-renew-hook-conflicts-with-deploy-hook-value/65462/3 – xiaoxinmiao Jun 15 '22 at 03:18
77

I recently (October 2017) installed and ran certbot 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:

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

It would be a good idea to check, if this file already exists before creating a crontab entry.

Dennis
  • 3
  • 2
ishigoya
  • 1,038
  • 6
  • 7
  • 4
    I saw I had this as well after running certbot. Very nice that lets encrypt did this! It's a great project. – Bjorn Dec 11 '17 at 07:24
  • 16
    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](https://community.letsencrypt.org/t/cerbot-cron-job/23895/5). – Hamish Downer Aug 02 '18 at 19:55
  • Thanks for mentioning that a cronjob had already been installed. I was not aware of that till I read your post. – NilsB Dec 01 '18 at 06:58
  • 3
    For anyone wondering, that makes it run every 12 hours. The other answer `43 6 * * *` would make it run every day at 6:43 AM. Once a day should be sufficient, but either one works fine. – orrd Aug 22 '19 at 23:38
56

The certbot documentation recommends running the script twice a day:

Note:

if you're setting up a cron or systemd job, we recommend running it twice per day (it won't do anything until your certificates are due for renewal or revoked, but running it regularly would give your site a chance of staying online in case a Let's Encrypt-initiated revocation happened for some reason). Please select a random minute within the hour for your renewal tasks.

As Michael Hampton mentions the name has changed to certbot, but they still provide the -auto option that keeps itself updated. The certbot-auto command need root priviledges to run, so the line in your cron script should look something like this:

52 0,12 * * * root /full/path/to/certbot-auto renew --quiet

In my own case the certbot-auto script is placed in the git-user's home directory. The exact command is then

52 0,12 * * * root /home/git/certbot-auto renew --quiet

Note that the example in the documentation corresponds to a relative path, as indicated by the dot which can be confusing:

./path/to/certbot-auto renew --quiet

Be sure to testrun the renew command in a shell beforehand to test the path, if the certificate isn't due for renewal nothing will happen (run this test without the --quiet flag to see what is happening).

It is not strictly necessary to reload the server when the certificate is renewed in this way, since the path to the live certificate doesn't change if set up correctly.

This is true if you are running apache - for nginx, consider adding a renew hook, such as:

52 0,12 * * * root certbot renew --renew-hook 'service nginx reload'

In a docker environment (edit 2020-09-18)

While the above is still true to the best of my knowledge, if your application is running in a docker environment you can let this proxy network take care of all your certificates - both locally and in a live environment. I'm not affiliated with the project, but I've been using it happily for a few years now and haven't touched cron (for this task) or certbot-scripts since.

It has the added benefit of forcing traffic through port 443 automatically (if you enable it) so you don't have to fiddle with apache or nginx configuration - the container serving the web application just need to serve port 80 and the proxy takes care of the rest.

glaux
  • 671
  • 5
  • 7
  • 1
    I like how this is explained, detailing service restart is not needed (it could make a mess if someone is doing anything on it, having a chance twice a day to get caught) and mentioning privileges needed. – Gusstavv Gil Feb 21 '17 at 02:18
  • 4
    This is not true — it *is* necessary to reload the server, at least with Nginx — nginx appears to cache the initial certificate and does not register a new cert even if the file changes. See this post for info on using `--renew-hook` to only restart after a successful renewal: https://www.guyrutenberg.com/2017/01/01/lets-encrypt-reload-nginx-after-renewing-certificates/ – Whatcould Aug 18 '17 at 01:43
50

You shouldn't have to set up anything. Any recent Debian/Ubuntu install of certbot should install a systemd timer and a cron job (and the cron job will only run certbot if systemd is not active, so you don't get both running).

systemd timer

You can check your systemd timers using command systemctl list-timers (or systemctl list-timers --all if you also want to show inactive timers). Something like this:

% sudo systemctl list-timers
NEXT                         LEFT        LAST                         PASSED      UNIT                         ACTIVATES
Fri 2018-08-03 06:17:25 UTC  10h left    Thu 2018-08-02 06:27:13 UTC  13h ago     apt-daily-upgrade.timer      apt-daily-upgrade.service
Fri 2018-08-03 11:43:29 UTC  15h left    Thu 2018-08-02 16:54:52 UTC  3h 7min ago certbot.timer                certbot.service
Fri 2018-08-03 12:44:58 UTC  16h left    Thu 2018-08-02 19:14:58 UTC  47min ago   apt-daily.timer              apt-daily.service
Fri 2018-08-03 19:43:44 UTC  23h left    Thu 2018-08-02 19:43:44 UTC  18min ago   systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service
Mon 2018-08-06 00:00:00 UTC  3 days left Mon 2018-07-30 00:00:09 UTC  3 days ago  fstrim.timer                 fstrim.service

The certbot timer should be here /lib/systemd/system/certbot.timer and it will execute the command specified in /lib/systemd/system/certbot.service

certbot.timer will execute the `certbot.service at 12 am and 12 pm, after a random delay of up to 12 hours (43200 seconds).

# cat /lib/systemd/system/certbot.timer
[Unit]
Description=Run certbot twice daily

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

[Install]
WantedBy=timers.target

and certbot.service will execute the renew command.

# cat /lib/systemd/system/certbot.service
[Unit]
Description=Certbot
Documentation=file:///usr/share/doc/python-certbot-doc/html/index.html
Documentation=https://letsencrypt.readthedocs.io/en/latest/
[Service]
Type=oneshot
ExecStart=/usr/bin/certbot -q renew
PrivateTmp=true

cron job

As others have mentioned, there is also a cron job installed in /etc/cron.d/certbot:

# 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(43200))' && certbot -q renew

This is doing:

  • test -x /usr/bin/certbot -a \! -d /run/systemd/system - check if /usr/bin/certbot is an executable file and that /run/systemd/system is not a directory. Only continue to the next bit if this check succeeds.
    • The systemd part of the check effectively means that if systemd is running, don't run certbot from the cron job - leave that to the timer.
  • perl -e 'sleep int(rand(43200))' - sleep a random amount between 0 seconds and 12 hours (43200 = 12 x 60 x 60).
  • certbot -q renew check your certificates and renew any if required. The -q flag is "quiet" - don't produce any output unless there is an error.

I was originally confused by the cron job as it wasn't going to run due to systemd, so how would certbot be run? I found the answer in this forum post which is what I based this answer on.

Hamish Downer
  • 9,142
  • 6
  • 36
  • 49
  • 4
    "You shouldn't have to set up anything" but my cert expired recently, and I installed certbot about 3 months ago. `/etc/cron.d/certbot` exists, `systemctl list-timers` shows `certbot.timer`, but my certs weren't renewed. Running `certbot` manually worked fine, so I don't know what's going on. Ended up adding an old school `crontab` entry. – Dan Dascalescu Oct 16 '18 at 05:20
  • This is the most up to date and correct answer but with a caveat that it depends on what dist you are running: https://certbot.eff.org/docs/using.html#id8 – olive_tree Nov 22 '18 at 20:16
  • "and the cron job will only run if systemd is not active". Can you help in finding some doc about this "precedence" explained please? – titus May 31 '19 at 11:22
  • 1
    @titus the explanation is that the cron job first runs a `test` to check if systemd is active and if it is, the cron job immediately exits without running `certbot` - see the text about the cron job. I shall edit the text to be more precise. – Hamish Downer Jun 01 '19 at 18:42
  • 1
    Most competent answer for up-to-date systems a set up in or after 2018. – Max May 11 '20 at 10:26
  • Thanks for your help. You must include `systemctl enable certbot.timer` (run at boot) and `systemctl start certbot.timer` (run when scheduled) for people creating new timer. – OscarGarcia Sep 30 '20 at 08:17
  • The path to the timer, when using the new recommended install method with snap, is now `/etc/systemd/system/snap.certbot.renew.timer` – Rmatt Jun 11 '21 at 15:08
7

Other members already provided lot more detailed answers. But looks like I should mention it here.

As of certbot version 0.21.1 --renew-hook flag is changed to --deploy-hook Make sure you're not using deprecated flag.

certbot renew --deploy-hook "systemctl restart myservice"
Shinebayar G
  • 275
  • 4
  • 9
5

For LetsEncrypt certificate renewal, I generally use getssl. It is a very handy shell wrapper which can even install certificate on other machines via SSH connection.

The cron entry is the following:

01 23 * * * root /root/scripts/getssl/getssl -u -a -q >>/var/log/getssl.log 2>&1 ; /usr/sbin/apache2ctl graceful

As already suggested, you should run it daily or, even better, twice a day.

shodanshok
  • 44,038
  • 6
  • 98
  • 162
5

As already mentioned by glaux:

Note: if you're setting up a cron or systemd job, we recommend running it twice per day (it won't do anything until your certificates are due for renewal or revoked, but running it regularly would give your site a chance of staying online in case a Let's Encrypt-initiated revocation happened for some reason). Please select a random minute within the hour for your renewal tasks.

Source: https://certbot.eff.org/all-instructions/#debian-8-jessie-apache

So i ended up using this (running is twice a day, at 01:00 and at 13:00 everyday):

6 1,13 * * * certbot renew --post-hook "service apache2 restart"

or even better:

6 1,13 * * * certbot renew --renew-hook "service apache2 restart"

I didn't test but this should work also:

6 1,13 * * * certbot renew --post-hook "/etc/init.d/apache2 restart"
6 1,13 * * * certbot renew --renew-hook "/etc/init.d/apache2 restart"

--pre-hook and --post-hook hooks run before and after every renewal attempt. If you want your hook to run only after a successful renewal, use --renew-hook in a command like this.

Source: https://certbot.eff.org/docs/using.html

Tadej
  • 371
  • 5
  • 5
3

Since the preferred install method of certbot was modified to snap, the path to the timer is now /etc/systemd/system/snap.certbot.renew.timer.

You may also check the configuration via running systemctl show certbot.timer

Rmatt
  • 131
  • 3
2

If your Certbot certificate was obtained using the standalone plugin then you might need to stop your web server in order for the renewal to succeed. This can be done in cron using the --pre-hook and --post-hook operators: Certbot documentation.

Grant_Bailey
  • 53
  • 1
  • 2
  • 10
2

This is what I use:

/opt/letsencrypt/letsencrypt-auto renew

gives output as:

Upgrading certbot-auto 0.8.1 to 0.9.1...
Replacing certbot-auto...
Creating virtual environment...
...
new certificate deployed with reload of apache server; fullchain is
/etc/letsencrypt/live/host.simplecoin.cz/fullchain.pem
-------------------------------------------------------------------------------

Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/host.simplecoin.cz/fullchain.pem (success)

And its saying that apache is restarted already, so no need to do it over again. If I run it again:

Cert not yet due for renewal

therefore it's not problem to renew certificate daily, my cron is then:

@daily /opt/letsencrypt/cronautorenew.sh

I use script to tweak logging to separate file, so here is my cronautorenew.sh:

#!/usr/bin/env bash
printf "\nattempt to renew certificates" >>/var/log/letsencrypt_cron.log 2>&1
date >>/var/log/letsencrypt_cron.log 2>&1
/opt/letsencrypt/letsencrypt-auto renew >>/var/log/letsencrypt_cron.log 2>&1
printf "renew finished\n" >>/var/log/letsencrypt_cron.log 2>&1
Pavel Niedoba
  • 234
  • 1
  • 3
  • 10
1

According to EFF certbot guide

Many Linux distributions provide automated renewal when you use the packages installed through their system package manager.

If you are not sure whether or not your system has this already automated, check your system’s crontab (typically in /etc/crontab/ and /etc/cron.*/* $ crontab -l and systemd timers $ systemctl list-timers.

Suhayb
  • 113
  • 4
0

1.Make sure the task is started

systemctl status certbot.timer

● certbot.timer - Run certbot twice daily
 Loaded: loaded (/lib/systemd/system/certbot.timer; enabled; vendor preset: enabled)
 Active: active (waiting) since Wed 2022-06-15 11:05:24 CST; 25min ago
Trigger: Thu 2022-06-16 06:12:29 CST; 18h left
Triggers: ● certbot.service

Jun 15 11:05:24 iZwz96pjn701slg1l6nzbuZ systemd[1]: Started Run certbot twice daily.

2.Just add the following script to a file - named whatever you want - and put it in /etc/letsencrypt/renewal-hooks/deploy/

Don't forget to make the file executable with the sudo chmod +x /path/to/file command.

#!/bin/sh
do
        if [ "$domain" = mail.example.com ]
        then
                service apache2 reload
        fi
done

3.Check if it is executed

cat /var/log/letsencrypt/letsencrypt.log

Source: https://www.xhalford.com/using-hook-scripts-with-certbot/

xiaoxinmiao
  • 101
  • 2