Skip to content

Instantly share code, notes, and snippets.

@justinhartman
Last active August 13, 2024 15:29
Show Gist options
  • Save justinhartman/79c527076ce7cc740423eb92b5600d52 to your computer and use it in GitHub Desktop.
Save justinhartman/79c527076ce7cc740423eb92b5600d52 to your computer and use it in GitHub Desktop.
Let's Encrypt Certbot post hook command for Nginx which checks the updated configuration files and reloads the server if everything validates.
#!/usr/bin/env bash
#
# Certbot Nginx Reload
#
# Let's Encrypt Certbot post hook command for Nginx which checks the updated
# configuration files and reloads the server if everything validates.
#
# Author : Justin Hartman <code@justinhartman.co>
# Version : 1.0.1
# License : MIT <https://opensource.org/licenses/MIT>
# Readme : https://git.io/JtMvL
# Copyright: Copyright (c) 2021 Justin Hartman <https://justinhartman.co>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#######################################
# Output coloured messages based on a
# set of arguments.
# Globals:
# None
# Arguments:
# String info, success, warning,
# danger, or none
# Returns:
# String printf styled message
#######################################
cprint() {
if [ "$2" == "info" ]; then
COLOR="96m"
elif [ "$2" == "success" ]; then
COLOR="92m"
elif [ "$2" == "warning" ]; then
COLOR="93m"
elif [ "$2" == "danger" ]; then
COLOR="91m"
else #default color
COLOR="0m"
fi
STARTCOLOR="\e[$COLOR"
ENDCOLOR="\e[0m"
printf "$STARTCOLOR%b$ENDCOLOR" "$1"
}
#######################################
# Define log file variable and check to
# see if an old file should be deleted.
# Globals:
# None
# Arguments:
# None
# Returns:
# String cprint method output
#######################################
logfile() {
NGINX_RELOAD_LOG=/tmp/nginx_reload.log
if [[ -f "$NGINX_RELOAD_LOG" ]]; then
cprint "Removing old log file.\n" "warning"
/bin/rm -f "$NGINX_RELOAD_LOG"
fi
}
#######################################
# Main script method to process the
# application thread.
# Globals:
# None
# Arguments:
# None
# Returns:
# String cprint method outputs
main() {
# Cleanup and load log file.
logfile
# Check if the nginx config file is OK.
nginx -t &>"$NGINX_RELOAD_LOG"
if grep -q 'test failed' "$NGINX_RELOAD_LOG"; then
cprint "Fail: Error with config file.\n" "danger"
cprint "Aborting nginx restart.\n" "danger"
cprint "Log file output:\n" "info"
cat "$NGINX_RELOAD_LOG"
exit 1
elif grep -q 'test is successful' "$NGINX_RELOAD_LOG"; then
cprint "Success: Reloading nginx server.\n" "success"
systemctl reload nginx
fi
}
# Load the main method.
main
# Exit gracefully.
exit 0

Certbot Nginx Reload Post Hook Script

About

This script is a post hook for certbot which will check all your nginx config files, validate them, and then reload the NGINX server.

Setup Let's Encrypt Certbot

You can follow my detailed howto tutorial on setting up a Debian server over here which contains everyting you need to install, configure and get certbot up and running on your Debian 10 machine.

Using the Script

If you've followed my instructions above, or you already have a working certbot application, then your next step is to use my script by configuring certbot to reload NGINX when it successfully renews certificates.

Step 1

First create the nginx-reload.sh post hook file:

$ sudo nano /etc/letsencrypt/renewal-hooks/post/nginx-reload.sh

Step 2

You are going to want to copy the code of the script by clicking here and head on over and paste it in your /etc/letsencrypt/renewal-hooks/post/nginx-reload.sh file.

Step 3

Once you have the file saved, make it executable and reload nginx.

$ sudo chmod a+x /etc/letsencrypt/renewal-hooks/post/nginx-reload.sh
$ sudo nginx -t && sudo systemctl reload nginx

Done. The script is now setup to begin working automatically in the background. Certbot runs a cronjob twice daily and if a certificate is renewed your newly created post hook script will be executed and run.

Usage

The script is not intended to be run manually as it's primary use is for certbot to use it as a post hook function when it has finished renewing a domain. That said, you can execute the script manually or via certbot as follows.

Certbot

With certbot it will be run after the renew command is completed.

$ sudo certbot renew

Manual

This only runs the check and reload.

$ sudo /etc/letsencrypt/renewal-hooks/post/nginx-reload.sh

Success Output

Executing the nginx-reload.sh file without any errors in any of your nginx config or virtual host files will output the following success messages to your console:

$ sudo /etc/letsencrypt/renewal-hooks/post/nginx-reload.sh
Removing old log file.
Success: Reloading nginx server.

Similarly, when the certbot cronjob executes and runs this post hook script the following successful output will be seen.

$ sudo certbot renew
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Processing /etc/letsencrypt/renewal/example.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Plugins selected: Authenticator webroot, Installer None
Renewing an existing certificate
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/example.com/fullchain.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/example.com/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Running post-hook command: /etc/letsencrypt/renewal-hooks/post/nginx-reload.sh
Output from nginx-reload.sh:
Removing old log file.
Success: Reloading nginx server.

Error Output

Executing the nginx-reload.sh file with an error in either your nginx config or virtual hosts files will output the following error and log file:

$ sudo /etc/letsencrypt/renewal-hooks/post/nginx-reload.sh
Removing old log file.
Fail: Error with config file.
Aborting nginx restart.
Log file output:
nginx: [emerg] "worker_connections" directive is not allowed here in /etc/nginx/nginx.conf:7
nginx: configuration file /etc/nginx/nginx.conf test failed

Similarly, when the certbot cronjob executes and runs this post hook script the following output will be seen.

$ sudo certbot renew
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Processing /etc/letsencrypt/renewal/example.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Plugins selected: Authenticator webroot, Installer None
Renewing an existing certificate
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/example.com/fullchain.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/example.com/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Running post-hook command: /etc/letsencrypt/renewal-hooks/post/nginx-reload.sh
Output from nginx-reload.sh:
Removing old log file.
Fail: Error with config file.
Aborting nginx restart.
Log file output:
nginx: [emerg] "worker_connections" directive is not allowed here in /etc/nginx/nginx.conf:7
nginx: configuration file /etc/nginx/nginx.conf test failed

Hook command "/etc/letsencrypt/renewal-hooks/post/nginx-reload.sh" returned error code 1

License

MIT https://opensource.org/licenses/MIT

Copyright (c) 2021 Justin Hartman https://justinhartman.co

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

@ynott
Copy link

ynott commented Jan 16, 2023

tyyy

@justinhartman
Copy link
Author

tyyy

You are most welcome @ynott ;-)

@jeff-kilbride
Copy link

Great script, thanks!

@justinhartman
Copy link
Author

You are very welcome @jeff-kilbride - glad it's of use to people other than just me! :-)

@ynott
Copy link

ynott commented Dec 30, 2023

Hi folks,

Step 2 of 02_README.md describes saving nginx-reload.sh to /etc/letsencrypt/renewal-hooks/post/.
But, A better suggestion might be to save it to /etc/letsencrypt/renewal-hooks/deploy/.

The /deploy directory can contain scripts that are executed only when certbot successfully renews a certificate.

certbot/certbot#8368 (comment)

@Siphonay
Copy link

Really useful script, thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment