How To Secure Nginx with Let's Encrypt on Ubuntu 14.04
How To Secure Nginx with Let's Encrypt on Ubuntu 14.04
We hope you find this tutorial helpful. In addition to guides like this one, we provide simple cloud infrastructure for developers. Learn more →

How To Secure Nginx with Let's Encrypt on Ubuntu 14.04

PostedDecember 17, 2015 561.3k views Nginx Security Let's Encrypt Ubuntu

Introduction

Let's Encrypt is a new Certificate Authority (CA) that provides an easy way to obtain and install free TLS/SSL certificates, thereby enabling encrypted HTTPS on web servers. It simplifies the process by providing a software client, certbot, that attempts to automate most (if not all) of the required steps. Currently, the entire process of obtaining and installing a certificate is fully automated only on Apache web servers. However, Let's Encrypt can be used to easily obtain a free SSL certificate, which can be installed manually, regardless of your choice of web server software.

In this tutorial, we will show you how to use the Let's Encrypt client to obtain a free SSL certificate and use it with Nginx on Ubuntu 14.04. We will also show you how to automatically renew your SSL certificate. If you're running a different web server, simply follow your web server's documentation to learn how to use the certificate with your setup.

Nginx with Let's Encrypt TLS/SSL Certificate and Auto-renewal

Prerequisites

Before following this tutorial, you'll need a few things.

You should have an Ubuntu 14.04 server with a non-root user who has sudo privileges. You can learn how to set up such a user account by following steps 1-3 in our initial server setup for Ubuntu 14.04 tutorial.

You must own or control the registered domain name that you wish to use the certificate with. If you do not already have a registered domain name, you may register one with one of the many domain name registrars out there (e.g. Namecheap, GoDaddy, etc.).

If you haven't already, be sure to create an A Record that points your domain to the public IP address of your server. This is required because of how Let's Encrypt validates that you own the domain it is issuing a certificate for. For example, if you want to obtain a certificate for example.com, that domain must resolve to your server for the validation process to work. Our setup will use example.com and www.example.com as the domain names, so both DNS records are required.

Once you have all of the prerequisites out of the way, let's move on to installing Certbot, the Let's Encrypt client software.

Step 1 — Install Certbot

The first step to using Let's Encrypt to obtain an SSL certificate is to install the certbot software on your server. The Certbot developers maintain their own Ubuntu software repository with up-to-date versions of the software. Because Certbot is in such active development it's worth using this repository to install a newer Certbot than provided by Ubuntu.

First, add the repository:

  • sudo add-apt-repository ppa:certbot/certbot

You'll need to press ENTER to accept. Afterwards, update the package list to pick up the new repository's package information:

  • sudo apt-get update

And finally, install Certbot with apt-get:

  • sudo apt-get install certbot

The certbot Let's Encrypt client is now ready to use.

Step 2 — Obtain a Certificate

Let's Encrypt provides a variety of ways to obtain SSL certificates, through various plugins. Unlike the Apache plugin, which is covered in a different tutorial, most of the plugins will only help you with obtaining a certificate which you must manually configure your web server to use. Plugins that only obtain certificates, and don't install them, are referred to as "authenticators" because they are used to authenticate whether a server should be issued a certificate.

We'll show you how to use the Webroot plugin to obtain an SSL certificate.

How To Use the Webroot Plugin

The Webroot plugin works by placing a special file in the /.well-known directory within your document root, which can be accessed (through your web server) by the Let's Encrypt servers for validation. Depending on your configuration, you may need to explicitly allow access to the /.well-known directory.

If you haven't installed Nginx yet, do so with this command:

  • sudo apt-get install nginx

To ensure that the directory is accessible to certbot for validation, let's make a quick change to our Nginx configuration. By default, it's located at /etc/nginx/sites-available/default. We'll use nano to edit it:

  • sudo nano /etc/nginx/sites-available/default

Inside the server block, add this location block:

Add to SSL server block
server {
        . . .

        location ~ /.well-known {
                allow all;
        }

        . . .
}

You will also want look up what your document root is set to by searching for the root directive, as the path is required to use the Webroot plugin. If you're using the default configuration file, the root will be /usr/share/nginx/html.

Save and exit.

Check the configuration file for syntax errors:

  • sudo nginx -t

If all is well, restart Nginx with this command:

  • sudo service nginx restart

Now that we know our webroot-path, we can use the Webroot plugin to request an SSL certificate with these commands. Here, we are also specifying our domain names with the -d option. If you want a single cert to work with multiple domain names (e.g. example.com and www.example.com), be sure to include all of them, starting with the most high level domain (e.g. example.com). Also, make sure that you replace the highlighted parts with the appropriate webroot path and domain name(s):

  • certbot certonly --webroot --webroot-path=/usr/share/nginx/html -d example.com -d www.example.com

Note: The certbot software requires superuser privileges, so you will be required to enter your password if you haven't used sudo recently.

If this is your first time running certbot, you will be prompted to enter an email address and agree to the terms of service. After doing so, you should see a message telling you the process was successful and where your certificates are stored:

