Skip to content

Instantly share code, notes, and snippets.

@mschmitt
Last active April 13, 2016 11:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mschmitt/e38be63bf3264c339f42b648ea8920ed to your computer and use it in GitHub Desktop.
Save mschmitt/e38be63bf3264c339f42b648ea8920ed to your computer and use it in GitHub Desktop.
#!/bin/bash
# A wrapper for acme-tiny to do automatic cert rollovers.
#
# Certs/Keys/Requests are stored as
# /opt/letsencrypt/domains/*/{crt,key,csr}.pem
#
# .well-known/acme-challenge directories in document roots
# are writable for the user "letsencrypt" who runs this script
# and symlinked as
# /opt/letsencrypt/domains/*/acme-challenge
#
# /etc/sudoers:
# letsencrypt ALL=(root)NOPASSWD:/usr/sbin/apachectl graceful
#
# While I'm at it, this is how to make the challengedir visible
# in a fully reverse-proxied virtual host:
# ProxyPass /.well-known/acme-challenge/ !
# ProxyPass / http://127.0.0.1:9001/
# ProxyPassReverse / http://127.0.0.1:9001/
#
# This was written in March 2016 and so far has never
# productively renewed a single cert. Good luck!
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
# OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
ACMETINY=/opt/letsencrypt/src/acme-tiny/acme_tiny.py
ACCOUNTKEY=/opt/letsencrypt/etc/account.key
DOMAINBASE=/opt/letsencrypt/domains/
RENEWALS_DONE=0
for DOMAIN in $(ls $DOMAINBASE)
do
echo "------- $DOMAIN:"
# Runtime environment for this domain
DOMAINDIR=$DOMAINBASE/$DOMAIN/
CSR=$DOMAINDIR/csr.pem
CRT=$DOMAINDIR/crt.pem
CHALLENGEDIR=$DOMAINDIR/acme-challenge/
# Ensure challenge directory is in place and writable
if [ ! -w $CHALLENGEDIR ]
then
echo "$CHALLENGEDIR not writable. Skipping $DOMAIN"
continue
fi
# Skip rollover if cert has more than 30 days validity left.
THIRTYDAYS=$((60*60*24*30)) # seconds
openssl x509 -in $CRT -checkend $THIRTYDAYS > /dev/null
if [ $? -eq 0 ]
then
echo "More than 30 days left for $DOMAIN. Skipping."
continue
fi
# Do renewal
python $ACMETINY --account-key $ACCOUNTKEY \
--csr $CSR \
--acme-dir $CHALLENGEDIR \
> $CRT.new
# Check new certificate for plausibility
openssl x509 -subject -noout -in $CRT.new | grep -q $DOMAIN
if [ $? -eq 0 ]
then
echo "Got new cert for $DOMAIN."
cp $CRT $CRT.bak
mv $CRT.new $CRT
else
echo "No usable cert for $DOMAIN received. Skipping."
continue
fi
# Output cert info to see what we got.
openssl x509 -issuer -subject -startdate -noout -in $CRT
openssl x509 -text -noout -in $CRT | grep DNS
# Keep track of whether webserver will need reload
let RENEWALS_DONE++
done
if [ $RENEWALS_DONE -gt 0 ]
then
echo "$RENEWALS_DONE renewals succeeded. Reloading webserver."
# Reload web server
sudo /usr/sbin/apachectl graceful
else
echo "No certificates were renewed."
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment