Today.

Matthew Mihok posted:

Exploring Let's Encrypt for HTTPS

Let's Encrypt is a fairly new service and tooling that boasts free certificates and automated SSL management. Today, and in the past, providing HTTPS has been a massive hassle for System Admins, Operations, and DevOps people. The whole "chain of trust" is sometimes even considered a racket just to charge people and businesses money to provide arbitrary trust on your website. That being said, HTTPS, and SSL encryption is absolutely necessary when ingesting form data of any kind.

There are in fact a couple use-cases to take advantage of Let's Encrypt's SSL certificates over self-signed or bought certificates:

  • Enable your website(s) to use HTTPS
  • Don't want to pay money for a SSL certificate
  • Dislike having to renew SSL certificates on a regular basis

Today, we're going to explore the tooling and enable HTTPS for a website. To do this, we'll start by exploring the Let's Encrypt's certbot confusingly named letsencrypt on Ubuntu 16.04. From certbot's website:

Certbot is an easy-to-use automatic client that fetches and deploys SSL/TLS certificates for your webserver. Certbot was developed by EFF and others as a client for Let’s Encrypt and was previously known as “the official Let’s Encrypt client” or “the Let’s Encrypt Python client.” Certbot will also work with any other CAs that support the ACME protocol.

A couple prerequisites and knowledge:

  • Networking, specifically DNS and domain name management
  • Server with a Public IP
  • Linux, specifically Ubuntu/Debian

Here are the versions we're working with today:

  • Ubuntu 14.04 or 16.04
  • letsencrypt 0.8.1

Note (2017-02-12): For some reason Ubuntu 16.04 Xenial has a older version (0.4.1-1) of the letsencrypt package available but all the commands should work the same. There may just be less GUI interactivity.

Okay, lets get started

Usually I would begin with a simple Vagrant box but there is a requirement to use a server accessible on the internet due to Let's Encrypt verification process. Today I'll quickly spin up a DigitalOcean machine to illustrate the process.

Okay, ssh into your server and we'll begin installing letsencrypt

Installing the certificate manager

If you're on 16.04 the installation is dead simple, simply run the command: apt install letsencrypt You can skip to the next section now!

If you're on 14.04 or want the latest version, then we have to install certbot manually. I also like to keep all my manually installed software/binaries organized. We're lucky in this specific case as certbot comes with a wrapper called certbot-auto that handles upgrading itself. But in cases where the software didn't come with this functionality out of the box, you would want to take the organization to the next level and version the folder according to the current version you are installing.

cd /opt
sudo mkdir certbot

Note: If we were installing software that didn't include auto-update: sudo mkdir certbot/certbot-0.8.1 would be the next additional step

Next, lets download the binary

cd certbot
sudo wget https://dl.eff.org/certbot-auto

Because we are security conscious, we'll want to verify any script we download from the internet. To do this lets download the gpg signature:

sudo wget -N https://dl.eff.org/certbot-auto.asc

And verify the file:

gpg2 --keyserver hkp://keys.gnupg.net --recv-key A2CFB51FA275A7286234E7B24D17C995CD9775F2
gpg2 --trusted-key 4D17C995CD9775F2 --verify certbot-auto.asc certbot-auto

Note: The key from the keyserver may change, so you should always refer to the certbot documentation.

Finally, lets create a symlink to our new certbot binary so we can access it from anywhere

sudo chmod a+x certbot-auto
sudo ln -s /opt/certbot/certbot-auto /usr/local/bin/letsencrypt

Note: I've made the symlink letsencrypt instead of certbot for consistency between Ubuntu 14.04 and 16.04 and so that the rest of the post makes sense, but you could name it certbot if you wanted.

Alright, now we can start using Let's Encrypt with our new letsencrypt command line tool.

Obtaining a new certificate

One of the major caveats of using Let's Encrypt (there are two,) is that it does not currently (and it may never) support wildcard SSL certificates. This can complicate things in that instead of making one certificate for *.startup.com, which would handle everything from app.startup.com, blog.startup.com, to www.startup.com. We now have to make a certificate for each domain or subdomain we need.

There are two ways to do this, through the command line or through a command..line.. GUI haha. If you installed the more up-to-date version you have access to the GUI (Its a little bit more user friendly I suppose,) try it out with that first if you would like.

Otherwise, I'll walk us through the command line route:

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

The above command creates all the new certificates, keys, and signs/verifies everything with Let's Encrypt's root CA for example.com and www.example.com.

The tricky part here is that to sign and verify the newly created certificates it has to serve some data up from the domains we're trying to use. There are two methods to serve that data, either putting some files in your base html directory (--webroot -w /var/www/html) or running it's own web server (--standalone.) The latter will try to use port 80 so if you already are running Apache, or Nginx, or another service is using that port and will fail to create the certificates.

Boom! We now have certificates for example.com and www.example.com, now lets start using them.

Using the certificates

Let's Encrypt keeps the certificates and keys in /etc/letsencrypt/live/ for each domain so regardless of subdomain both example.com and www.example.com files are in the example.com folder. You should allow it to continue to live there, otherwise you may break the awesome automatic renewal feature.

Depending on your choice of web server, you have to tell it to start using the new certificates and files so that you can begin serving traffic through SSL. I use Mozilla's SSL Configuration Generator to keep things secure although it can look a bit confusing to read if you haven't had a chance to use any of the SSL configuration directives before.

Next, lets setup auto-renewal so we never have to worry about it again.

Renewing certificates

This is by far my favourite feature of Let's Encrypt. If you kept the certificate and key files in /etc/letsencrypt/live/ folder you can setup a cronjob or systemd timer to automatically renew your certificate when it needs to.

For Ubuntu 16.04 which uses systemd, we'll create two files letsencrypt.service and letsencrypt.timer.

Here's /etc/systemd/system/letsencrypt.service:

[Unit]
Description=Let's Encrypt autorenew certificate for mihok.computer

[Service]
Type=oneshot
ExecStart=/usr/bin/letsencrypt renew
User=root
Group=systemd-journal

And /etc/systemd/system/letsencrypt.timer:

[Unit]
Description=Run Let's Encrypt twice daily

[Timer]
OnCalendar=*-*-* 00/12:00:00
Persistent=true     
 
[Install]
WantedBy=timers.target

I've created a gist for both files here. The first .service file is the command definition, which runs letsencrypt renew. The next, .timer file tells systemd when to run the file (twice daily starting at midnight.) Next lets enable and start them:

sudo systemctl enable letsencrypt.timer
sudo systemctl start letsencrypt.timer

For Ubuntu 14.04 we'll setup a simple cronjob to run the renew command. Simply edit the crontab using crontab -e and add the following line:

*/12 * * * * /usr/bin/letsencrypt renew

That's it! The cronjob or systemd timer will run twice a day, every day, and will check if the certificate needs renewal. If it does, it will automatically renew and update the certificate!