Implementing SSL Using Let’s Encrypt

I recently decided to implement SSL certificates for all of my published websites. Rather than pay the high costs that commercial cert providers charge, I opted for using Let’s Encrypt. This turned out to be a lot easier than I expected, though I did run into a few gotchas.

First, go the EFF’s Certbot website and use the interactive selector to find the appropriate instructions for the OS/server combo for your system. In my case, I’m running Apache on Ubuntu 16.04. Here’s how I installed the app on my server:

$ sudo apt-get install software-properties-common
$ sudo add-apt-repository ppa:certbot/certbot
$ sudo apt-get update
$ sudo apt-get install python-certbot-apache

Second step is to run the app. The simplest way to do this (for my configuration) is with the following code:

$ sudo certbot --apache

Although this will work fine, I host a number of different projects on the same server. Best practice in this scenario is to certify each hosted domain individually. It’s also best practice to include any aliases and sub-domains as well. Here’s an example for one of my projects:

$ sudo certbot --apache -d -d -d

Note that it’s important to start the list of domains with simple version of the name first as show above.

This is where my first ‘gotcha’ happened. Silly me, I never thought to set my router to direct https requests to Port 443. Once I fixed this, certbot ran just perfectly, although it now threw a different error.

My second ‘gotcha’ was that I had never enabled the mod_ssl module in Apache. In short, Apache was not listening for anything on Port 443. This turned out to be a super-easy fix as well:

sudo a2enmod ssl

Followed by:

sudo service apache2 restart

Then followed by:

apache2ctl -M

… to confirm the module was enabled.

When the instruction runs successfully, the app will ask for some details. Among these, you’ll be asked to choose between allowing both http and https requests or forcing all requests to https. I went with the second, more secure option.

Third, I confirmed that all was working properly using’s SSL testing tool at

Fourth, and finally, I set up a cron job to update the certs when they expire. (Let’s Encrypt certs only last for 90 days, so this is important.)

At the command line, I entered the following instruction to first confirm that cert updating actually works properly for my install. Here’s the code:

$ sudo certbot renew --dry-run

With confirmation in hand, the next thing is to set up a cron job to run this on a daily basis. This involved adding something like the following instruction to /etc/crontab:

15 3 * * * /usr/bin/certbot renew --quiet

Choose whatever run schedule you want. I went for 3:15 every afternoon. Note this will only renew certs that are about to expire. This helps to avoid into any over-quota situations.


This tutorial at Digital Ocean was quite useful in understanding the above process. I also found the Certbot documentation, the community forum at Let’s Encrypt, and the documentation at Let’s Encrypt to be very useful.


Update An SSL Certificate

Once every year, I need to update the SSL certificate for one my domains. Somehow, I’ve never written down the instructions until now:

Step 1: Initiate the Certificate Renewal

Start by purchasing a certificate renewal from the vendor. (I use Thawte.) They’ll send an email asking for purchase approval.

Step 2: Generate a Certificate Signing Request (CSR)

At the command line, navigate to the folder where certs and keys are stored. Mine is /etc/pki/tls/, and contains folders certs, misc, and private. In my setup, it also contains the .conf file for openssl.

Type the following command:

sudo openssl genrsa -des3 -out private/your-keyname-here.key 2048

This creates a private key owned by root and stores it in the file, /etc/pki/tls/private/your-keyname-here.key.

Next, working from within the same folder as before, use this private key to create a CSR. Type:

sudo openssl req -new -key private/your-keyname-here.key -out your-keyname-here.csr

The openssl process will now ask for certain details to be included in the CSR. When requested, do not enter an email address, challenge password or an optional company name. The process creates a CSR file owned by root and stores it in, /etc/pki/tls/your-keyname-here.csr.

Now validate the CLR on this testing site. For more details about generating the CSR, check here.

Step 3: Submit the CSR

Navigate to the certificate provider’s website, sign in, then submit the CSR for approval. On success, the provider will send download and installation instructions via email.

Step 4: Install the certificate

Follow the instructions in the email to download the certificate, unzip it, and move the contained files into the appropriate target directory or directories for your setup. My latest certificate included two files, namely, ssl_certificate.crt and IntermediateCA.crt. In my setup, both files went into the /etc/pki/tls/certs/ folder. Make sure to be logged as root when creating these files, and set file permissions to 644.

For more details, visit this page.

Step 5: Update the SSL config file

Back at the command line, navigate to /etc/httpd/conf.d/ and open ssl.conf. Find the lines for the following settings:


… and make sure they point to correct files and locations for each of these settings. My setup looks like this:

SSLCertificateFile /etc/pki/tls/certs/ssl_certificate.crt
SSLCertificateKeyFile /etc/pki/tls/private/
SSLCertificateChainFile /etc/pki/tls/certs/IntermediateCA.crt

Step 6: Reboot the server

Follow the instructions in the earlier article, Rebooting the MSA Server on Digital Ocean, to restart the server.

Step 7: Verify success

Once the server is back up, verify the certificate is working properly using this testing tool.

@Note on passphrases for SSL certs: if you opt for a passphrase when creating a CSR, you’ll need to provide this passphrase each time the server is rebooted. This is okay for a stable environment but becomes a pain when server restarts are frequent.

I opted to remove the passphrase on my dev server using the instructions outlined here. However, my production server still requires the passphrase.