If you are looking to automate the process of obtaining, installing, and updating TLS/SSL certificates on your web server, then Let’s Encrypt is a very useful tool. It is a certificate authority (CA) that comes packaged with a corresponding software client, Certbot, that will automatically install TLS/SSL certificates. This means that you can run encrypted HTTPS on a web server without having to worry about constant maintenance.
Right now, Certbot is able to fully automate the process of obtaining and installing a certificate using the two most commonly used web servers: Nginx and Apache. Which of these you are using will depend on your personal preference and needs, but for those coming to this topic for the first time I recommend looking at the differences between Nginx and Apache to work out which one is best for you.
In this tutorial, I will show you how to use Certbot to automatically download, configure, and renew certificates from Let’s Encrypt, a free and open certificate authority developed by the Internet Security Research Group, and which is trusted by almost all the browsers in use today.
What We Will Do
In this tutorial, we are going to install Certbot, and then use it to get a free SSL certificate for Nginx on Ubuntu 18.04. We will also set up this certificate to renew automatically, so you don’t have to spend hours maintaining it. We will then test the system to make sure that everything is running smoothly.
The best practice for doing this is to use a separate Nginx server block file, rather than the default Nginx file. Setting up a distinct server block file for each domain helps to avoid a number of common mistakes, and it also means that if anything goes wrong you will have the default block file as a backup.
Before starting this tutorial, you are going to need a few things. To my mind, the best solution to using your Ubuntu setup as a HTTPS server is to use a LEMP stack, and this is what I’m using in the following tutorial. I know that some people prefer a different setup, however, so I’ll list the absolute minimum requirements here:
- First, an Ubuntu 18.04 server set up and running. You will also need this server to have a sudo non-root user, and an operational firewall.
- A registered, working, and tested domain name. In this tutorial, I’m going to use example.com. There are plenty of ways to get a domain name cheaply, or even for free, or you can just use your existing registrar.
- For your domain name, you are going to need to have set up two DNS records. One should be an A record with example.com pointing to your server’s public IP, and the other another A record with example.com pointing to the same place.
- Once you have all this, go ahead and install Nginx on your server. This is pretty straightforward, but there are plenty of guides available if you get stuck. Make sure, when you install Nginx, that you also have a server block for your domain. In this tutorial, I will use /etc/nginx/sites-available/example.com as my example, but install the server block wherever is easiest for you.
Keep in mind that Nginx can also be used as a proxy server within your network environment. If you are using a proxy configuration, it complicates the SSL setup process but can still be done with Let’s Encrypt. To secure external traffic from end to end, you will need to actually obtain two separate SSL certificates.
The first one, which will be used between external browsers and your Nginx proxy, must come from a certificate authority like Let’s Encrypt. The secondary certificate will encode the traffic between your proxy server and the back-end application server that responds to the request. This secondary certificate can be set up as a self-signed internal SSL certificate. Just make sure you add the “proxy_ssl_trusted_certificate” attribute to your Nginx configuration file.
Step 1: Install Certbot
Once you’ve got everything I’ve described, the first step is to install Certbot on your server. This will allow you to get an SSL certificate to use with Let’s Encrypt. Right now, Certbot is in quite rapid development, and unfortunately this means that the version listed in the standard Ubuntu repositories is often out of date. The first step in installing Certbot is therefore to add the development repository to your system.
Go ahead and do this using apt as su:
$ sudo add-apt-repository ppa:certbot/certbot
It’s also good practice, whenever you add a new repository, to run an update:
$ sudo apt update
Now you can add the Nginx package for Certbot straight from the command line, again using apt:
$ sudo apt install python-certbot-nginx
And that’s it, for now. You should have an installation of Certbot ready to use. However, in order for it to get SSL certificates for you, you are going to have to configure Nginx. Luckily, this is also pretty straightforward.
Step 2: Configure and Confirm Nginx
In order for Certbot to obtain and maintain SSL certificates for you, it needs to know where your server block is. The way it does this is to look for a server_name tag, and compare it to the domain that you are requesting a CA for. If you’ve installed Nginx with standard options, this should already be working. However, it’s good practice to check this before you go on to the next step.
First, find your server block, and open it using your favorite text editor, again as su. I use gedit, but you can equally use nano:
$ sudo nano /etc/nginx/sites-available/example.com
With the file open, look or search for the server_name line. It should look like this:
server_name example.com www.example.com;
If it does, good.
If it doesn’t, you are going to have to tell Nginx where to look. To do so, update the line to point it to the right domain. Then save and close the document. This should be all you have to do, but it is worth checking at this point that everything is well. You can check that your edits make sense to Nginx by running it from the command line:
$ sudo nginx -t
If you get an error, something went wrong. The most likely source is a typo in your own edits, so go back and check the file for those. Once you’ve got this command running with no errors, you can move on.
The next step is to re-start Nginx so it will use the correct server block. To do this, you will need to make a system call, but don’t worry. Run this command:
$ sudo systemctl reload nginx
At this point, Nginx should report that it found the correct server block.
So far so good.
Step 3: Allow HTTPS Traffic Through your Firewall
The next step is to allow HTTPS traffic through your existing firewall. This step will be a little different depending on which firewall you have, and how you have it configured. I would recommend, however, using ufw, because it plays nicely with Nginx, and this is the firewall that most Nginx installation guides recommend. This is largely because Nginx will register a few profiles with ufw when it is installed, which makes your life a whole lot easier.
You can check your current ufw settings directly from the command line, so go ahead and do that:
$ sudo ufw status
The output should look something like this:
As you can see, at the moment only HTTP traffic is allowed through your server, so you need to tell ufw to allow HTTPS through. Nginx already comes with a profile that will allow this, so all you need to do is enable it:
$ sudo ufw allow 'Nginx Full'
Then disable the obsolete Nginx HTTP profile by deleting it:
$ sudo ufw delete allow 'Nginx HTTP'
To check that these commands worked, you can verify the configuration settings for ufw in the same way as before. Run the same status command:
$ sudo ufw status
And you should see that the output has changed, so now HTTPs is permitted:
Status: active To Action From -- ------ ---- OpenSSH ALLOW Anywhere Nginx Full ALLOW Anywhere OpenSSH (v6) ALLOW Anywhere (v6) Nginx Full (v6) ALLOW Anywhere (v6)
So you should now have Nginx installed, with a ufw set up that will allow HTTPs traffic through.
Step 4: Get an SSL Certificate
Certbot offers a few ways of getting SSL certificates, all of which run through plugins. The advantage of getting an SSL certificate in this way is that the plugin will take care of reconfiguring Nginx, and then reloading it, without you having to do anything.
I know, however, that some of you might want to increase the level of security offered by the standard method of key exchange available through Let’s Encrypt. For most of you, this will not be necessary, and you can skip to the next paragraph. However, if you want to secure your key exchange you can, for instance, generate a Diffie-Hellman group at this point, and secure your key exchange channel using this key. There are plenty of guides available on how to do this for those who are extra conscious about security, but in this tutorial I will stick to the standard methods for key exchange.
To run the Nginx plugin for Certbot, use this command:
$ sudo certbot --nginx -d example.com -d www.example.com
Here, you are running Certbot with the –nginx tag to tell it to use the plugin, and adding a -d tag in order to tell it which domains you want the certificate to be valid for.
If you are following this tutorial, this will probably be the first time you’ve run Certbot, and so it will prompt you for an email address, and ask you to agree to its terms of service:
Once you’re past that, Certbot will contact the Let’s Encrypt server, and ask you to verify that you own the domain that you are requesting a CA for.
Hopefully, all will go smoothly. The next step is to configure your HTTPs settings, and Certbot will prompt you to do so using the following output:
Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
1: No redirect – Make no further changes to the web server configuration.
2: Redirect – Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you’re confident your site works on HTTPS. You can undo this
change by editing your web server’s configuration.
Select the appropriate number [1-2] then [enter] (press ‘c’ to cancel):
Which of these options you choose will depend on your own needs, but if you are setting up a new site I’d recommend going with “2.” Whichever you select, Certbot will then reload Nginx to implement the new settings. It will then tell you where your certificates are stored:
If you’ve reached this point, your certificates should be downloaded, stored, and loaded. You can test if this is the case, though, by simply reloading your website and looking for the green ‘lock’ symbol. You should also notice that your domain name is now https://. One final check is to use a security check like that at SSL Labs Server Test, and check your security assessment. If your certificates are all up and running, it should return an “A” grade.
Technically, you should now have everything in place to run HTTPs through Nginx, with Certbot managing your SSL certificates. I will show you how to test that in just a minute, but before I do it is worth pointing out that the same process I’ve described here can be used to install, configure and maintain CAs on a wide variety of third-party server providers. A good example of this is Amazon’s popular EC2 service.
The process of setting up Nginx and Certbot to work with your EC2 server is essentially the same as with your own Ubuntu 18.04 server. It is here, in fact, that Certbot really proves its worth, because the security configuration of EC2 servers can otherwise be quite complex, and the security of EC2 servers is particularly critical, given the ubiquity of AWS in the cloud share market: AWS/EC2 powers nearly 20% of the web, including many popular website builders like Wix and Squarespace.
Step 5: Verifying Auto-Renewal for Certbot
The final step in installing any new software is to check that it works. This is particularly critical when setting up Certbot, because the certificates it downloads from Let’s Encrypt are only valid for 90 days. This is partially to keep the certificates secure, but also acts to encourage users to automate their security renewal process. Happily, Certbot already comes with a script to automate this.
If you are curious, you can look at the script: it’s in /etc/cron.d. There, you can see that the script will run automatically twice a day, and will attempt to renew any certificate that is due to expire in the next 30 days.
This should mean that Certbot will automatically keep your CAs up to date. However, you can check that everything is working properly by running the following command:
$ sudo certbot renew --dry-run
Though the output of this command is not that helpful in itself, if it completes with no errors you can be certain that Certbot will renew your certificates when needed. If it is unable to do so, it will send you an email (to the address you gave it above) to warn you that something went wrong.
Next Steps and Extra Security
For most of us, the standard set up offered through Certbot and Nginx will offer a good level of security and adaptability. However, for some applications a few further configuration steps may be required. If you want to allow an A+ SSL rating, for instance, Certbot will allow you to configure this also.
If you’ve followed the tutorial above, you should see that your server blocks contain these lines, which have been generated by Certbot:
ssl_certificate /etc/letsencrypt/live/YOUR-DOMAIN/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/YOUR-DOMAIN/privkey.pem;
This is great for most purposes, but there is a stronger configuration, using OCSP stapling, which requires that each virtual host needs a trusted ssl certificate as well. To enable this, add this line after those above:
After this, you will need to edit the shared SSL settings, which should be stored in /etc/letsencrypt/options-ssl-nginx.conf. Open this config file, and replace the contents to tell Nginx that you want to use stapling:
ssl_session_cache shared:le_nginx_SSL:1m; ssl_session_timeout 1d; ssl_session_tickets off;
ssl_protocols TLSv1.2; ssl_prefer_server_ciphers on; ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"; ssl_ecdh_curve secp384r1;
ssl_stapling on; ssl_stapling_verify on;
add_header Strict-Transport-Security "max-age=15768000; includeSubdomains; preload;"; add_header Content-Security-Policy "default-src 'none'; frame-ancestors 'none'; script-src 'self'; img-src 'self'; style-src 'self'; base-uri 'self'; form-action 'self';"; add_header Referrer-Policy "no-referrer, strict-origin-when-cross-origin"; add_header X-Frame-Options SAMEORIGIN; add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection "1; mode=block";
Save, exit, and restart Nginx, and you should be up to an A+ security rating. You can check this by running another test through the SSL Labs Server Test.
Beyond this, there are plenty of further steps you can take to make your system completely impregnable, such as using content-specific features like Content Security Policy and Subresource Integrity, or even Brotli compression to replace gzip.