hieuvnlabs logo
Hiusvu

How To Secure Nginx with a Free Let's Encrypt SSL Certificate on Ubuntu

Published on September 4, 2026

How To Secure Nginx with a Free Let's Encrypt SSL Certificate on Ubuntu

Introduction

Let's Encrypt is a Certificate Authority that provides free, automated SSL/TLS certificates. With the Certbot client you can obtain a certificate, configure Nginx and set up automatic renewal in a few minutes.

In this guide we will use Certbot to obtain an SSL certificate for a domain served by Nginx on Ubuntu, then verify that automatic renewal works.

Prerequisites

To follow this tutorial, you need:

  • An Ubuntu 20.04 or 22.04 server with a sudo user and the ufw firewall enabled.
  • A registered domain name. This guide uses your_domain as an example; replace it with your own.
  • Two DNS records pointing at your server's public IP: an A record for your_domain and an A record for www.your_domain.
  • Nginx installed with a server block for your_domain. If you have not done that yet, see How To Install Nginx on Ubuntu.

Step 1 — Installing Certbot

Certbot is under very active development, so the package in Ubuntu's default repository tends to be outdated. The recommended way to install it today is through snap, which ships with Ubuntu.

Make sure snapd is up to date:

sudo snap install core; sudo snap refresh core

If you previously installed Certbot through apt, remove it to avoid conflicts:

sudo apt remove certbot

Install Certbot:

sudo snap install --classic certbot

Link the certbot command so it can be run from anywhere:

sudo ln -s /snap/bin/certbot /usr/bin/certbot

Check it:

certbot --version
Output
certbot 2.9.0

Step 2 — Confirming Nginx's Configuration

Certbot needs to find the correct server block in your Nginx configuration to configure SSL automatically. It does that by looking for a server_name directive that matches the domain you request a certificate for.

Open the server block file for your domain:

sudo nano /etc/nginx/sites-available/your_domain

Find the server_name line and make sure it looks like this:

...
server_name your_domain www.your_domain;
...

If it does, exit the editor. If you had to change it, test the syntax and reload Nginx:

sudo nginx -t
sudo systemctl reload nginx

Step 3 — Allowing HTTPS Through the Firewall

If ufw is enabled, check its current status:

sudo ufw status
Output
Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
Nginx HTTP                 ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)
Nginx HTTP (v6)            ALLOW       Anywhere (v6)

Only HTTP (port 80) is open. To allow HTTPS (port 443) as well, enable the Nginx Full profile and remove the now redundant Nginx HTTP profile:

sudo ufw allow 'Nginx Full'
sudo ufw delete allow 'Nginx HTTP'

Check again:

sudo ufw status
Output
Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
Nginx Full                 ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)
Nginx Full (v6)            ALLOW       Anywhere (v6)

Step 4 — Obtaining an SSL Certificate

Certbot offers several ways to obtain a certificate. The Nginx plugin reconfigures Nginx and reloads it whenever necessary. Run the following, listing every domain you want covered with -d flags:

sudo certbot --nginx -d your_domain -d www.your_domain

On the first run Certbot asks for your email address (for expiry notices) and asks you to agree to the terms of service. It then contacts the Let's Encrypt server and runs a challenge to verify that you control the domain before issuing the certificate.

If everything succeeds, you will see something like:

Output
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/your_domain/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/your_domain/privkey.pem
This certificate expires on 2026-12-03.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.

Deploying certificate
Successfully deployed certificate for your_domain to /etc/nginx/sites-enabled/your_domain
Successfully deployed certificate for www.your_domain to /etc/nginx/sites-enabled/your_domain
Congratulations! You have successfully enabled HTTPS on https://your_domain and https://www.your_domain

Certbot has edited your server block: it added listen 443 ssl, the certificate paths, and a block that redirects all HTTP traffic to HTTPS. Open the configuration to see the result:

sudo cat /etc/nginx/sites-available/your_domain
server {
    server_name your_domain www.your_domain;
    root /var/www/your_domain/html;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }

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

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

    listen 80;
    listen [::]:80;
    server_name your_domain www.your_domain;
    return 404; # managed by Certbot
}

Open https://your_domain in your browser. You should see the padlock icon in the address bar. For a deeper check, run the Qualys SSL Labs Server Test; Certbot's default configuration usually scores an A.

Step 5 — Verifying Automatic Renewal

Let's Encrypt certificates are valid for 90 days, which is meant to encourage automated renewal. The snap-installed Certbot ships a systemd timer that runs twice a day and renews any certificate that is within 30 days of expiry.

Check that the timer is active:

sudo systemctl list-timers | grep certbot
Output
Thu 2026-09-04 23:07:00 UTC  9h left  Thu 2026-09-04 11:07:00 UTC  3h ago  snap.certbot.renew.timer  snap.certbot.renew.service

To be sure renewal works, do a dry run (nothing is actually renewed):

sudo certbot renew --dry-run
Output
Saving debug log to /var/log/letsencrypt/letsencrypt.log

Processing /etc/letsencrypt/renewal/your_domain.conf
Simulating renewal of an existing certificate for your_domain and www.your_domain

Congratulations, all simulated renewals succeeded:
  /etc/letsencrypt/live/your_domain/fullchain.pem (success)

If you see no errors, you are done. When the time comes, Certbot renews the certificate and reloads Nginx to pick up the new one. If renewal ever fails, Let's Encrypt emails a warning to the address you provided before the certificate expires.

Useful Certbot Commands

List the certificates issued on this server:

sudo certbot certificates

Add a new domain to an existing certificate:

sudo certbot --nginx -d your_domain -d www.your_domain -d blog.your_domain

Revoke and delete a certificate:

sudo certbot delete --cert-name your_domain

Conclusion

You have installed Certbot, obtained a free SSL certificate from Let's Encrypt, configured Nginx to redirect to HTTPS and confirmed automatic renewal. Your entire site is now encrypted at no cost. If you run into trouble, check the log at /var/log/letsencrypt/letsencrypt.log.