Switching SSL certs to letsencrypt

Last night's StartSSL outage - including the OCSP servers - was the last straw. I decided to give letsencrypt a go. I won't miss StartSSL - it was always painful to deal with them and having them permanently blacklist FreeBSD.org as a rogue site always bugged me.

I didn't want to use the security/py-letsencrypt tool due to the footprint. However, security/letsencrypt.sh was Just Right(TM).

It is incredibly easy to use. Here's a sample on FreeBSD:

# pkg install letsencrypt.sh

You need a small nginx.conf hook for the domain validation to work:

location /.well-known/acme-challenge {
  alias /usr/local/etc/letsencrypt.sh/.acme-challenges;
}

This must be in the port 80 http server block for the domain you want a certificate for. You can use the same one for all sites.

Now to get a cert:

# cd /usr/local/etc/letsencrypt.sh
# touch config.sh
# echo "blog.crashed.org" > domains.txt
# letsencrypt.sh --cron

+ Generating account key...
+ Registering account key with letsencrypt...
Processing blog.crashed.org
 + Signing domains...
 + Creating new directory /usr/local/etc/letsencrypt.sh/certs/blog.crashed.org ...
 + Generating private key...
 + Generating signing request...
 + Requesting challenge for blog.crashed.org...
 + Responding to challenge for blog.crashed.org...
 + Challenge is valid!
 + Requesting certificate...
 + Checking certificate...
 + Done!
 + Creating fullchain.pem...
 + Done!

That's it! 10 seconds! And yes, there is just one minimal line of configuration that is absolutely required. (See config.sh.sample for the full details)

For the nginx side, you use the certificates with this (in addition to the rest of your ssl setup):

ssl_certificate  /usr/local/etc/letsencrypt.sh/certs/blog.crashed.
org/fullchain.pem;
ssl_certificate_key  /usr/local/etc/letsencrypt.sh/certs/blog.crashed.
org/privkey.pem;

These are "only" 90 day certificates so it is fairly important to to renew them. It turns out that's easy too. Notice the "--cron" switch above? Once a day I run:

PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin
55 16 * * * /usr/local/bin/letsencrypt.sh --cron; sleep 30; service nginx reload

(Naturally, pick different times!)

Once it's got less than 30 days to go, it generates a new certificate and nginx is reloaded to use it.

I was looking for a trivial, quick-fix for the experiment. I'll use the proper hooks mechanism to avoid unnecessary reloads, but for now this will do just fine.

While I was there, I added some other magic to to update and publish the TLSA fingerprints via DNSSEC but that's outside the scope of this article.

This stuff is REALLY easy. There's no excuse now.

Contact information