LetsEncrypt


Update Dec 2017
While these instructions will likely still work there are easier ways of running a secure site, use Caddy

Free, automated SSL with LetsEncrypt

LetsEncrypt documentation aka Certbot.

Installation

# apt-get install git
# mkdir /root/letsencrypt
# git clone https://github.com/letsencrypt/letsencrypt /root/letsencrypt
# cd /root/letsencrypt

Get a certificate

We prefer to configure virtual hosts manually, all letscnerypt commands will therefore only provision or renew a certificate - there are alternatives.

Note:
* DNS for your domain must be configured correctly for www and non-www access.
* LetsEncrypt will attempt to create and write to a .well-known directory in your document root, web service must have write access.

First time letsencrypt will install all dependencies (if any are missing).
It will also ask for an email address to be used for urgent notices and key recovery, you will also need to agree to the terms.

To provision a certificate including sub-domains just include multiple -d options on the command line.
Remember, www is just a sub-domain and needs to be explicitly specified.

~/letsencrypt# ./letsencrypt-auto certonly --webroot -w /var/www/vhosts/whatdidilearn.today/ -d whatdidilearn.today -d www.whatdidilearn.today
Bootstrapping dependencies for Debian-based OSes...
...
Reading package lists... Done
Building dependency tree
Reading state information... Done
ca-certificates is already the newest version.
ca-certificates set to manually installed.
gcc is already the newest version.
gcc set to manually installed.
python is already the newest version.
python-dev is already the newest version.
The following extra packages will be installed:
  python-chardet-whl python-colorama-whl python-distlib-whl python-html5lib-whl python-pip-whl python-requests-whl python-setuptools-whl python-six-whl python-urllib3-whl python3-pkg-resources
  python3-virtualenv
Suggested packages:
  augeas-doc augeas-tools python3-setuptools
Recommended packages:
  libssl-doc
The following NEW packages will be installed:
  augeas-lenses dialog libaugeas0 libffi-dev libssl-dev python-chardet-whl python-colorama-whl python-distlib-whl python-html5lib-whl python-pip-whl python-requests-whl python-setuptools-whl
  python-six-whl python-urllib3-whl python-virtualenv python3-pkg-resources python3-virtualenv virtualenv
...

If your certificate was provisioned successfully you will see a message similar to:

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at /etc
   /letsencrypt/live/whatdidilearn.today/fullchain.pem.
...

A message similar to the following means your certificate request failed - in this case because the www sub-domain was not configured correctly in DNS.
If you get a failure, fix the cause and then just re-run the letsencrypt command.

IMPORTANT NOTES:
 - If you lose your account credentials, you can recover through
   e-mails sent to info@bespoke-it.solutions.
 - The following errors were reported by the server:

   Domain: www.whatdidilearn.today
   Type:   unauthorized
   Detail: Invalid response from
   http://www.whatdidilearn.today/.well-known/acme-challenge/...

Check expiry date of a certificate

# openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -noout -enddate
notAfter=Jul  5 14:03:00 2016 GMT

Renew a certificate

Watch out for contents of .htaccess, expecially if your site is running Drupal.
If running Drupal there is a patch for .htaccess that allows access to .well-known directory.

While it is nice to auto renew certificates (via cron) - is it much of a hardship just to renew the certificate when the reminder email from LetsEncrypt arrives?

That said, here is the renewal script I use which only go out and attempt a renewal if the certificate actually needs it. i.e. there are less than 10 days to go before expiry.

#!/bin/bash

# Renew LetsEncrypt certificates.
# Based on a script on Pastebin - but I don't have a record of the URL or original author.

# Usage: sudo /home/itsupport/bin/renew-certificates.sh

certRenewed=0

for f in /etc/letsencrypt/renewal/*.conf; do

domain="${f##*/}"
domain=${domain%.conf}

echo "[INFO]: Domain: ${domain}"

certFile="/etc/letsencrypt/live/${domain}/fullchain.pem"
certDate=$(openssl x509 -in ${certFile} -text -noout|sed -e '/Not After/!d ;s/.* : //g')

expiry=$(date -d "${certDate}" +%s)
datenow=$(date -d "now" +%s)
expiryDays=$((( $expiry - $datenow ) / 86400 ))

echo "[INFO]: Expires on: ${certDate}"
echo "[INFO]: In days   : ${expiryDays}"

if [ "$expiryDays" -gt 10 ] ; then
        echo "[INFO]: ... the certificate is up to date"
else
        echo "[WARN]: ... expires in < 10 days, starting renewal request ..."
        domainList=$( openssl x509 -in /etc/letsencrypt/live/${domain}/cert.pem -text -noout | grep DNS | sed "s/DNS://g" | sed 's/ //g' )
        echo "[WARN]: ... for domain(s): ${domainList}"
        vhostDir="/var/www/vhosts/${domain}/"
        echo "[WARN]: ... in VHost Dir : ${vhostDir}"
        /root/letsencrypt/letsencrypt-auto certonly --force-renewal --webroot -w ${vhostDir} -d ${domainList}
        if [ $? -eq 0 ] ; then
                echo "[WARN]: ... Renewal process finished"
                certRenewed=1
        else
                echo "[ERROR]: ... Certificate renewal failed!"
        fi
fi
done

if [ $certRenewed -eq 1 ] ; then
        echo "[INFO]: One or more certificates renewed, reloading Apache ..."
#       service apache2 reload
        # Experience says that a reload or restart is not enough to get browsers to register the cert change
        # Stop Start does though
        service apache2 stop
        service apache2 start
fi

Remove all trace of LetsEncrypt for a domain

Based on this forum thread.

domain=vps.example.org.uk
rm -rf /etc/letsencrypt/live/${domain}/
rm -rf /etc/letsencrypt/archive/${domain}/
rm -rf /etc/letsencrypt/renewal/${domain}.conf
# Remove well-know dir from vhost - your path may be different.
rm -rf /var/www/vhosts/${domain}/.well-known
Comment on this article using form below. Requires email login only for authentication. HTML forbidden, Markdown only.