NGINX SSL with Lets Encrypt


What is SSL?

SSL (Secure Sockets Layer) is the standard security technology for establishing an encrypted link between a web server and a browser. This link ensures that all data passed between the web server and browsers remain private and integral. SSL is an industry standard and is used by millions of websites in the protection of their online transactions with their customers. (Source)

Basically, this means that SSL is used to create a more secure connection between your server and the user. We like this because it not only protects the users data, but it helps protect the server as well. For me, I use SSL on every site that I have, so we’ll go through the process of setting that up, and how to manage it.
In order to set up SSL, you will need to have an active domain present in the server_name section, as well as having the domain pointed to your NGINX server. This is because we’ll be using LetsEncrypt to generate our own SSL Certificates, and it requires an active connection to the website. The reason we’ll be using LetsEncrypt instead of paying for a certificate is because LetsEncrypt allows us to generate certificates that are valid for 90 days at no cost to us, and then allows us to renew them indefinitely. To simplify this process, we’ll be using CertBot which automates a huge part of the process for us.

Installation and Setup

Lets get started. First, we’re going to need to install CertBot. To do that, we’ll need to add it to the repository so we can download the package.

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

Now that CertBot is installed, we’ll be able to easily generate certificates because CertBot has an NGINX plugin that references are NGINX installation and not only uses that to pull what domains you’re using, but also to update files so that you don’t have to. To begin with CertBot we’ll do sudo certbot --nginx. This will prompt us will a screen that looks similar to this. Your results will vary depending on your domain(s).

For your usage, you’ll likely only have one option which is your domain. To select it you can simply hit Enter. In the future, should yours have multiple domains, but you only want to generate domains for specific ones, you’ll simply enter in the corresponding numbers separated by either a space or comma. EX. 1 2 3 OR 1,2,3

The CertBot will progress through its steps to generate SSL Certs for the sites selected. Once finished, it will look something like this.

Now, you’ll notice in my screenshot that it says its unable to install the certificates, this is because I’ve added my certificates to the ssl-defaults.conf snippet so that its easy for me to change on all pages. I’ll cover that more in detail later on.
Once this has completed, we’ll see that it stored our certs in /etc/letsencrypt/live/cyanserver.com/ which will contain a couple of files including fullchain.pem & privkey.pem. These are the two files we’ll need.
In each of your server blocks, you’ll need to add the following lines. These are typically located right under server_name.

ssl_certificate /etc/letsencrypt/live/cyanserver.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/cyanserver.com/privkey.pem;

Once our ssl_certificates have been generated, and we’ve added them into our server blocks, we need to update our Diffie-Hellman Parameters. This dhparam.pem affects the security of the initial key exchange between our server and its users.

sudo openssl dhparam -out /etc/nginx/dhparam.pem 2048
Heads up!
This step can take a long while. Be patient, its important.

Once the dhparam.key has been generated, we need to add it to our server blocks. Add it a line below the ssl_certificates.

ssl_dhparam /etc/nginx/dhparam.pem

Lastly, in order to achieve an A+ on SSLLAbs, we need to make sure we enable HTTP Strict Transport Security. To do this, we want to add the following to our Config:

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

I typically put this right after my listen properties.

Once you’ve added the ssl_certificate & dhparam.pem lines to the server blocks, we want to test our NGINX config by doing sudo nginx -t. If it outputs the following, we are in good shape:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Finally, we need to reload NGINX so that it takes the updated settings. To do this we can go do sudo nginx -s reload. Once NGINX is reloaded, we should be all set!

Expanding SSL Certifications

In this portion we’ll go over how you expand your certificates to cover more websites. We’ll do this a specific way so its easy for us and not something where we have to update a bunch of stuff.

Typically the way you expand a cert is via the following command:

sudo certbot --nginx --cert-name domain.com --domains domain.com,new.domain.com,n2.domain.com

When you’re constantly adding new domains, it can be a pain because you have to type out each domain every single time. I’ve never been a fan of having to type everything out every single time, so we’ll go ahead and simply this process. We’ll do this by creating a couple of files that will help us expedite the process.
The first file we are going to create is our expand.sh script. This will be what we run to expand. Make sure you replace cyanlab.io with your domain name.

#!/bin/bash
 
domains=$(<domains.txt)
 
sudo certbot --nginx --cert-name cyanlab.io --domains "$domains"

This script assumes that both the expand.sh and domains.txt files are in the same location. For me, I put them on my user directory.
Next we need to create the domains.txt. Each line should end with a , and should not have a space before or after it.

domain.com,
new.domain.com,
n2.domain.com

This domains.txt will allow us to keep a running tally of the domains. If we need a new domain, we simply add it to the list and if we no longer need a domain we simply we move it from the list.
Now that both files are created, we need to make sure the file is executable. sudo chmod +x expand.sh
After it runs, you should be all updated.

Certificate Renewal

Renewing your SSL Certificates is extremely important. LetsEncrypt only generates certificates that last 90 days, so that means we need to renew them every 90 days. Thankfully, CertBot makes this fairly simple, and we can take it a step further by automating it.

To manually renew certificates we can run:

sudo certbot renew

Its really that simple.

But lets face it, no one wants to have to remember to renew their certificates, so we’re going to automate it using the crontab. First, we need to enter the crontab sudo crontab -e. We use sudo here so that these commands run as sudo and we are not required to add sudo into the actual crontab. Once the crontab is open, we want to add the following to the end of the document:

30 0 1 * * certbot renew --post-hook "nginx -s reload" >> /var/log/letsencrypt/renew-cronjob.log

This sets the cron tab to run on the first of the month, at 12:30 AM. That way, the update reload of the server is unlikely to affect any clients. CertBot will only update certificates that are within 30 days of expiring and will only reload the server if certificates were updated. You won’t have an issue of this occurring every single month unless you have a range of certificates that were created at separate times. Keep in mind, when you expand certificates, it renews ALL certificates under that domain, so this is only likely to occur if you have multiple root domains.
Once that’s saved, that’s all there is to it. CertBot will automatically renew your certificates before they expire.