Using CertBot to Automatically Secure Your Nginx Site

CertBot is a nifty tool created by the EFF the help leverage the power of free certificate authorities like Let's Encrypt. Its primary goal is to help configure popular web servers to use a SSL/TLS certificate. There's really no excuse this day and age to have an insecure site. Here, we're going to secure a site running behind Nginx on the CentOS 7 platform.

Assumptions

I'm assuming Nginx is already installed and configured for whatever site you might be running.  

Install Dependencies

CertBot is available through the EPEL CentOS repositories. It's usually a good idea to have EPEL enabled anyways, so let's do that.

[user@host ~]$ sudo yum install epel-release -y
...
Installed:
  epel-release.noarch 0:7-11

Complete!

Install CertBot

With the EPEL repositories enabled, we can now install CertBot.

[user@host ~]$ sudo yum install certbot -y
...
Installed:
  certbot.noarch 0:0.27.1-1.el7

Complete!

Since we are using Nginx, we also need that specific CertBot plugin.  Install it like so:

[user@host ~]$ sudo yum install python2-certbot-nginx -y
...
Installed:
  python2-certbot-nginx.noarch 0:0.27.1-1.el7

Complete!

Request a new Cert and allow CertBot to Configure Nginx

Now we should be able to tell CertBot to generate new certificates from Let's Encrypt for the site(s) we want. Here I'm also allowing CertBot to modify my Nginx configuration.

[user@host ~]$ sudo certbot --nginx -d yoursitename.com,www.yoursitename.com --preferred-challenges http
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx
Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for yoursitename.com
http-01 challenge for www.yoursitename.com
Waiting for verification...
Cleaning up challenges
Deploying Certificate to VirtualHost /etc/nginx/nginx.conf
Deploying Certificate to VirtualHost /etc/nginx/nginx.conf

Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the webserver 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): 2
Redirecting all traffic on port 80 to ssl in /etc/nginx/nginx.conf
Redirecting all traffic on port 80 to ssl in /etc/nginx/nginx.conf

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations! You have successfully enabled https://yoursitename.com and
https://www.yoursitename.com

You should test your configuration at:
https://www.ssllabs.com/ssltest/analyze.html?d=yoursitename.com
https://www.ssllabs.com/ssltest/analyze.html?d=www.yoursitename.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/yoursitename.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/yoursitename.com/privkey.pem
   Your cert will expire on 2019-02-19. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot again
   with the "certonly" option. To non-interactively renew *all* of
   your certificates, run "certbot renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

At this point, you should have a working certificate configured in Nginx.  A section of  /etc/nginx/nginx.conf configuration should look something like this:

    server {
    server_name www.yoursitename.com yoursitename.com; # managed by Certbot
        root         /usr/share/nginx/html;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
        
        }

        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }


    listen [::]:443 ssl ipv6only=on; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/yoursitename.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/yoursitename.com/privkey.pem; # 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 = www.yoursitename.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    if ($host = yoursitename.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


        listen       80 ;
        listen       [::]:80 ;
    server_name www.yoursitename.com yoursitename.com;
    return 404; # managed by Certbot

    }
}

Viewing Current Certificates

If you would like to inspect your certificates, do this:

user@host ~]$ sudo certbot certificates
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Found the following certs:
  Certificate Name: yoursitename.com
    Domains: yoursitename.com www.yoursitename.com
    Expiry Date: 2019-02-19 03:17:41+00:00 (VALID: 89 days)
    Certificate Path: /etc/letsencrypt/live/yoursitename.com/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/yoursitename.com/privkey.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Automating Certificate Updates

Be aware that Let's Encrypt only will give you certificates for 90 days. That's not a lot of time. The whole goal here is to automate this task. Using the guidance from the CertBot official docs [1], let's add a cron job that runs twice a day that can renew our certificate(s). It's important to note that an actual renewal will not happen until the certificate(s) have 30 days or less before expiration.

[user@host ~]$ echo "python -c 'import random; import time; time.sleep(random.random() * 3600)' && certbot renew" | sudo tee /etc/cron.daily/certbot_renew
[user@host cron.daily]# chmod +x /etc/cron.daily/certbot_renew

Verify that the daily file is accurate:

[user@host ~]$ cat /etc/cron.daily/certbot_renew
python -c 'import random; import time; time.sleep(random.random() * 3600)' && certbot renew

At this point, we should be all set. It's always prudent to check back from time to time that this task is running error free.  

References

  1. https://certbot.eff.org/lets-encrypt/centosrhel7-nginx