Skip to main content

Free SSL with Let’s Encrypt & NGINX

Posted on March 1, 2018 by KeithThompsonKeithThompson

Every few weeks it seems like one of the major web browsers or search engines makes a change that makes SSL/TLS more important. Recently, Google announced that Chrome will label all connections to websites using HTTP instead of HTTPS as “Not Secure” soon. Currently, we’ll see this behavior when we’re about to submit a form over HTTP, but the coming change will be any page served over HTTP.
As if seeing “Not Secure” in the Omnibox wasn’t bad enough, Google’s search engine also prioritizes sites that use SSL/TLS.
We need SSL, but sometimes paying for a certificate is out of the question. That is where Let’s Encrypt comes in, helping provide free SSL certificates to secure the entire web.
Let’s look at how we can use Let’s Encrypt with NGINX to deploy a simple website that is secure by default.

Installing NGINX

Before we get started, we need two things:

  1. A domain (so we can set up DNS).
  2. A publically accessible server that we can point our domain (or subdomain) to, can install software on, and can start a service on (sudo access).

If you’re a Linux Academy student, then a Cloud Server will work perfectly for this demo. We’ll use CentOS 7 as the operating system for our server.

Adding the Official NGINX Yum Repo

We’re going to install a pre-built version of NGINX directly from the official NGINX repository. Installation only takes a few steps, and the first is to add a new repo file at /etc/yum.repos.d/nginx.repo:

$ sudo vim /etc/yum.repos.d/nginx.repo


name=nginx repo

Now we need to update and install using yum:

$ sudo yum update
$ sudo yum install -y nginx

Starting and Enabling NGINX

With NGINX installed, we’ll need to make sure that it is running and also that it will run when our server restarts. To do this, we’ll use systemd:

$ sudo systemctl start nginx
$ sudo systemctl enable nginx

Configuring DNS

This step can’t be demonstrated, but you’ll need to set up a DNS A record to point to your server’s IP Address. Here’s my DNS configuration using an unused domain that I have registered:

@       A       MY_IP_ADDRESS
www     CNAME

Do something similar with a domain that you own before proceeding.

Creating Virtual Host Configurations

Let’s create a straightforward virtual host configuration for our domain (substitute with your domain). We do this so that there is a server block for certbot to modify.

server {
    listen 80;
    location / {
        root /usr/share/nginx/html;
        index index.html;

That configuration file will be loaded by NGINX on the next reload, and it specifies that if any requests are received with the Host set to either or, then they should be handled by this server configuration. Now that this basic NGINX configuration is set up, we’re ready to let certbot set up SSL.

Configuring Let’s Encrypt

Let’s Encrypt will be our Certificate Authority, but the tool that we’re going to use to generate our certificates will be certbot. We’re going to install certbot from the EPEL repository, and will need to add that repository if it’s not already enabled on our server.

$ sudo yum install epel-release
$ sudo yum install -y certbot-nginx

The certbot utility has many different plugins to help us set up SSL for our servers (Apache, NGINX, DNS provider plugins, etc.), and what we’ve installed includes the NGINX plugin. With certbot installed, let’s generate our certificates.
Note: we need to make sure that our DNS changes have gone live.

$ sudo certbot --nginx -d -d

That command will send us through a series of command line prompts. We’ll accept the terms, put in our email address, and when asked we want to specify to redirect all traffic to HTTPS. When finished, certbot will have changed the server configuration for our domain and reloaded the server. Here’s the final configuration file after the certbot modifications:

server {
    location / {
        root /usr/share/nginx/html;
        index index.html;
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
server {
    if ($host = {
        return 301 https://$host$request_uri;
    } # managed by Certbot
    if ($host = {
        return 301 https://$host$request_uri;
    } # managed by Certbot
    listen 80;
    return 404; # managed by Certbot

Without touching the generated configuration, our website is receiving an A rating from the SSL Report on SSL Labs.

Renewing Certificates Automatically

Certificates generated by Let’s Encrypt are valid for 90 days, so we’ll need to renew them more often than if we paid a different certificate authority for a certificate. Thankfully, certbot once again has this covered. The certbot renew command will check which certificates on the server need to be renewed soon and fetch new ones. Behind the scenes, certbot has already created a certbot-renew systemd service and timer (found at /lib/systemd/system/certbot-renew.{service,timer}). We’re going to make a small modification to the configuration file that the service uses (located at /etc/sysconfig/certbot) to make sure that NGINX is reloaded after a certificate is renewed.
Find the uncommented line containing POST_HOOK and set it to match this:

POST_HOOK="--post-hook 'systemctl reload nginx'"

Finally, let’s enable the service and timer:

$ sudo systemctl start certbot-renew
$ sudo systemctl enable certbot-renew
$ sudo systemctl start certbot-renew.timer
$ sudo systemctl enable certbot-renew.timer

With this timer and service enabled, there will be a daily check to see if our certificate needs to be renewed. If the certificate does need to be renewed, certbot will fetch the new certificate(s) and reload the NGINX configuration automatically after the new certificates are downloaded.


Setting up SSL using NGINX and Let’s Encrypt (using certbot) is free and relatively simple. There isn’t a reason for any of us to be running any publically accessible services without SSL now. Let’s help secure the web!


Leave a Reply

Your email address will not be published. Required fields are marked *