Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
#!/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
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 - if certificates are updated, then will invoke "service $WEB_SERVER restart"
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
service $WEB_SERVER restart
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 root@$IP_REMOTE "rm -f \"$CERT_TARBALL_REMOTE\"; tar -zchf \"$CERT_TARBALL_REMOTE\" -C \"$CERT_PATH\" $DOMAIN"
# copy tarball from public to internal server
echo "Copy remote \"$CERT_TARBALL_REMOTE\" to local \"$CERT_TARBALL_LOCAL\"..."
scp root@$IP_REMOTE:"$CERT_TARBALL_REMOTE" "$CERT_TARBALL_LOCAL" > /dev/null
# 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."
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 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
#
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
echo "SSL cert was updated. New certificate validity dates:"
if [[ ! -z $EMAIL ]]; then
cert_stats $DOMAIN | tee mail -s "SSL cert updated" $EMAIL
else
cert_stats $DOMAIN
fi
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
You can’t perform that action at this time.