Last active
November 15, 2022 00:10
-
-
Save andygock/8278c7c3b929d92cc8e67bd6286826d9 to your computer and use it in GitHub Desktop.
This file contains 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 | |
# | |
# renew-letsencrypt-certificates.sh DOMAIN [EMAIL] | |
# | |
# Copy Let's Encrypt SSL certs from a remote public facing web server to local filesystem | |
# Look for changes, if any change, restarts the web service | |
# Useful for using Let's Encrypt with local internal servers, with custom DNS. | |
# Working "mail" command needed for email alerts | |
# | |
if [ -z $1 ]; then | |
echo "Syntax error, use:" | |
echo " renew-letsencrypt-certificates.sh DOMAIN [EMAIL]" | |
exit 1 | |
fi | |
# SSH options to remote VPS, e.g different port | |
SSH_OPTS="-p 22" | |
SCP_OPTS="-P 22" | |
DOMAIN=$1 | |
# send email message here when a renewal occurs, or on error | |
EMAIL=$2 | |
# Get SOA DNS server | |
DNS=$(dig soa $DOMAIN | grep -v ^\; | grep SOA | sed -r 's/^(.*)SOA\t//' | cut -d " " -f 1 | sed -r 's/\.$//') | |
# Get remote public facing web server IP address | |
IP_REMOTE=$(dig @$DNS +short $DOMAIN A) | |
if [[ -z $IP_REMOTE ]]; then | |
echo "Can not determine remote IP for $DOMAIN" | |
exit 1 | |
fi | |
# .pem certificates will be saved here. You must have write permissions here | |
# and your Apache or nginx .conf files should refer to this path | |
# Actual cert files will be in a subdir e.g $CERT_PATH/$DOMAIN/*.pem | |
CERT_PATH=/etc/letsencrypt/live | |
CERT_PATH_DOMAIN="$CERT_PATH/$DOMAIN" | |
# e.g httpd, nginx, refer to restart_www() for methods of restart or reload | |
WEB_SERVER=nginx | |
DIR=$(dirname $0) | |
CERT_TARBALL_REMOTE=/root/certs_${DOMAIN}.tar.gz | |
CERT_TARBALL_LOCAL=/root/certs_${DOMAIN}.tar.gz | |
# this flag is used by this script, leave this alone! | |
certs_updated=0 | |
restart_www () { | |
if [[ "$WEB_SERVER" == "nginx" ]]; then | |
nginx -s reload | |
else | |
systemctl restart $WEB_SERVER | |
fi | |
} | |
# return 0 if renewed, 1 if not renewed for whatever reason | |
refresh_certificates () { | |
# create tarball on public server of current letsencrypt certs for desired domain | |
echo "Create \"$CERT_TARBALL_REMOTE\" on remote..." | |
ssh $SSH_OPTS root@$IP_REMOTE "rm -f \"$CERT_TARBALL_REMOTE\"; tar -zchf \"$CERT_TARBALL_REMOTE\" -C \"$CERT_PATH\" $DOMAIN" | |
# copy tarball from public to internal server, remove existing file if it iexsts | |
[[ -f "$CERT_TARBALL_LOCAL" ]] && rm -f "$CERT_TARBALL_LOCAL" | |
echo "Copy remote \"$CERT_TARBALL_REMOTE\" to local \"$CERT_TARBALL_LOCAL\"..." | |
scp $SCP_OPTS root@$IP_REMOTE:"$CERT_TARBALL_REMOTE" "$CERT_TARBALL_LOCAL" | |
# create cert path if we need to | |
[[ -d "$CERT_PATH_DOMAIN" ]] || mkdir -p "$CERT_PATH_DOMAIN" | |
# check local tarball is persent | |
if [[ ! -f "$CERT_TARBALL_LOCAL" ]]; then | |
echo "Error: Local \"$CERT_TARBALL_LOCAL\" is missing. The copy or write operation above has failed. Quitting" | |
exit 1 | |
fi | |
echo "Extracting certificates to local \"$CERT_PATH_DOMAIN\"..." | |
tar -zxvf "$CERT_TARBALL_REMOTE" -C "$CERT_PATH_DOMAIN" --strip-components=1 > /dev/null | |
echo "Delete remote \"$CERT_TARBALL_REMOTE\"..." | |
ssh $SSH_OPTS root@$IP_REMOTE "rm -f '$CERT_TARBALL_REMOTE'" | |
# Restart web server only if certs changed since last run of this script | |
# Although it's probably fine if we just restarted it each time anyway | |
# Create a CHECKSUMS file in $CERT_PATH_DOMAIN, verify against this in the future to detect changes | |
pushd . &> /dev/null | |
cd "$CERT_PATH_DOMAIN" | |
if [[ -f CHECKSUMS ]]; then | |
echo -n "Checking whether certificates have changed... " | |
sha256sum --status -c CHECKSUMS | |
if [[ $? -ne 0 ]]; then | |
# checksum is different, certificate has changed, restart web server and reclaculate checksums | |
echo "Change found. Certificates updated. Restarting or reloading $WEB_SERVER ..." | |
restart_www | |
sha256sum *.pem > CHECKSUMS | |
return 0 | |
else | |
# No update performed, certficates the same as previous | |
echo "Certificates not changed." | |
return 1 | |
fi | |
else | |
# no checksum performed yet | |
echo "Certificates updated. Restarting or reloading $WEB_SERVER ..." | |
restart_www | |
sha256sum *.pem > CHECKSUMS | |
return 0 | |
fi | |
popd > /dev/null | |
} | |
# | |
# Script starts here | |
# | |
# check cert stats by connecting to local web server | |
cert_stats () { | |
echo | openssl s_client -showcerts -connect $1:443 2> /dev/null | openssl x509 -noout -dates | |
} | |
# we need to copy those certs to this machine at regular machine | |
refresh_certificates | |
if [[ $? -eq 0 ]]; then | |
# updated, both cron and interactive mode | |
# restart web server | |
nginx -s reload | |
echo "SSL cert updated. New certificate validity dates:" | |
# get SSL cert stats | |
if [[ ! -z $EMAIL ]]; then | |
cert_stats $DOMAIN | mail -s "SSL cert updated" $EMAIL | |
fi | |
cert_stats $DOMAIN | |
elif [[ -t 0 ]]; then | |
# not updated - interactive mode | |
echo "SSL cert does not need updating. Current certificate validity dates:" | |
cert_stats $DOMAIN | |
fi | |
exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi ... great script ... May i use this as reference ?
I dont understand all of it though ... any reason why you did not want to use something like getssl ?