Installing Let's Encrypt with Ansible
I started using Let's Encrypt during beta and feel in love with it. It's made installing, setting up and maintaining SSL certificates so easy. It's also extremely affordable (given that it is free) for everyone. I truely believe every website should be running over HTTPS no matter what and Let's Encrypt gives you no more excuses. In this article I'm going to tell you how I've setup and automated Let's Encrypt on a half dozen of projects. I've set everything up on Ubuntu 14.10 and am using Nginx as my webserver. If you are working on another O/S and using another webserver this configuration may not work for you.
Installing and Setting up Nginx with Let's Encrypt
When installing Let's Encrypt I've done part of it manually and then automated, with Ansible, the renewal. The initial setup and obtaining the certificate is done by hand. Before we get started we need to install a few dependencies and Nginx on our Ubuntu server. I normally have this scripted as part of my server setup but for now let's walk through the installation steps.
The first thing we need to do is update our package manager cache
Then we'll need to install git and bc if they aren't already installed. Git, as you know, is a version control system and we are using it to pull down the Let's Encrypt code used to obtain our SSL certs. The bc library is an interactive algebraic language with arbitrary precision which follows the POSIX 1003.2 draft standard.
We'll be using the web-root plugin with Nginx to obtain our SSL cert. Before setting up the web-root plugin we need to install Nginx.
Now that we have git, bc and Nginx installed we can configure Nginx to use the web-root plugin. The web-root plugin works by creating a temporary file in the ./well-known directory. Let's Encrypt will open the temporary file inorder to do it's validation. Lets give Nginx access to the web-root directory by editing the Nginx configuration file.
We'll need to add the following location block to the SSL server block
We can now save, exit and reload nginx.
Installing and Obtaining an SSL Certificate
Now that we have Ngnix configured to access the web-root plugin we can setup and install Let's Encrypt. The first thing we want to do is clone the Let's Encrypt source code.
We now have the Let's Encrypt source code setup and are ready to obtain our SSL certificate. We're going to use the web-root plugin to request an SSL certificate using the command line tool. We will use the -d command to specify the domain.
When you run the command line tool you will be prompted with a few questions. Let's encrypt will ask you for your email address (which is used for urgent notices and lost key recovery) and it will ask you to accept the terms and conditions. Assuming we have configured everything correctly and entered the correct information into the prompts we should get the below output.
You'll be able to find your SSL certificates in
The following files are stored in the directory
- privkey.pem --> Your private key
- cert.pem --> Server certificate
- chain.pem --> Root and intermediate certificates only
- fullchain.pem --> All certificates. This includes the server certificate. It's a concatenation of cert.pem and chain.pem
When you generate new certificates the old ones will be stored in
To increase security I create a strong Deffie-Hellman group by running the following command
This will generate a file called dhparam.pem in
We're now ready to configure Nginx with our certificates.
Configuring Ngnix to use our SSL certificates
Now that we've obtained our SSL certifications, we need to configure Nginx. We'll need to configure Ngnix to rewrite all non-ssl traffic to our SSL port, turn on ssl, point Ngnix to our obtained certificates and configure the server to only allow the most secure ssl protocols and ciphers. Finally we'll setup Nginx to use the Deffie-Hellman group file we generated.
First lets create a server block to rewrite all insecure traffic to our secure port. We want to create a new server block above the default server block that looks like this.
As you can see I set my nginx_server_name as a variable in my ansible vars file. This way I can make changes to the server name in one place and the rest of the ansible files will be updated. Now that we have the server rewriting all traffic over SSL, we need to turn on ssl and tell Nginx where to read our certificates from. In the main server block we are going to add the following lines
Again I am referencing nginx_server_name, ssl_cert_dir and ssl_cert_key as ansible variables that I've configured in my ansible vars file. Now that we have turned on SSL and are listening on port 443 we need to setup our server to only allow the most secure protocols and ciphers. Below the ssl_certificate_key you can add the below configuration options.
Now we are setup to run Ngnix over SSL. You can save, exit and reload Nginx at this point.
Inorder to make the server configuration reusable I usually build my Ngnix config as a template in my ansible playbooks using Jinja2. This allows me to easily deploy and configure Ngnix on any new servers that I'm going to deploy. This also allows me to automate the setup and configure of Ngnix. This way I only have to generate the Let's Encrypt certificates and then I can set the rest up using Ansible files.
Below is a sample Nginx configuration file.
Let's Encrypt certificates are valid for only 90 days. They recommend updating the certificate every 60 days though. This allows you to catch any errors that may occur before the certificate expires. Since you can obtain a new certificate from the Let's Encrypt client we are going to set up the renew process on a cron job. This will ensure we don't have to think about regenerating a new certificate every 90 days. I've set this up by creating a cron job in one of my ansible files.
The cron I setup is very naive and simple. I'm calling the Let's Encrypt client with the renew command
I'm piping the output to a log file to help with debugging. The cron is set to run every Monday at 2:30am. The second cron job will reload Nginx every Monday at 2:40am to ensure the new certificate is loaded if one is found. That's it, I'm now able to renew my certificate every 60 days.
In the past purchasing and getting a certificate has always been a pain and it's expensive. Let's Encrypt now gives you an option that will save you both time and money. I've always dreaded the day I had to sit down and spend an hour getting the certificate setup. It also killed me knowing I had to spend money on it when it should just be free. Now I'm able to set everything up once and focus on the important parts of my projects.
This entire process of setting up Let's Encrypt is based on this amazing Digital Ocean article.
For more details on what's going on with Let's Encrypt you can look at their documentation.