Output
IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at /etc/letsencrypt/live/example.com/fullchain.pem. Your cert will expire on 2017-07-26. To obtain a new or tweaked version of this certificate in the future, simply run certbot again. To non-interactively renew *all* of your certificates, run "certbot renew" - If you lose your account credentials, you can recover through e-mails sent to sammy@example.com. - Your account credentials have been saved in your Certbot configuration directory at /etc/letsencrypt. You should make a secure backup of this folder now. This configuration directory will also contain certificates and private keys obtained by Certbot so making regular backups of this folder is ideal. - 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

You will want to note the path and expiration date of your certificate, highlighted in the example above.

Firewall Note: If you receive an error like Failed to connect to host for DVSNI challenge, your server's firewall may need to be configured to allow TCP traffic on port 80 and 443.

Note: If your domain is routing through a DNS service like CloudFlare, you will need to temporarily disable it until you have obtained the certificate.

Certificate Files

After obtaining the cert, you will have the following PEM-encoded files:

  • cert.pem: Your domain's certificate
  • chain.pem: The Let's Encrypt chain certificate
  • fullchain.pem: cert.pem and chain.pem combined
  • privkey.pem: Your certificate's private key

It's important that you are aware of the location of the certificate files that were just created, so you can use them in your web server configuration. The files themselves are placed in a subdirectory in /etc/letsencrypt/archive. However, Certbot creates symbolic links to the most recent certificate files in the /etc/letsencrypt/live/your_domain_name directory. Because the links will always point to the most recent certificate files, this is the path that you should use to refer to your certificate files.

You can check that the files exist by running this command (substituting in your domain name):

  • sudo ls -l /etc/letsencrypt/live/your_domain_name

The output should be the four previously mentioned certificate files. In a moment, you will configure your web server to use fullchain.pem as the certificate file, and privkey.pem as the certificate key file.

Generate Strong Diffie-Hellman Group

To further increase security, you should also generate a strong Diffie-Hellman group. To generate a 2048-bit group, use this command:

  • sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

This may take a few minutes but when it's done you will have a strong DH group at /etc/ssl/certs/dhparam.pem.

Step 3 — Configure TLS/SSL on Web Server (Nginx)

Now that you have an SSL certificate, you need to configure your Nginx web server to use it.

Edit the Nginx configuration that contains your server block. Again, it's at /etc/nginx/sites-available/default by default:

  • sudo nano /etc/nginx/sites-available/default

Find the server block. Comment out or delete the lines that configure this server block to listen on port 80. In the default configuration, these two lines should be deleted:

Nginx configuration deletions
        listen 80 default_server;
        listen [::]:80 default_server ipv6only=on;

We are going to configure this server block to listen on port 443 with SSL enabled instead. Within your server { block, add the following lines but replace all of the instances of example.com with your own domain:

Nginx configuration additions — 1 of 3
        listen 443 ssl;

        server_name example.com www.example.com;

        ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

This enables your server to use SSL, and tells it to use the Let's Encrypt SSL certificate that we obtained earlier.

To allow only the most secure SSL protocols and ciphers, and use the strong Diffie-Hellman group we generated, add the following lines to the same server block:

Nginx configuration additions — 2 of 3
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        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';
        ssl_session_timeout 1d;
        ssl_session_cache shared:SSL:50m;
        ssl_stapling on;
        ssl_stapling_verify on;
        add_header Strict-Transport-Security max-age=15768000;

Lastly, outside of the original server block (that is listening on HTTPS, port 443), add this server block to redirect HTTP (port 80) to HTTPS. Be sure to replace the highlighted part with your own domain name:

Nginx configuration additions — 3 of 3
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}

Save and exit.

Test the configuration file for syntax errors by typing:

  • sudo nginx -t

Once you have verified that there are no syntax errors, put the changes into effect by restarting Nginx:

  • sudo service nginx restart

The Let's Encrypt TLS/SSL certificate is now in place. At this point, you should test that the TLS/SSL certificate works by visiting your domain via HTTPS in a web browser.

You can use the Qualys SSL Labs Report to see how your server configuration scores:

In a web browser:
https://www.ssllabs.com/ssltest/analyze.html?d=example.com

This SSL setup should report an A+ rating.

Step 4 — Set Up Auto Renewal

Let's Encrypt's certificates are only valid for ninety days. This is to encourage users to automate their certificate renewal process. We'll need to set up a regularly run command to check for expiring certificates and renew them automatically.

To run the renewal check daily, we will use cron, a standard system service for running periodic jobs. We tell cron what to do by opening and editing a file called a crontab.

  • sudo crontab -e

Your text editor will open the default crontab which is a text file with some help text in it. Paste in the following line at the end of the file, then save and close it:

crontab
. . .
15 3 * * * /usr/bin/certbot renew --quiet --renew-hook "/usr/sbin/service nginx reload"

The 15 3 * * * part of this line means "run the following command at 3:15 am, every day". You may choose any time.

The renew command for Certbot will check all certificates installed on the system and update any that are set to expire in less than thirty days. --quiet tells Certbot not to output information nor wait for user input. --renew-hook "/usr/sbin/service nginx reload" will reload Nginx to pick up the new certificate files, but only if a renewal has actually happened.

cron will now run this command daily. All installed certificates will be automatically renewed and reloaded when they have thirty days or less before they expire.

For more information on how to create and schedule cron jobs, you can check our How to Use Cron to Automate Tasks in a VPS guide.

Conclusion

That's it! Your web server is now using a free Let's Encrypt TLS/SSL certificate to securely serve HTTPS content.

216 Comments

Creative Commons License