Let’s Encrypt: Reload Nginx after Renewing Certificates

Today I had an incident which caused my webserver to serve expired certificates. My blog relies on Let’s Encrypt for SSL/TLS certificates, which have to be renewed every 3 months. Usually, the cronjob which runs certbot --renew takes care of it automatically. However, there is one step missing, the server must reload the renewed certificates. Most of the time, the server gets reloaded often enough so everything is okay, but today, its been a quite a while since the last time since the nginx server was restarted, so expired certificates were served and the blog became unavailable.

To workaround it, we can make sure nginx reloads it configuration after each successful certificate renewal. The automatic renewal is defined in /etc/cron.d/certbot. The default contents under Debian Jessie are as follows:

# /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 && perl -e 'sleep int(rand(3600))' && certbot -q renew

The last line makes sure certificate renewal runs twice a day. Append --renew-hook "/etc/init.d/nginx reload" to it, so it looks like this:

0 */12 * * * root test -x /usr/bin/certbot && perl -e 'sleep int(rand(3600))' && certbot -q renew --renew-hook "/etc/init.d/nginx reload"

The --renew-hook runs the next argument after each successful certificate renewal. In our case we use it to reload the nginx configuration, which also reloads the newly renewed certificates.

Update 2019-02-27:

renew-hook has been deprecated in recent versions of certbot. Plus, debian moved from using cronjobs for automatic renewals to systemd timer if they are available. On the other hand, now certbot supports having hooks in configuration files. So, instead of what is described above, i would suggest creating a file /etc/letsencrypt/renewal-hooks/deploy/01-reload-nginx with the following content:

#! /bin/sh
set -e

/etc/init.d/nginx configtest
/etc/init.d/nginx reload

don’t forget to make the file executable.

11 thoughts on “Let’s Encrypt: Reload Nginx after Renewing Certificates”

  1. Hi

    Thanks for your instruction on how to restart Nginx ONLY after a successful renewal of certificates. All the websites I’ve checked talk about automatic restarting the web server, which is very inefficient if you do an automatic renewal of your certificates once or twice a day.

    Your solution is interesting, but can you tell me if that’s compatible with the letsencrypt tool that is available in Ubuntu 16.04 (as instructed on https://certbot.eff.org/#ubuntuxenial-nginx)? If not, can you give a little more information on how to set it up in this kind of environment?

    Thank you in advance

  2. You can also pass a --renew-hook "service nginx reload" to your certbot certonly --webroot call and it will be automatically executed in the renewal configuration. No need to manually edit the CRON file.

  3. Alix Axel has the correct idea here. If you have already created your certificates, then you can add the following in your domain renewal config under [renewalparams]:

    /etc/letsencrypt/renewal/yourdomain.com.conf:

    [renewalparams]
    renew_hook = service nginx reload
    
  4. It depends on how your cron is configured to run. By default it’ll run as root.

  5. I stumbled here because certs weren’t being refreshed in nginx. I’m running Ubutu 16.04 LTS.

    If I may suggest, replace your hook for “/usr/sbin/nginx -t && /etc/init.d/nginx reload” . This will ensure that you’re not automatically reloading on a broken config (because maybe you were playing with the configs at that moment).

    After installation, I had written a (custom) root cronjob that called “–renew-hook ‘nginx reload'”, but I was unaware that certbot had already installed one in /etc/cron.d/certbot . Very sneaky. The two cronjobs were of course competing with each other, and whenever /cron.d/certbot got to renew the certs before my custom cronjob got to it, no reloading would take place (–renew-hooks only fire after actual renewal). Thanks for helping me realize that.

  6. Same issue here, thanx. If you have tons of domains it’s much easier to edit just the cron file.

  7. As of 0.17, --renew-hook has been replaced with --deploy-hook. So far, it looks like it’s a straight-forward facade. However, there’s no guarantee it won’t be completely removed now that it’s changed.

    I’ve been looking for --renew-hook docs everywhere, and have only been able to find a collection of SO/SE posts, random forum threads, and some blogs like yours. I think I used this post when I set up at least one of my certbot instances, and wanted to make sure you knew about the update.

  8. Be careful with --deploy-hook as it will run “once for each successfully issued certificate” which would reload your nginx server quite a few times for a mult-tenant server. We’re using --post-hook instead as it will only run once after all certs are renewed.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.