When I was setting up this new blog, I wanted to see if there was a way of enabling TLS for it without having to buy a certificate.
Let's face it, this site has nothing confidential nor there is sensitive information like logins that need to be protected, thus having to pay to have a valid SSL protected site did not make any sense.
I started looking if there was any CA that offered free certificates or anything like it. That's when I came across this interesting project: "Let's Encrypt".
Let's Encrypt is a fully automated, free and open CA that offers certificates in a fully automated way. The generated certificates last for only 90 days.
You might be thinking that that sucks, because every 3 months you will have to go through the hassle of renewing the certificates for your sites.
The really cool thing about this project is that they provide a client that makes it extremely simple to generate and renew the certificates for your sites, with minimal intervention when generating the certificate and no intervention at all for renewing.
Setting up TLS in nginx using "Let's Encrypt"
Here I'm going to show the steps I took in order to setup TLS for this blog in my Ubuntu 14.04 server using Let's Encrypt and nginx.
I am not going to use the nginx plugin for Let's Encrypt because, according to their documentation, it is in experimental state and it is not shipped with Let's Encrypt.
I will be using the webroot plugin. This plugin requires access to the root folder of the site you want to generate the certificate for.
The reason behind this is that Let's Encrypt, in order to validate that the requester actually controls the domain he is asking the certificate for, will require a challenge. One of the challenge methods (the one used by this plugin) is to provide a file in a certain location of the site with a requested random content.
Installing the Let's Encrypt client
The best way to install this is by cloning their repo. This also makes it easy to update it.
$ sudo git clone https://github.com/letsencrypt/letsencrypt /opt/letsencrypt
Updating is just pulling the latest changes from upstream to our repo.
Generating the certificate
This is the beauty of Let's Encrypt, the whole process is reduced to a one-liner command.
Let's assume that the site's root is located on the path
/var/www/ and the name is
All you need to do to generate the certificate is:
$ /opt/letsencrypt/letsencrypt-auto certonly --webroot -w /var/www -d www.mysite.com
Want something easier than that? Impossible.
After the process has finished, Let's Encrypt will have generated a set of PEM files under the directory
Actually, what you are going to find in that directory are symlinks to the current certificates for the site.
You can find all the certificates that the client has ever generated for the site under
If you want to change the default arguments for the certificate generation you can take a look at the different arguments you can pass the Let's Encrypt client.
You can also setup a configuration file with everything you need for a certain certificate generation and give only that to the Let's Encrypt client.
Enabling TLS on a site using nginx
This is really straightforward.
Just open the nginx's configuration file for your site and add the following piece inside the
listen 443 ssl; ssl_certificate /etc/letsencrypt/live/www.mysite.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/www.mysite.com/privkey.pem;
Reload the server's configuration and Voila! you have TLS enabled with a valid certificate.
Now, if you want to go for something stronger regarding with security you will need to generate strong Diffie-Hellman parameters and restrict which ciphers you want to use.
To generate the Diffie-Hellman parameters run the following command:
$ sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
And to make nginx use them and restrict the ciphers add the following right after the changes you made to enable TLS in your site's configuration file:
ssl_prefer_server_ciphers on; ssl_dhparam /etc/ssl/certs/dhparam.pem; ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
Renewing the certificate is just as easy as generating a new certificate for a site, a single command:
$ /opt/letsencrypt/letsencrypt-auto renew
This will renew all the certificates that are managed by Let's Encrypt that are due for renewal (less than 30 days for expiration).
In any case, having to remember to run the command every 60-90 days is still a pain and prone to forgetting and letting your site with an invalid certificate.
That's the reason why I think setting up automatic renewal is key.
As you can imagine, this is really easy using
Open the crontab for the
$ sudo crontab -e and add the following cron jobs:
30 20 * * 6 /opt/letsencrypt/letsencrypt-auto renew >> /var/log/letsencrypt-renew.log 35 20 * * 6 service nginx reload
This will basically execute the renewal process every Saturday at 20:30 and 5 minutes later we reload the nginx configuration.