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.
ssh into your server and we'll begin installing
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
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
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.
Using the certificates
Let's Encrypt keeps the certificates and keys in
/etc/letsencrypt/live/ for each domain so regardless of subdomain both
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.
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
[Unit] Description=Let's Encrypt autorenew certificate for mihok.computer [Service] Type=oneshot ExecStart=/usr/bin/letsencrypt renew User=root Group=systemd-journal
[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!