Backlit Keyboard in the dark

Let's Encrypt certificates on NGINX

At Smartson, we wanted to increase the security and the integrity of our visitors by adding the ability to retrieve the content encrypted using SSL.

We already served our site https://smartson.se/ over SSL/TLS. We used a relatively cheap commercial certificate and we realized that hade room for improvements. I have followed the Let’s Encrypt initiaive since before is’t launch since it would offer a higher security and thus integrity for the user if implemented correctly.

After a bit of searching we found a guide on how to configure Let’s Encrypt together with NGINX so that we would be able to get an A rating in SSL/TLS tests. The guide we started with was How to setup Let’s Encrypt for Nginx on Ubuntu 16.04 (including IPv6, HTTP/2 and A+ SSL rating).

It’s worth noting that we are running Ubuntu Linux 14.04 LTS and use nginx version 1.4.6.

Let me guide you on how we installed and configured our Let’s Encrypt issued certificate.

Installing and configuring Let’s Encrypt

In order to make it possible to reuse the configuration we create a diectory that will contains files that can be included by the nginx server instances that needs to support SSL/TLS. I’ll place the directory in /etc/nginx/snippets/.

To begin I create a file that holds the location expressions so that Let’s Encrypt can makr it’s verification callbacks. Which it does to verify the ownership of the hostname and domain as a part of the certificate issuing process. The file we create is /etc/nginx/snippets/letsencrypt.conf and conatins:

location ^~ /.well-known/acme-challenge/ {
	default_type "text/plain";
	root /var/www/letsencrypt;
}

Then create the directory that the root directive points to by running mkdir -pv /var/www/letsencrypt. Then make sure that the read- and write permissions for the directory is set appropiatly.

After that I create a file with the SSL/TLS-configuration in /etc/nginx/snippets/ssl.conf. This file will also be reused by several server instances.

The file in contains:

ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;

ssl_protocols TLSv1.2;
ssl_ciphers EECDH+AESGCM:EECDH+AES;
ssl_ecdh_curve secp384r1;
ssl_prefer_server_ciphers on;

ssl_stapling on;
ssl_stapling_verify on;

add_header Strict-Transport-Security "max-age=15768000; includeSubdomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

I modified the configuration a bit from the default configuration to increase the number of browser clients that can use the certificate without compromising with it’s security by changing the ssl_protocols directive to the following:

ssl_protocols TLSv1.2 TLSv1.1 TLSv1;

Modify NGINX-configuration

Now it’s time to install the Let’s Encrypt software. I add the Let’s Encrypt’s repository for Ubuntu 14.04 so that I can fetch the package via apt to manage our certificates.

$ sudo add-apt-repository ppa:certbot/certbot
$ sudo apt-get update
$ sudo apt-get install certbot

When the packages have been installed we are ready to request a certificate from Let’s Encrypt. This is done by the help of the newly installed certbot program. But prior to requesting the certificate make sure to create the directory by issuing mkdir -pv /var/www/example. Also remember to adjust the read and write permissions so that the user running the web server and only that user can read and modify the files in the directory.

The the certbot command and due to the fact that we have a working web server that can respond to the authentication request we use the webroot plugin to handle the challenge. In order to specify the domains that we are requesting certificates for add one -d per hostname.

$ certbot certonly --webroot -w /var/www/example -d example.com -d www.example.com
$ certbot certonly -n -d example.com -d www.example.com

If you have more than one virtual web server instance on the same host. I would recommend not using the same certificate for multiple hosts. A better option is to use one call per virtual host - the reason behind this is that it’s easier to move a virtual host to another server if needed. On order to do that call the certbot once per virtual host.

After obtaining a certificate (or several) from Let’s Encrypt it’s required to restart or reload the NGINX service, e.g. by issuing service nginx reload.

Automating the renewal of issued certificates

Since the lifespan of the certificates from Let’s Encrypt is only 3 months at the most it’s essential to renew them automatically.

<M> <H> * * * /path/to/certbot/certbot -n renew >> /path/to/certbot/certbot-cron.log && sudo service nginx reload
<M> <H> * * * /path/to/certbot/certbot -n renew >> /path/to/certbot/certbot-cron.log && sudo service nginx reload

We makes the check if the certificate needs to be reissued twice a day using cron. There is some room for improvements in this. I guess that it would be possible to use --pre-hook and --post-hook to restart NGINX. Another improvement would be to save the outcome of the renewal and if someone actually needs to take a look at the renewal manually if it fails.

 2017-05-19  4 minutes