In this tutorial, we’re going to see how to install a TLS/SSL certificate on a webserver using Nginx on Ubuntu 16.04. We’ll use a Let’s Encrypt certificate. This is a little be more difficult than doing the same thing on a Apache webserver, but it’s still totally doable! Note that, as usual, this whole tutorial should be followed by simply replacing example.com by your own domain name.

1. First, be sure to create an A Record that points your domain to the public IP address of your server. Both for example.com and www.example.com.

2.  Update your server:

sudo apt-get update

3. Install the following package:

sudo apt-get install letsencrypt

4. In order to obtain an SSL certificate, we’ll use the Webroot plugin. This plugin works by placing a special file in the /.well-known directory of your website Nginx configuration file. Let’s Encrypt will use it to validate your request to issue a cerficate. Open your virtual host file:

sudo nano /etc/nginx/sites-available/example.com

5. Inside your server block, add this location block:

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

6. Note your document root, as it will be required by the Webroot plugin. Here we use the path /var/www/example.com.

7. Save and exit.

8. Run this command in order to check your configuration for syntax errors:

sudo nginx -t

9. If no syntax error is found, you can restart Nginx:

sudo systemctl restart nginx

10. It’s time to request an SSL certificate, by running the following command:

letsencrypt certonly –webroot -w /var/www/example/public_html -d example.com -d www.example.com -w /var/www/thing/public_html -d thing.is -d m.thing.is

11. When prompted, enter an email address and agree to the TOS. Note the expiration date of the certificate.

12. For a greater security of your web server, we’ll generate a Diffie-Hellman group. Use this command to generate a 2048-bit group:

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

Note that the process can take a little while. The DH group will be created at /etc/ssl/certs/dhparam.pem.

13. We’ll create a new Nginx configuration snippet in the /etc/nginx/snippets directory.

sudo nano /etc/nginx/snippets/ssl-example.com.conf

14. In this file, we set the ssl_certificate directive to the certificate file and the ssl_certificate_key to the associated key. In our case, this will look like this:

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

15. Save and close the file.

16. Next, we will create another snippet that will define some SSL settings. This will set Nginx up with a strong SSL cipher suite and enable some advanced features that will help keep our server secure. The parameters we will set can be reused in future Nginx configurations, so we will give the file a generic name:

sudo nano /etc/nginx/snippets/ssl-params.conf

17. To set up Nginx SSL securely, we will be using the recommendations by Remy van Elst on the Cipherli.stsite. Copy and paste the following before saving the file:

# from https://cipherli.st/
# and https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# Disable preloading HSTS for now.  You can use the commented out header line that includes
# the "preload" directive if you understand the implications.
#add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

ssl_dhparam /etc/ssl/certs/dhparam.pem;

18. Before we go any further, let’s back up our current server block file:

cp /etc/nginx/sites-available/example.com /etc/nginx/sites-available/example.com.bak

19. Open the server block file to make adjustments:

nano /etc/nginx/sites-available/example.com

20. We will be splitting the configuration into two separate blocks. After the two first listen directives, we will add a server_name directive, set to your server’s domain name. We will then set up a redirect to the second server block we will be creating. Afterwards, we will close this short block:

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name example.com www.example.com;
    return 301 https://$server_name$request_uri;
}

    # SSL configuration

    # listen 443 ssl default_server;
    # listen [::]:443 ssl default_server;

    . . .

21. Next, we need to start a new server block directly below to contain the remaining configuration. We can uncomment the two listen directives that use port 443. We can add http2 to these lines in order to enable HTTP/2 within this block. Afterwards, we just need to include the two snippet files we set up:

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name example.com www.example.com;
    return 301 https://$server_name$request_uri;
}

server {

    # SSL configuration

    listen 443 ssl http2 default_server;
    listen [::]:443 ssl http2 default_server;
    include snippets/ssl-example.com.conf;
    include snippets/ssl-params.conf;

    . . .

22. Save and close the file when you are finished.

Example of the configuration file:

server {
        listen 80;
        listen [::]:80;
        server_name example.com www.example.com;
        return 301 https://$server_name$request_uri;

        root /var/www/example.com/public_html;
        index index.php index.html;

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

        location / {
                try_files $uri $uri/ /index.php?$args;
        }
        location ~ \.php$ {
                include snippets/fastcgi-php.conf;
                include fastcgi_params;
                fastcgi_pass unix:/run/php/php7.0-fpm.sock;
                fastcgi_param SCRIPT_FILENAME /var/www/example.com/public_html$fastcgi_script_name;
        }
}

server {
        listen 443 ssl http2 default_server;
        listen [::]:443 ssl http2 default_server;
        include snippets/ssl-example.com.conf;
        include snippets/ssl-params.conf;
        server_name example.com www.example.com;
        root /var/www/example.com/public_html;
        index index.php index.html;
        location ~ /.well-known {
                allow all;
        }
        location / {
                try_files $uri $uri/ /index.php?$args;
        }
        location ~ \.php$ {
                include snippets/fastcgi-php.conf;
                include fastcgi_params;
                fastcgi_pass unix:/run/php/php7.0-fpm.sock;
                fastcgi_param SCRIPT_FILENAME /var/www/example.com/public_html$fastcgi_script_name;
        }
}

23. Check that there are no syntax errors in the files:

sudo nginx -t

24. If the configuration is correct, restart Nginx:

sudo systemctl restart nginx

25. A practical way to ensure your certificates won’t get outdated is to create a cron job that will periodically execute the automatic renewal command for you. To edit the crontab for the root user, run:

sudo crontab -e

26. Add the following lines:

30 2 * * 1 /usr/bin/letsencrypt renew >> /var/log/le-renew.log
35 2 * * 1 /bin/systemctl reload nginx

26. Save and exit.

That’s it, you have everything set up to offer your customers a properly encrypted connection when they surf your site!

If you’re a website owner and you would like we implement a SSL/TLS certificate for you, don’t hesitate to contact us. We’ll be happy to offer you a range of services, including Let’s Encrypt certificates but also certificates provided by other institutions (such as Symantec).