Skip to content

Instantly share code, notes, and snippets.

@philcryer
Created February 26, 2016 20:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save philcryer/9663b2b24a6cebc51fc2 to your computer and use it in GitHub Desktop.
Save philcryer/9663b2b24a6cebc51fc2 to your computer and use it in GitHub Desktop.
auto renewal script for Let's Encrypt
#!/bin/bash
#
# this is going to be a rewrite of this:
# https://github.com/defsdoor/letsencrypt-autorenew/blob/master/get_certificates
# example file mycerts:
## EMAIL admin@example.com
## HOSTS www.example.com
## EMAIL admin@mail.example.com
## HOSTS mail.example.com
## imap.example.com pop3.example.com smtp.example.com
# would like to have this script work with new setups, still using the certonly setup - I don't want the webserver down
# while it's the cert(s) for the domains...
LEDIR=/opt/letsencrypt
CONF_FILE=/etc/letsencrypt/mycerts
LEROOT=/etc/letsencrypt/live
RENEW_DAYS_LEFT=8
function die {
echo "$*"
exit 1
}
function generate {
typeset EMAIL="$1"
typeset HOSTS="$2"
CMD=""
for H in $HOSTS
do
CMD="$CMD -d $H"
done
./letsencrypt-auto certonly --renew-by-default --agree-tos --webroot --email $EMAIL $CMD --webroot-path /var/www/content/letsencrypt
}
function check_same_hosts {
typeset CERT="$1"
typeset HOSTS="$2"
CERT_HOSTS="$(get_hosts_from_cert $CERT)"
SORTED_CERT_HOSTS="$(sort_hosts "$CERT_HOSTS")"
SORTED_HOSTS="$(sort_hosts "$HOSTS")"
if [[ "$SORTED_HOSTS" == "$SORTED_CERT_HOSTS" ]]
then
return 0
else
return 1
fi
}
function check_expiring_soon {
typeset CERT="$1"
EXPIRY_DATE=$(date -d "$(openssl x509 -in $CERTIFICATE -text | sed '/Not After/{s/^.*: //g;p};d')" '+%Y%m%d%H%M%S')
typeset RENEW_DATE=$(date -d "now +$RENEW_DAYS_LEFT days" '+%Y%m%d%H%M%S')
if [[ $EXPIRY_DATE < $RENEW_DATE ]]
then
return 1
else
return 0
fi
}
function sort_hosts {
typeset HOSTS="$1"
echo "$HOSTS" | sed -r 's/[[:blank:]]+/\n/g' | sort -u
}
function get_hosts_from_cert {
typeset CERT=$1
openssl x509 -in $CERT -text |
sed -e '/X509v3 Subject Alternative Name/,/DNS/!d;/X509v3 Subject/d;s/DNS:\([^, \n]*\)/\1/g;s/[[:blank:]]//g;s/,/ /g'
}
function check_update_required {
typeset EMAIL="$1"
typeset HOSTS="$2"
typeset -i UPDATE_REQUIRED=0
set $HOSTS
MAIN_HOST=$1
CERTIFICATE=$LEROOT/$MAIN_HOST/cert.pem
if [[ ! -d $LEROOT/$MAIN_HOST || ! -f $CERTIFICATE ]]
then
echo "Update required - certificate missing"
UPDATE_REQUIRED=1
else
check_same_hosts "$CERTIFICATE" "$HOSTS"
UPDATE_REQUIRED=$?
if ((UPDATE_REQUIRED==0))
then
check_expiring_soon $CERTIFICATE
UPDATE_REQUIRED=$?
if ((UPDATE_REQUIRED==1))
then
echo "Update required - certificate expiring soon ($EXPIRY_DATE)"
else
echo "$MAIN_HOST - up to date"
fi
else
DIFFERENCE=$(diff <(echo "$SORTED_HOSTS") <(echo "$SORTED_CERT_HOSTS") | egrep "^[<>]" )
echo "Update required - hosts differ $DIFFERENCE"
fi
fi
return $UPDATE_REQUIRED
}
function process {
typeset EMAIL="$1"
typeset HOSTS=$2
if ! check_update_required "$EMAIL" "$HOSTS"
then
generate "$EMAIL" "$HOSTS"
fi
}
function read_conf {
while read LINE
do
[[ -z "$LINE" ]] && continue
[[ "$LINE" = \#* ]] && continue
set $LINE
case "$1" in
"EMAIL")
[[ ! -z "$HOSTS" ]] && process "$EMAIL" "$HOSTS"
HOSTS=""
EMAIL=$2 ;;
"HOSTS")
[[ ! -z "$HOSTS" ]] && process "$EMAIL" "$HOSTS"
shift
HOSTS="$*" ;;
*) HOSTS="$HOSTS $*" ;;
esac
done < $CONF_FILE
process "$EMAIL" "$HOSTS"
}
echo "Entering $LEDIR"
cd $LEDIR || die "Could not change directory into $DIR"
echo "Updating from git"
git pull || die "Git pull returned unexpectedly"
read_conf
exit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment