How to Secure Nginx with Let's Encrypt on Ubuntu 20.04

How to Secure Nginx with Let’s Encrypt on Ubuntu 20.04

Let’s Encrypt is developed by the Internet Security Research Group (ISRG). It is free and open an ssl certificate authority. The certificates, issued by Let’s Encrypt is trusted and suitable for almost all available browsers.

In this guide, we will instruct in detailed how to secure the Nginx web server with Let’s Encrypt using the certbot tool on Ubuntu 20.04.

Prerequisites 

To learn, Let’s Encrypt with certbot practically, you should have the following:
  1. A Ubuntu system installed with Nginx web server.
  2. A domain name hosted on Nginx and pointing to a public server IP. For this tutorial, we will use testsite.com.

Install Certbot

Certbot is a top-rated utility to use Let’s Encrypt ssl certificate. It is developed in Python to automate the process of obtaining and renewing SSL certificate by Let’s Encrypt and configuring on web servers.
 
To install certbot, first, need to install “software-properties-common” package.
 
To do this, update the Ubuntu package index and install “software-properties-common” using the following command:
# sudo apt update
# sudo apt install software-properties-common

After completion of the installation, add PPA repository for certbot to Ubuntu system using below command:

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

Now finally, install the certbot package after updating the package again:

# sudo apt update
# sudo apt install certbot

Generate Strong Dh (Diffie-Hellman) Group

Diffie-Hellman (DH) key exchange is a way of securely exchanging cryptographic keys over an unsecured communication channel. Create a new set of 2048 bit DH parameters to fortify the safety:
# sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

Here, we can also generate 4096 bit DH parameters by changing the size of 4096 in the above command. The only issue is there it will take a long time (more than 30 minutes) to generate, totally depending on our system resource.

Configuring a Let’s Encrypt SSL certificate

To configure an SSL certificate for our domain, we will use the Webroot plugin to creating a temporary file for validating domain in the “${webroot-path}/.well-known/acme-challenge.” directory. When we execute the command to generate a new SSL certificate for the requested domain, the Let’s Encrypt server will make an HTTP request to that temporary file to validate the domain resolves to the server where we are running certbot.
 
To make it simple for all Nginx configured domain, we can map all HTTP request for “.well-known/acme-challenge” to a single custom directory at location “/var/lib/letsencrypt”.
 
To create a directory for HTTP request and to make it writable with Nginx web server, we can use the following command:
# sudo mkdir -p /var/lib/letsencrypt/.well-known
# sudo chgrp www-data /var/lib/letsencrypt
# sudo chmod g+s /var/lib/letsencrypt
We should add these two snippets to avoid duplicate code, which we will add in our all Nginx server block files.
/etc/nginx/snippets/letsencrypt.conf
location ^~ /.well-known/acme-challenge/ {
  allow all;
  root /var/lib/letsencrypt/;
  default_type "text/plain";
  try_files $uri =404;
}

/etc/nginx/snippets/ssl.conf

ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
ssl_prefer_server_ciphers on;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 30s;
add_header Strict-Transport-Security "max-age=15768000; includeSubdomains; preload";
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
After creating the snippets, add “letsencrypt.conf” snippet into the domain server block as shown below:
/etc/nginx/sites-available/testsite.com.conf
server {
  listen 80;
  server_name testsite.com www.testsite.com;
  include snippets/letsencrypt.conf;
}

Now, activate the server block by making a symbolic link file of server block file from “sites-available” to “sites-enabled” directory, as shown below:

# sudo ln -s /etc/nginx/sites-available/testsite.com.conf /etc/nginx/sites-enabled/testsite.com.conf

Reload the Nginx service for changes to take effect

# sudo systemctl reload nginx

Now, we can run certbot with webroot plugin to create a new SSL certificate files for the requested domain:

# sudo certbot certonly --agree-tos --email admin@example.com --webroot -w /var/lib/letsencrypt/ -d testsite.com -d www.testsite.com

After creating an SSL certificate successfully, we will get the following output on the screen:

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/testsite.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/testsite.com/privkey.pem
   Your cert will expire on 2020-06-24. 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 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
Now we can include the newly generated certificate files in the domain server block file, as shown below:
/etc/nginx/sites-available/testsite.com.conf
server {
    listen 80;
    server_name www.testsite.com testsite.com;
    include snippets/letsencrypt.conf;
    return 301 https://$host$request_uri;
}
server {
    listen 443 ssl http2;
    server_name www.testsite.com;
    ssl_certificate /etc/letsencrypt/live/testsite.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/testsite.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/testsite.com/chain.pem;
    include snippets/ssl.conf;
    include snippets/letsencrypt.conf;
    return 301 https://testsite.com$request_uri;
}
server {
    listen 443 ssl http2;
    server_name testsite.com;
    ssl_certificate /etc/letsencrypt/live/testsite.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/testsite.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/testsite.com/chain.pem;
    include snippets/ssl.conf;
    include snippets/letsencrypt.conf;
    # . . . other code
}

In the above configuration, we are forcing the request to HTTPS and redirecting “www” version of domain to “non www” version. Again, reload Nginx service to take effect for above server block configurations:

# sudo systemctl reload nginx

Let’s Encrypt SSL certificate auto renewal

The SSL certificates provided by Let’s Encrypt is valid for 90 days. The Certbot providing a tool to auto-renewal SSL certificate before expire, to use this cron job tool need to creates a cron job which will run in a day and it will renew the certificate 30 days before its expiration. As we are using the webroot plugin after renewing the SSL certificate we need to reload Nginx service.
 
So, we can include “—renew-hook “ systemctl reload nginx” into the cron job so it will automatically reload the Nginx service after the renewal of SSL certificate.
/etc/cron.d/certbot
0 */12 * * * root test -x /usr/bin/certbot -a ! -d /run/systemd/system && perl -e 'sleep int(rand(3600))' && certbot -q renew --renew-hook "systemctl reload nginx"

You can check the renewal process by executing below command (certbot with –dry-run):

# sudo certbot renew --dry-run

If there is no error prompted on-screen after running above command, means renewal process was successful and your configuration is good to go for auto-renewal of SSL certificates.

Conclusion

In this tutorial, we have learned about Let’s Encrypt and certbot. We learn to use certbot to create an SSL certificate; also, we have created Nginx snippets to avoid code duplication. We configured Nginx server block to use Let’s Encrypt SSL certificate and also learn how to set a cronjob for autorenewal of Let’s Encrypt certificates.
 
The certbot is used by almost all enginers to create an SSL certificate; If you want to know more about certbot, you should start from the certbot’s documentation.

0 Comments

Submit a Comment

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

Related Articles