Setting up a Let's Encrypt SSL certificate

2017-10-02 by Senko Rašić

Today there's a gradual shift from using unencrypted HTTP for serving web sites and apps, to using HTTPS everywhere. Historically this hasn't been possible because most organizations giving out SSL certificates (CA's) charged for it. This is changing with Let's Encrypt, an open, popular and free SSL certificate authority (CA) that enables anyone to set up SSL/TLS on their site with no extra cost.

At GoodCode we're using Let's Encrypt for securing nearly all of the web apps and sites we work. Instead of using the official client, we've found out that a third party acmetool client is easier to set up and works like a charm.

Since we also mostly use nginx, here's how to set up HTTPS for your nginx site using acmetool:

Installation

Acmetool client is written in Go, producing a standalone binary with no dependencies that can just be dropped in the system, making it easy to install.

You can install the package via package manager, as acmetool is packaged for all the major operating systems (including various popular Linux distributions). Alternatively, download the tar.gz archive matching your hardware and operating system, extract it, copy the acmetool binary to /usr/local/bin and you're good to go.

The README file has detailed instructions for available download options.

ACME challenges

To be able to request a certificate, acmetool needs to be able to prove it is running on the server name for which the certificate is requested. The Let's Encrypt CA gives the client a challenge (a file to be signed by the client). The client cryptographically signs the challenge and puts the response in a specific location in the website so that Let's Encrpyt can find it. Once Let's Encrypt confirms the response is a valid one, it agrees to issue the SSL certificate for the site. Here's a more detailed description of how Let's Encrypt works.

To allow for this, we must setup nginx to serve the files acmetool creates under a specific URI: /.well-known/acme-challenge. Importantly, these files need to be served under HTTP, so even if you want to have HTTPS-only site, you'll still need these to be available via HTTP.

We can do this by adding a location block inside the server configuration:

server {
    listen 80 default;

    ...

    # Add this location block
    location /.well-known/acme-challenge {
        alias /var/lib/acme/www;
    }
}

This tells nginx to serve /.well-known/acme-challenge requests from /var/lib/acme/www directory, which we'll create in the next step. Test and reload the nginx configuration:

nginx -t
nginx -s reload

acmetool quickstart

The acmetool client has a quickstart command to automate the setup process. Start it with:

acmetool start

It'll ask a few questions:

  • to confirm terms of use,
  • whether to use live or staging Let's Encrypt servers — you always want to use the live servers unless you are developing your own Let's Encrypt client and want to test it,
  • which method of publishing challenge responses you want to use — the method described here is webroot so that's what you should choose,
  • location of the webroot directory — use /var/lib/acme/www here,
  • whether you want to install a cron script to automatically renew certificates — yes, you do,
  • your email address, so you receive notificatins if your certificate wasn't renewed on time.

This setup will create /var/lib/acme directory and populate it with various configuration and state files used by acmetool. We need to add our www directory manually:

mkdir /var/lib/acme/www

Request certificates

To request the certificates, use the want command in acmetool (use your site name instead of example.com here):

acmetool want example.com www.example.com

You can ask for as many certificates as you like. The only limit is that at the time of this writing, Let's Encrypt doesn't support wildcard certificates, ie. you can't ask for *.example.com.

The client will immediately try to obtain the certificates. If it shows no output, then everything went well. If there are problems (eg. your site isn't reachable under that name, or you've set up nginx incorrectly), it'll complain loudly in the error messages.

You can verify the status of all the requested certificates using the status command:

acmetool status

And you can stop using a certificate (or cancel a request) with unwant (note that this doesn't revoke the certificate, only that acmetool stops caring about it):

acmetool unwant

Renewals

Acmetool can be run from time to time to check every certificate that it wants is installed. Actually, this is exactly what the cron script it asked you in the setup about does — it runs acmetool once a day to check everyhing's fine. This is because Let's Encrypt certificates have a short lifetime (3 months) and are meant to be renewed automatically.

Starting acmetool with no specific command just tells it to run through all the certificates it wants and renew them (or request them, if it previously failed to do so due to an error):

acmetool

Setting up SSL in nginx

The last piece of the puzzle is telling nginx to use HTTPS.

server {
    # Listen on the HTTPS port
    listen 443;

    # Use your server name(s) here
    server_name example.com www.example.com;

    # Enable SSL and set up certificate
    ssl on;

    # acmetool will put the files in the directory called after the domain name
    ssl_certificate /var/lib/acme/live/example.com/fullchain;
    ssl_certificate_key /var/lib/acme/live/example.com/privkey;


    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305:ECDHE+AES128:RSA+AES128:ECDHE+AES256:RSA+AES256:ECDHE+3DES';
    ssl_prefer_server_ciphers on;

    # The usual web server configuration goes here
    ...
}

Check the configuration with nginx -t. If there are problems finding the certificates or the related private key, nginx will complain. Otherwise, restart the server with nginx -s reload.

Note: the above example uses ssl protocols and ciphers that are considered secure as the time of this writing, but covering this subject is outside the scope of this article. You should check your site setup from time to time (eg using Qualys SSL Labs testing tool) to see if you need to change or upgrade anything.

HTTPS-only site

If you'd like to force clients to only use HTTPS to connect to your site, you can remove everything except the ACME challenge location block, and a redirect block in your HTTP server definiition:

server {
    listen 80 default;

    # Allow Let's Encrypt CA to access challenge responses via HTTP
    location /.well-known/acme-challenge {
        alias /var/lib/acme/www;
    }

    # Redirect everyone else to HTTPS version
    location / {
        rewrite ^(/.*) https://example.com$1 permanent;
    }
}
Author
Senko Rašić
We’re small, experienced and passionate team of web developers, doing custom app development and web consulting.