Site icon David Ramsden

A Guide to Using Let’s Encrypt

Up until a few moments ago, I was using CAcert for all my certificate needs. A free service offering SSL/TLS certificates. The only issue with CAcert is that their Root Certificate is not included in all mainstream Operating Systems or browsers, meaning users will get a certificate error unless they choose to install the Root Certificate.

But now Let’s Encrypt is on the scene. A free, open and automated certificate authority that is trusted and should work right off the bat in most modern Operating Systems and browsers.

And in the modern world encryption (and trust) is important and needed.

Here’s a quick guide to using Let’s Encrypt (LE). I’m using Debian with Apache, Dovecot and Postfix.

First download the official LE client from GitHub by cloning the repository. You’ll want to run the LE client as a user who can gain root via sudo:

$ git clone https://github.com/letsencrypt/letsencrypt
$ cd letsencrypt
$ ./letsencrypt-auto --help

The LE client will build itself, pulling down any required dependancies and configure itself. The build is self contained in $HOME/.local/share/letsencrypt.

If you’re running grsecurity and get a Segmentation Fault, you need to use paxctl to fix the python binary. Whenever letsencrypt-auto is run it’ll self update so you may need to run paxctl often:

$ sudo paxctl -cE $HOME/.local/share/letsencrypt/bin/python

Now the LE client is installed, you’re ready to start creating certificates. Normally when you purchase a certificate there are (or should be) several background checks that the issuer performs and LE is no different apart from it’s all automated using something called ACME (Automatic Certificate Management Environment). This is essentially a two-factor authentication mechanism. ACME sends a HTTP request to the Common Name (CN) and if used the Subject Alternative names (SAN) in the certificate and requests a unique file with unique content. It’s two-factor because a) you need access to DNS to configure the records for the CN and SANs in the certificate request and b) you need access to the machine the DNS records are pointing at to get the ACME challenge/response files on to. This stops people from requesting certificates for stuff they don’t own.

But here’s the problem. This works great when requesting certificates for websites because you’ve got a web server running. Not so great for a mail server which may not be running a web server on the same box. If you’re in this situation you may have to temporarily stand up a web server on the mail server for ACME. But if your mail server is on the same box as your web server, you can use the following trick (specific to Apache but can be adapted easily for nginx).

You’ve probably got a default vhost. One that specifies the ServerName as _default_. This matches any other request where no vhost is defined. You’ve probably got this to redirect to your main site. For example:

<VirtualHost *:80>
        ServerName _default_
        RedirectMatch permanent (.*) https://www.mainsite.co.uk$1
</VirtualHost>

The problem if you’re trying to request a certificate for a mail server is that it’s not going to have a virtual server configured in your web server. Therefore when the ACME makes a HTTP request to http://smtp.domain.com/.well-known/acme-challenge, the verification is going to fail.

If you’re running Apache one workaround is to configure an Alias outside of any virtual hosts so it applies everywhere. Create /etc/apache/conf.d/letsencrypt-acme containing:

Alias /.well-known/acme-challenge/ /var/www/.well-known/acme-challenge/

And reload Apache.

Create a file in /var/www/.well-known/acme-challenge called test.txt with some text in it. Now when you visit http://smtp.domain.com/.well-known/acme-challenge/test.txt you shouldn’t get a 404 Not Found. Also note that if you’re using the Redirect directive in an existing virtual host (e.g. to redirect http://domain.com to http://www.domain.com), you should be using the RedirectMatch directive like so:

RedirectMatch permanent (.*) http://www.domain.com$1

ACME will follow redirect requests and the above ensures that any request to http://domain.com/.well-known/acme-challenge is redirected to http://www.domain.com/.well-known/acme-challenge, otherwise just using the standard Redirect directive will break things.

Why do this, though? Because it makes the following a lot easier.

As mentioned each CN or SAN has to be validated. By using the trick above you only need to tell the LE client one web root to use. Here’s the command that will request a certificate for www.domain.com with webmail.domain.com as a SAN:

$ ./letsencrypt-auto certonly --webroot -w /var/www -d www.domain.com -d webmail.domain.com

The ACME challenge/response gets written (temporarily) to /var/www/.well-known/acme-challenge. The ACME sends a HTTP request to http://www.domain.com/.well-known/acme-challenge and http://webmail.domain.com/.well-known/acme-challenge and both get served from /var/www/.well-known/acme-challenge.

If everything worked you should now have a public and private key in /etc/letsencrypt/live/www.domain.com as well as a full chain certificate.

When it comes to renewing certificates, simply run:

$ ./letsencrypt-auto renew

Now there’s no excuse to ever use self-signed certificates!