Last active
March 18, 2022 03:10
-
-
Save ljm42/fbf73bf4d3a9a7322f2466ae48c0e75b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Copyright 2017, ljm42 | |
# | |
# This program is free software; you can redistribute it and/or | |
# modify it under the terms of the GNU General Public License version 2, | |
# as published by the Free Software Foundation. | |
# | |
# The above copyright notice and this permission notice shall be included in | |
# all copies or substantial portions of the Software. | |
# | |
# the latest version of this script can be found here: | |
# https://gist.github.com/ljm42/fbf73bf4d3a9a7322f2466ae48c0e75b | |
VERSION=0.7 | |
###################################### | |
# REQUIREMENTS BEFORE INSTALLING | |
###################################### | |
# | |
# This script will watch for changes to your LetsEncrypt certificates and | |
# copy them to the unRAID certificate directory, automatically keeping unRAID current. | |
# | |
# This script will attempt to validate the certs before restarting nginx. If there is a problem, | |
# you will need to delete/replace the files in /boot/config/ssl/certs and reboot. | |
# | |
# Requirements (yeah, there are a lot): | |
# - You must be running unRAID 6.4.0-rc3+ with SSL enabled in the unRAID GUI | |
# - You should install the User Scripts plugin | |
# - You must have the LSIO LetsEncrypt docker installed and working for your domain | |
# (referred to as "mydomain.com" here) | |
# - Note: to prevent a conflict with port 443, the LetsEncrypt docker either needs to be | |
# on its own IP or unRAID should be on a custom port | |
# - The url you want to use to access your server must be added as a subdomain | |
# in LetsEncrypt (i.e. add "tower" as a subdomain of "mydomain.com" to get "tower.mydomain.com") | |
# - External to your network, that url ("tower.mydomain.com") should resolve to your router via DDNS | |
# and port 443 should be forwarded from the router to port 443 on your LetsEncrypt IP | |
# (LetsEncrypt will not issue the cert unless it can reach the IP address) | |
# - Internal to your network, that url should resolve to your unRAID server (i.e. 192.168.1.50) | |
# You might do this by adding "tower.mydomain.com -> 192.168.1.50" to your router and using | |
# your router for DNS on your network. | |
# Or you could distribute hosts files that contain this line (don't include the pound sign): | |
# 192.168.1.50 tower.mydomain.com | |
###################################### | |
# CONFIGURATION | |
###################################### | |
# Set the path to your LSIO Let's Encrypt key folder. | |
# This folder should contain your privkey.pem and fullchain.pem files | |
LE_CERT_PATH="/mnt/user/appdata/letsencrypt/keys/letsencrypt" | |
# In the User Scripts plugin, add a new script named "copy_le_certs" and paste in the | |
# contents of this script. Set the schedule to disabled. | |
# Then add another new script named "copy_le_certs_launcher" and paste the following | |
# into the script area (remove the first pound sign and leading spaces from each line) | |
# #!/bin/bash | |
# echo "/boot/config/plugins/user.scripts/scripts/copy_le_certs/script" | at NOW -M > /dev/null 2>&1 | |
# Schedule the launcher script to run at array start | |
###################################### | |
# END CONFIGURATION | |
###################################### | |
###################################### | |
# Begin script | |
###################################### | |
###################################### | |
# Setup environment | |
###################################### | |
# Setup variables for logger and echo. Thanks WeeboTech! | |
# https://forums.lime-technology.com/topic/37535-how-to-have-script-log-messages-to-unraidss-syslog/#comment-361182 | |
#P=${0##*/} # basename of program | |
#R=${0%%/$P} # dirname of program | |
#P=${P%.*} # strip off after last . character | |
# The above variables don't work when executed by the User Scripts plugin. Just set it manually: | |
P="copy_le_certs" | |
# logger -t${P}[$$] "message" | |
# echo "${P}[$$] message" | |
UN_SERVER_NAME=${HOSTNAME} | |
UN_CERT_PATH="/boot/config/ssl/certs" | |
KEY_SOURCE="${LE_CERT_PATH}/privkey.pem" | |
KEY_DEST="${UN_CERT_PATH}/${UN_SERVER_NAME}_unraid_key.pem" | |
CERT_SOURCE="${LE_CERT_PATH}/fullchain.pem" | |
CERT_DEST="${UN_CERT_PATH}/${UN_SERVER_NAME}_unraid_cert.pem" | |
CHANGED=0 | |
###################################### | |
# Ensure multiple copies of the script do not run at the same time | |
###################################### | |
# http://mywiki.wooledge.org/BashFAQ/045 | |
exec 9>/tmp/${P}.lck | |
if ! flock -n 9 ; then | |
echo "${P}[$$] another instance is already running. If you are sure this is wrong, delete '/tmp/${P}.lck'"; | |
logger -t${P}[$$] "another instance is already running. If you are sure this is wrong, delete '/tmp/${P}.lck'"; | |
ps -ef | grep "${P}" | |
exit 1 | |
fi | |
# this now runs under the lock until 9 is closed (it will be closed automatically when the script ends) | |
###################################### | |
# Ensure variables set properly and files exist | |
###################################### | |
# Make sure source directory and files exist | |
if [[ ! -d "${LE_CERT_PATH}" && ! -x "${LE_CERT_PATH}" ]]; then | |
echo "${P}[$$] error: ${LE_CERT_PATH} does not exist. exiting" | |
logger -t${P}[$$] "ERROR: source directory does not exist, unable to start monitoring" | |
exit 1 | |
fi | |
if [[ ! -e "${KEY_SOURCE}" ]]; then | |
echo "${P}[$$] error: ${KEY_SOURCE} does not exist. exiting" | |
logger -t${P}[$$] "ERROR: source key does not exist, unable to start monitoring" | |
exit 1 | |
fi | |
if [[ ! -e "${CERT_SOURCE}" ]]; then | |
echo "${P}[$$] error: ${CERT_SOURCE} does not exist. exiting" | |
logger -t${P}[$$] "ERROR: source cert does not exist, unable to start monitoring" | |
exit 1 | |
fi | |
# Make sure destination directory exists | |
if [[ ! -d "${UN_CERT_PATH}" && ! -x "${UN_CERT_PATH}" ]]; then | |
mkdir -p ${UN_CERT_PATH} | |
if [[ ! -d "${UN_CERT_PATH}" && ! -x "${UN_CERT_PATH}" ]]; then | |
echo "${P}[$$] error: unable to create dest path ${UN_CERT_PATH}. exiting" | |
logger -t${P}[$$] "ERROR: unable to create dest path, unable to start monitoring" | |
exit 1 | |
fi | |
fi | |
# destination files have to exist or diff will fail | |
if [[ ! -e "${KEY_DEST}" ]]; then | |
cp ${KEY_SOURCE} ${KEY_DEST} | |
CHANGED=1 | |
fi | |
if [[ ! -e "${CERT_DEST}" ]]; then | |
cp ${CERT_SOURCE} ${CERT_DEST} | |
CHANGED=1 | |
fi | |
# compare source to destination without waiting for inotifywait, copy if needed | |
if ! diff ${KEY_SOURCE} ${KEY_DEST} >/dev/null ; then | |
cp ${KEY_SOURCE} ${KEY_DEST} | |
CHANGED=1 | |
fi | |
if ! diff ${CERT_SOURCE} ${CERT_DEST} >/dev/null ; then | |
cp ${CERT_SOURCE} ${CERT_DEST} | |
CHANGED=1 | |
fi | |
if [ "${CHANGED}" = "1" ]; then | |
# do not run nginx commands if they don't exist (i.e. running script on unRAID < 6.4 in prep for upgrade) | |
if [ -e "/etc/rc.d/rc.nginx" ]; then | |
/etc/rc.d/rc.nginx check | |
if [ $? -eq 0 ]; then | |
/etc/rc.d/rc.nginx reload | |
logger -t${P}[$$] "New LetsEncrypt certificates installed in unRAID gui" | |
/usr/local/emhttp/webGui/scripts/notify -e "unRAID Server Notice" -s "LetsEncrypt" -d "New LetsEncrypt certificates installed in unRAID gui" -i "normal" | |
else | |
logger -t${P}[$$] "New LetsEncrypt certificates are invalid. Resolve before rebooting." | |
/usr/local/emhttp/webGui/scripts/notify -e "unRAID Server Notice" -s "LetsEncrypt" -d "New LetsEncrypt certificates are invalid. Resolve before rebooting." -i "alert" | |
fi | |
else | |
logger -t${P}[$$] "New LetsEncrypt certificates installed in unRAID gui" | |
fi | |
CHANGED=0 | |
fi | |
###################################### | |
# Watch for changes using inotifywait | |
###################################### | |
logger -t${P}[$$] "now watching for changes to certs" | |
# in order to break out of inotifywait loop when array unmounts, need this while loop syntax: | |
# https://unix.stackexchange.com/questions/166546/bash-cannot-break-out-of-piped-while-read-loop-process-substitution-works | |
while read EVENT; do | |
# logger -t${P}[$$] "event - '${EVENT}'" | |
# if array is stopped, exit | |
if [ "${EVENT}" = "UNMOUNT" ]; then | |
logger -t${P}[$$] "Array unmounted, exiting" | |
break | |
fi | |
# just to be safe, ensure the source files still exist before copying | |
if [[ ! -e "${KEY_SOURCE}" || ! -e "${CERT_SOURCE}" ]]; then | |
logger -t${P}[$$] "LE certificates are missing, won't install" | |
continue | |
fi | |
# compare source to destination, copy if needed | |
if ! diff ${KEY_SOURCE} ${KEY_DEST} >/dev/null ; then | |
cp ${KEY_SOURCE} ${KEY_DEST} | |
CHANGED=1 | |
fi | |
if ! diff ${CERT_SOURCE} ${CERT_DEST} >/dev/null ; then | |
cp ${CERT_SOURCE} ${CERT_DEST} | |
CHANGED=1 | |
fi | |
if [ "${CHANGED}" = "1" ]; then | |
# do not run nginx commands if they don't exist (i.e. running script on unRAID < 6.4 in prep for upgrade) | |
if [ -e "/etc/rc.d/rc.nginx" ]; then | |
/etc/rc.d/rc.nginx check | |
if [ $? -eq 0 ]; then | |
/etc/rc.d/rc.nginx reload | |
logger -t${P}[$$] "New LetsEncrypt certificates installed in unRAID gui" | |
/usr/local/emhttp/webGui/scripts/notify -e "unRAID Server Notice" -s "LetsEncrypt" -d "New LetsEncrypt certificates installed in unRAID gui" -i "normal" | |
else | |
logger -t${P}[$$] "New LetsEncrypt certificates are invalid. Resolve before rebooting." | |
/usr/local/emhttp/webGui/scripts/notify -e "unRAID Server Notice" -s "LetsEncrypt" -d "New LetsEncrypt certificates are invalid. Resolve before rebooting." -i "alert" | |
fi | |
else | |
logger -t${P}[$$] "New LetsEncrypt certificates installed in unRAID gui" | |
fi | |
CHANGED=0 | |
#else | |
# logger -t${P}[$$] "there was an ${EVENT} event, but we don't care" | |
fi | |
done < <(inotifywait -q --monitor --event modify --event move --event create --event delete --event unmount --format "%e" ${KEY_SOURCE} ${CERT_SOURCE}) | |
# depending on how the script is exited, this message may not be logged | |
logger -t${P}[$$] "exiting script, no longer monitoring for changes" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment