Secure Nginx with Let’s Encrypt on Ubuntu 20.04

s2 0

Let’s Encrypt is a free, automated and open certification authority developed by the Internet Security Research Group (ISRG) that provides free SSL certificates.

Certificates issued by Let’s Encrypt are classified as trustworthy by all common browsers and are valid for 90 days from the date of issue.

This tutorial explains how to install a free Let’s Encrypt SSL certificate on Ubuntu 20.04 that is running Nginx as a web server. We’ll also show how to configure Nginx to use the SSL certificate and enable HTTP / 2.


Before proceeding, make sure that you meet the following requirements:

  • You have a domain name that points to your public IP. We use
  • You have installed Nginx on your CentOS server.
  • Your firewall is configured to accept connections on ports 80 and 443.

Install Certbot

We use certbot to get and renew the certificates.

Certbot is a fully featured and easy-to-use tool that automates the tasks of getting and renewing Let’s Encrypt SSL certificates and configuring web servers to use the certificates.

The certbot package is included in the standard Ubuntu repositories. To install it, run the following commands:

sudo apt updatesudo apt install certbot

Generate a strong Dh (Diffie-Hellman) group

The Diffie-Hellman key exchange (DH) is a method for the secure exchange of cryptographic keys via an unsecured communication channel.

Generate a new set of 2048-bit DH parameters by entering the following command:

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

You can also use a key length of up to 4096 bits, but the generation can take longer than 30 minutes depending on the system entropy.

Obtaining a Let’s Encrypt SSL Certificate

To get an SSL certificate for the domain we use the webroot plugin which creates a temporary file to validate the requested domain in the ${webroot-path}/.well-known/acme-challenge Directory. The Let’s Encrypt server makes HTTP requests to the temporary file to check whether the requested domain is resolved to the server on which certbot is running.

To make it easier, we’re going to map all HTTP requests for .well-known/acme-challenge in a single directory, /var/lib/letsencrypt.

The following commands create the directory and make it writable for the Nginx server:

sudo mkdir -p /var/lib/letsencrypt/.well-knownsudo chgrp www-data /var/lib/letsencryptsudo chmod g+s /var/lib/letsencrypt

To avoid duplicating code, let’s create two snippets and paste them into all of the Nginx server block files.

Open your text editor and create the first snippet, letsencrypt.conf:

sudo nano /etc/nginx/snippets/letsencrypt.conf
location ^~ /.well-known/acme-challenge/ {
  allow all;
  root /var/lib/letsencrypt/;
  default_type "text/plain";
  try_files $uri =404;

Next, create the second snippet, ssl.conf, including that of. recommended chopper Mozilla
, enables OCSP stapling, HTTP Strict Transport Security (HSTS) and enforces few security-related HTTP headers.

sudo nano /etc/nginx/snippets/ssl.conf
ssl_dhparam /etc/ssl/certs/dhparam.pem;

ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;

ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;

ssl_stapling on;
ssl_stapling_verify on;
resolver valid=300s;
resolver_timeout 30s;

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;

Once the snippets are created, open the domain server’s block file and paste the letsencrypt.conf Cutout as shown below:

sudo nano /etc/nginx/sites-available/
server {
  listen 80;

  include snippets/letsencrypt.conf;

To activate the new server block, create a symbolic link from the file to the sites-enabled Directory:

sudo ln -s /etc/nginx/sites-available/ /etc/nginx/sites-enabled/

Restart the Nginx service for the changes to take effect:

sudo systemctl restart nginx

You can now run Certbot with the Webroot plugin and get the SSL certificate files by issuing:

sudo certbot certonly --agree-tos --email [email protected] --webroot -w /var/lib/letsencrypt/ -d -d

When the SSL certificate is successfully obtained, certbot prints the following message:

 - Congratulations! Your certificate and chain have been saved at:
   Your key file has been saved at:
   Your cert will expire on 2020-10-18. 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"
 - 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:
   Donating to EFF:          

Now that you have the certificate files, you can edit your domain server block as follows:

sudo nano /etc/nginx/sites-available/
server {
    listen 80;

    include snippets/letsencrypt.conf;
    return 301 https://$host$request_uri;

server {
    listen 443 ssl http2;

    ssl_certificate /etc/letsencrypt/live/;
    ssl_certificate_key /etc/letsencrypt/live/;
    ssl_trusted_certificate /etc/letsencrypt/live/;
    include snippets/ssl.conf;
    include snippets/letsencrypt.conf;

    return 301$request_uri;

server {
    listen 443 ssl http2;

    ssl_certificate /etc/letsencrypt/live/;
    ssl_certificate_key /etc/letsencrypt/live/;
    ssl_trusted_certificate /etc/letsencrypt/live/;
    include snippets/ssl.conf;
    include snippets/letsencrypt.conf;

    # . . . other code

With the configuration above, we’re enforcing HTTPS and redirecting from www to a non-www version.

Reload the Nginx service for the changes to take effect:

sudo systemctl reload nginx

To check that the SSL certificate has been successfully installed, open your website with https://, and you’ll see a green lock icon.

If you have your domain with the. testing SSL Labs server test
, you get one A+ Class as shown in the picture below:

Automatic renewal of the Let’s Encrypt SSL certificate

Let’s Encrypt certificates are valid for 90 days. In order to automatically renew the certificates before they expire, the certbot package creates a cron job and a systemd timer. The timer automatically renews the certificates 30 days before they expire.

When the certificate is renewed, the nginx service must be reloaded. Open that /etc/letsencrypt/cli.ini and add the following line:

sudo nano /etc/letsencrypt/cli.ini
deploy-hook = systemctl reload nginx

To test the renewal process, run the certbot. the end --dry-run Command:

sudo certbot renew --dry-run

If there are no errors, it means that the renewal process was successful.


We showed you how to use the certbot Let’s Encrypt to download SSL certificates for your domain. We also created Nginx snippets to avoid duplicating code and configured Nginx to use the certificates.

To learn more about using Certbot, visit theirs documentation

If you have any questions or feedback, please feel free to leave a comment.