Let’s Encrypt!

Traditionally, getting an SSL certificate isn’t easy or cheap. SSL, or more accurately, SSL’s successor, TLS, is the underlying technology that encrypts web traffic. You’ve seen this as the https scheme on a URL and the padlock in your browser to let you know you’re securely browsing a website.

To set this up for your website, you used to (and still do on some hosts) need a dedicated IP address for the website, a fair amount of money, and jump through of hoops with the certificate authority (CA) issuing the certificate. There was, also, a lot of back and forth needing a certificate signing request (CSR) to send to the CA, then installing the real certificate when it was issued.

Let’s Encrypt aims to change that. The goal is a fully automated process where someone could type in a command on a server, wait a few seconds, and have a certificate issued and installed on their system.

It’s been in development for a while now and I’m proud to say that my employer, Automattic, is a Silver sponsor of the project. Yesterday, the opened for a public beta period. So, of course, I gave it a spin.

This site has had a certificate for some time, but I never pulled the trigger on enabling HTTPS on any of my other domains. I opted to try this on, perhaps, my greatest domain— kraft.beer.

Let’s jump in and get some HTTPS going.

Some Caveats

Let’s Encrypt does not support wildcard certificates. While you can add an infinite number of domains (registration rate limits notwithstanding), you can not make a *.example.com certificate at this time.

Currently, they’re issuing 90-day certificates, whereas 1-year is the norm. This isn’t a problem except be sure to test the renewal process within the quarter versus within the year.

The automated process ships with an Apache installer (to both create the certificate and install it on the server). There is a Nginx plugin deemed too experimental to include in the automated package. I’m sure it’ll get in tip-top shape soon.

I’m on Nginx and since I’m a bit skittish on running something too experimental for beta on my server (unless I have a hand in making it), I did not try to use the Nginx plugin.

Lastly, since it only entered public beta yesterday, many, many things will change pretty quickly I would imagine. This guide may be outdated by the time you read it, if it wasn’t already by the time I clicked “Publish”. First-party documentation available directly from Let’s Encrypt.

One-Time Setup

Via the command line on your server, assuming Git is already installed:

git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt

Each time it runs, it’ll check and install any dependencies needed, and will ask you to sudo.

Not needed, but can help improve your setup is to create a Diffie-Hellman group.

openssl dhparam -out dhparams.pem 2048

Note the location of the file and/or move it to somewhere feasible for your setup. You strictly don’t need to create one unique to each site, so I’m including it as a one-time setup step.

Generating Certificates

I first created a certificate via the manual process, which entailed it spitting out a random string to save to a randomly-named file on the server for it to verify my control. This would also allow you to, for example, create a certificate from a different computer than the server itself. Handy if you are restricted from using ssh on your server, but can submit keys.

Much easier for Nginx sysadmins is the webroot method.

./letsencrypt-auto certonly --webroot -w /srv/www/html/ -d example.com -d www.example.com

That’s it. In the command, you’re asking only for certificate creation (not installation) via the webroot method. The -w flag is specifying your webroot where your files are served. This will allow the Let’s Encrypt client to install a file, which their servers will check to verify ownership. Lastly, you’ll add each domain that you want added to that specific certificate preceded with a -d flag.

According to their documentation, you can do one command for multiple roots, e.g.

./letsencrypt-auto certonly --webroot -w /srv/www/example.com/html/ -d example.com -d www.example.com -w /srv/www/example.org/html -d example.org -d www.example.org

When it is complete, it’ll return a message:


 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/example.com/fullchain.pem. Your cert will
   expire on 2016-03-03. To obtain a new version of the certificate in
   the future, simply run Let's Encrypt again.
 - If like Let's Encrypt, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
   Donating to EFF:                  https://eff.org/donate-le

Nginx Configuration

The final step is to actually install the certificates. You’d need to modify your Nginx configuration to listen on port 443, to use the right certificates, and to use the right ciphers.

You can use something like this:

server {
    server_name example.com www.example.com;
    listen *:443 ssl http2;
    listen [::]:443 ssl http2;
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_dhparam /srv/www/example.com/ssl/dhparam.pem;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

    add_header Strict-Transport-Security "max-age=31536000;";
    ssl_session_cache shared:SSL:20m;
    ssl_session_timeout 10m;
    ssl_prefer_server_ciphers on;
    ssl_ciphers 'ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5';

This will setup SSL using HTTP/2. If running a version of Nginx prior to 1.9.5, you can use spdy instead of http2 to use SPDY or omit it completely to use plain HTTP/1.1.

It’ll also setup HTTP_Strict_Transport_Security (HSTS), which sends headers when requesting your page telling browsers that they must use HTTPS and it must be a valid certificate. This will, in most modern browsers, in effect, force HTTPS. It’ll also disable the ability to ignore certificate warnings. Additionally, you can add includeSubDomains (e.g.
add_header Strict-Transport-Security "max-age=31536000; include Subdomains;";) to force HSTS on all subdomains. I didn’t include this in the example since Let’s Encrypt does not support wildcard certificates.

Also, note the max-age is 31536000 seconds, or 1 year. This means that the browser will remember that it should use HSTS and thus HTTPS for one year. If you opt to drop HTTPS support, you will need to remove this line and wait a year before disabling HTTPS support to ensure everyone can still access your site.

The rest are more advanced settings on what your server will support. This particular setup yields a “A+” grade on SSL Labs, currently.

Lastly, note that this config doesn’t touch port 80 or http traffic at all. You should, however you see fit, account for that. I have a separate server block redirecting all http traffic to the https version of the URL.

After that, reload Nginx and you should be swimming along.


They state that running the same command will, in effect, renew the certificates. It’ll save the new certificate in the same place, so no configuration changes are needed as long as you didn’t move your privkey and fullchain initially.

If you set the flags and/or the config file correctly, you should be able to add this as a cron job on your server to automatically renewal—say every month. I didn’t set this up since I wouldn’t be surprised if the process is improved by the time I need to use it.

Closing Notes

All in all, it’s a pretty painless process, as long as it works. The documentation isn’t fully fleshed out yet—though great for a beta product—so trying to figure out when something doesn’t work as expected is mainly done by trial and error, searching their forums or their GitHub repo.

I’m excited to finally be able to use Let’s Encrypt and eager to see what happens now that they’re public.

Posted by Brandon Kraft

My life is an open-source book.

Leave a Reply

Your email address will not be published. Required fields are marked *