How to Secure Nginx with Let’s Encrypt on Ubuntu 26.04, 24.04 and 22.04

Last updated Wednesday, May 6, 2026 3:38 pm Joshua James 7 min read

An HTTP-only Nginx site leaves logins, cookies, and form traffic exposed on every hop between the browser and your server. The fastest way to secure Nginx with Let’s Encrypt on Ubuntu is Certbot’s Nginx plugin, which requests the certificate, updates the server block, and enables automatic renewal from Ubuntu’s own packages.

These steps cover Ubuntu 26.04, 24.04, and 22.04 with the same package names and the same Nginx plugin workflow. The main differences are the Certbot versions each LTS carries, while the actual install, issuance, renewal, and cleanup flow stays consistent.

Secure Nginx with Let’s Encrypt on Ubuntu

Before Certbot can issue anything, Nginx has to already answer for your domain over plain HTTP. Start with the preflight checks, then install Certbot and request the certificate against the live site.

This workflow assumes you control the Ubuntu server and its Nginx server block directly. If Nginx Proxy Manager, a hosting panel, a CDN, or a load balancer terminates TLS first, configure the certificate at that layer instead of running these Certbot and Nginx commands on the origin host.

Check the Nginx and DNS prerequisites on Ubuntu

Make sure these pieces are already in place before you request the certificate:

  • Nginx is installed and running. If you still need the web server itself, use the guide to install Nginx on Ubuntu first.
  • Your domain’s A or AAAA record already points to this server.
  • Your Nginx site uses the real domain in its server_name directive on port 80.
  • Ports 80 and 443 are reachable. If you manage access with UFW, open the web profile first with the guide to install and configure UFW firewall on Ubuntu.

Let’s Encrypt’s HTTP-01 challenge validates your domain over port 80. That challenge cannot issue wildcard certificates, so wildcard requests need DNS-01 instead of the Nginx plugin alone.

Update Ubuntu and install Certbot for Nginx

Refresh package metadata first so Certbot and the Nginx plugin come from the current Ubuntu repositories:

sudo apt update && sudo apt upgrade -y

These commands use sudo for tasks that need root privileges. If your account is not in the sudoers file yet, follow the guide to add a new user to sudoers on Ubuntu before continuing.

Install Certbot, the Nginx integration package, and curl for the HTTP checks used later:

sudo apt install certbot python3-certbot-nginx curl -y

On Ubuntu 26.04, 24.04, and 22.04, the APT package name for Certbot’s Nginx plugin is python3-certbot-nginx from Ubuntu’s universe component. If a customized server cannot find that package, enable Universe on Ubuntu, refresh APT, and retry the install command.

Certbot’s official Nginx on Linux Snap instructions are useful when you want the upstream Snap channel instead, but keep one Certbot install path per server so certificate files, renewal jobs, and plugin ownership stay predictable.

Confirm that Certbot is available:

certbot --version
certbot 4.0.0

Ubuntu 26.04 currently ships Certbot 4.0.0, Ubuntu 24.04 ships 2.9.0, and Ubuntu 22.04 ships 1.21.0. All three releases also ship the python3-certbot-nginx plugin and support the redirect, staging, dry-run, HSTS, and OCSP-stapling options referenced here.

Verify the Nginx site before requesting the certificate

Certbot will refuse to edit a broken Nginx configuration, so check the config and service state before you start:

sudo nginx -t
systemctl is-active nginx
systemctl is-enabled nginx
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
active
enabled

If the syntax test fails or the service is inactive, fix that first. Certbot’s Nginx installer expects a working port 80 server block that already matches your domain with server_name example.com www.example.com;.

For a local server-block check, send the intended hostname to Nginx instead of testing the bare loopback address. A default welcome page here usually means the wrong server block is answering:

curl -fsSI -H 'Host: example.com' http://127.0.0.1/

Request the Let’s Encrypt certificate for your Nginx site

Use the Nginx plugin so Certbot can issue the certificate and rewrite the matching server block in one pass:

sudo certbot --nginx --agree-tos --redirect --email admin@example.com -d example.com -d www.example.com

Each flag changes a different part of the deployment:

OptionWhat it changes
--nginxUses the Nginx plugin for both validation and configuration edits.
--agree-tosAccepts Let’s Encrypt’s subscriber agreement without an extra prompt.
--redirectAdds the HTTP to HTTPS redirect automatically.
--emailRegisters the certificate contact email for expiry and security notices.
-dLists every hostname you want on the same certificate.

A successful run prints the certificate and deployment paths:

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/example.com/privkey.pem
These files will be updated when the certificate renews.
Deploying certificate
Successfully deployed certificate for example.com to /etc/nginx/sites-enabled/example.com.conf
Successfully deployed certificate for www.example.com to /etc/nginx/sites-enabled/example.com.conf

Check the issued certificate and HTTPS redirect

After the certificate is in place, ask Certbot to show the active certificate set:

sudo certbot certificates

Relevant lines include the certificate name, domain list, and live file paths:

Found the following certs:
  Certificate Name: example.com
    Domains: example.com www.example.com
    Certificate Path: /etc/letsencrypt/live/example.com/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/example.com/privkey.pem

You can also test the redirect itself from the command line with curl:

curl -fsSI http://example.com
HTTP/1.1 301 Moved Permanently
Location: https://example.com/

Add HSTS and OCSP stapling after HTTPS works

Keep the first certificate request focused on issuance and the redirect. After HTTPS works for every hostname on the certificate, rerun Certbot against the same domains to harden the existing Nginx configuration with HSTS and OCSP stapling:

sudo certbot enhance --nginx --hsts --staple-ocsp -d example.com -d www.example.com

HSTS tells browsers to keep using HTTPS for the domain. Enable it only after the certificate, redirect, and subdomain coverage are correct, because browsers can remember that policy after a misconfiguration.

After the certificate, redirect, HSTS, and OCSP stapling are working, continue with broader Nginx hardening such as configuring security headers in Nginx and rate limiting in Nginx.

Renew Let’s Encrypt certificates on Ubuntu

Let’s Encrypt certificates are short-lived by design, so renewal matters just as much as the first request. Ubuntu’s package already installs a systemd timer for that job.

Test Certbot renewal on Ubuntu

Run a dry run now so you know whether the renewal path works before the real expiry window arrives:

sudo certbot renew --dry-run

Before the first certificate exists, Ubuntu shows this:

No simulated renewals were attempted.

After at least one real certificate exists, the same command should simulate renewal and end with a success summary like this:

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Processing /etc/letsencrypt/renewal/example.com.conf
Simulating renewal of an existing certificate for example.com and www.example.com
Congratulations, all simulated renewals succeeded:
  /etc/letsencrypt/live/example.com/fullchain.pem (success)

Confirm the automatic certbot.timer service on Ubuntu

Ubuntu enables the renewal timer when you install Certbot, so you do not need to add a manual cron job:

systemctl is-enabled certbot.timer
systemctl is-active certbot.timer
enabled
active

If either check fails, bring the timer back with sudo systemctl enable --now certbot.timer and rerun the two status checks.

Update Certbot on Ubuntu

Keep the Certbot packages current through normal APT updates so renewal fixes and ACME changes arrive with the rest of your Ubuntu patch cycle:

sudo apt update
sudo apt install --only-upgrade certbot python3-certbot-nginx -y

Troubleshoot Let’s Encrypt and Nginx on Ubuntu

Most Certbot failures come from DNS, a mismatched Nginx server block, or testing the wrong renewal state. Start with the exact error Certbot prints, then work through the matching fix below.

Fix DNS or HTTP-01 validation failures on Ubuntu

If Let’s Encrypt cannot reach the challenge URL, Certbot usually fails with an unauthorized or missing-record error:

Challenge failed for domain example.com
IMPORTANT NOTES:
 - The following errors were reported by the server:
   Domain: example.com
   Type:   unauthorized
   Detail: Invalid response from http://example.com/.well-known/acme-challenge/...

Check DNS first, then make sure the host is actually answering over port 80:

getent ahostsv4 example.com
curl -fsSI http://example.com
203.0.113.10    STREAM example.com
203.0.113.10    DGRAM
203.0.113.10    RAW
HTTP/1.1 200 OK

If the IP is wrong, fix DNS and wait for propagation. If the site is unreachable, open port 80 in your firewall and make sure Nginx is serving the same hostname you passed to Certbot.

Fix Nginx server block matching errors on Ubuntu

The Nginx installer plugin only edits server blocks that already declare the requested hostname. When it cannot find one, the error normally looks like this:

Could not automatically find a matching server block for example.com. Set the server_name directive to use the Nginx installer.

Add the real hostname to the port 80 site config, test the syntax, and reload Nginx:

server {
    listen 80;
    listen [::]:80;

    server_name example.com www.example.com;
    root /var/www/example.com/html;
}
sudo nginx -t
sudo systemctl reload nginx

For Ubuntu’s Nginx file layout, go back to install Nginx on Ubuntu and confirm the server block lives in /etc/nginx/sites-available/ with a matching symlink in /etc/nginx/sites-enabled/.

Fix dry-run output that says no simulated renewals were attempted

This message is simple: Certbot has nothing to renew yet. It appears when you test renewal before the first certificate has been issued on that server.

sudo certbot certificates
No certificates found.

Issue the first certificate with certbot --nginx, then rerun sudo certbot renew --dry-run. Once a renewal file exists under /etc/letsencrypt/renewal/, the dry run will simulate a real renewal instead of stopping immediately.

Avoid Let’s Encrypt rate limits while testing

If you keep retrying broken requests, Let’s Encrypt will eventually refuse more production issuances for the same identifier set:

Error creating new order :: too many certificates already issued for exact set of identifiers

Use Certbot’s staging mode while you are still fixing DNS, firewall, or server block issues:

sudo certbot --nginx --test-cert --email admin@example.com --agree-tos -d example.com -d www.example.com

Let’s Encrypt’s rate limit policy is generous for normal use, and renewal almost never hits it. For repeated testing, staging is the safer choice because the certificate is untrusted by browsers and does not spend production issuance capacity.

Remove Certbot and Let’s Encrypt configuration from Ubuntu

If you are decommissioning the site or moving to another ACME client, remove the certificate first, then clean out the Ubuntu packages and any leftover Let’s Encrypt data.

Delete the certificate from Certbot on Ubuntu

Delete the certificate record from Certbot before you remove the package:

sudo certbot delete --cert-name example.com

If the private key was exposed, revoke the certificate first and then delete it. For a normal migration or site retirement, deletion alone is usually enough.

Remove Certbot packages from Ubuntu

Stop the renewal timer, remove the Certbot packages, then preview orphaned dependency cleanup:

sudo systemctl disable --now certbot.timer
sudo apt remove --purge -y certbot python3-certbot-nginx
sudo apt autoremove --dry-run

If the dry run lists only packages you no longer need, run the real cleanup interactively:

sudo apt autoremove

Check that the Certbot packages no longer have an installed-state row:

dpkg-query -W -f='${db:Status-Abbrev} ${binary:Package}\n' certbot python3-certbot-nginx 2>/dev/null | grep '^ii' || echo "No Certbot packages are installed"
No Certbot packages are installed

The grep '^ii' filter checks only installed-state rows; the grep command in Linux guide covers the pattern syntax if you adapt this proof for other package checks.

Remove the SSL directives from the Nginx site if it will stay online

If the server block will keep serving plain HTTP after you remove the certificate, delete the Certbot-added listen 443 ssl, ssl_certificate, ssl_certificate_key, and redirect lines from the site file before you reload Nginx.

sudo nginx -t
sudo systemctl reload nginx
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Remove leftover Let’s Encrypt data if the server is being retired

The next commands permanently delete every Let’s Encrypt certificate, renewal file, and log directory on this server. Do not run them if the host still serves any other domain through Certbot.

sudo rm -rf /etc/letsencrypt
sudo rm -rf /var/lib/letsencrypt
sudo rm -rf /var/log/letsencrypt

If this Nginx host will continue serving other sites, keep the certificate directories those sites still need and only remove the specific site config you are retiring.

Conclusion

Nginx is serving HTTPS on Ubuntu with a Let’s Encrypt certificate that Certbot can renew through the packaged timer. For the next hardening pass, add browser-facing protections by configuring security headers in Nginx or control abusive requests with rate limiting in Nginx.

Follow LinuxCapable

Want more LinuxCapable guides in Google?

Add LinuxCapable as a preferred source so Google can show more of our fresh Linux tutorials in Top Stories and From your sources when relevant.

Add LinuxCapable as a preferred source on Google
Search LinuxCapable

Need another guide?

Search LinuxCapable for package installs, commands, troubleshooting, and follow-up guides related to what you just read.

Found this guide useful?

Support LinuxCapable to keep tutorials free and up to date.

Buy me a coffeeBuy me a coffee
Before commenting, please review our Comments Policy.
Formatting tips for your comment

You can use basic HTML to format your comment. Useful tags currently allowed in published comments:

You type Result
<code>command</code> command
<strong>bold</strong> bold
<em>italic</em> italic
<blockquote>quote</blockquote> quote block

Got a Question or Feedback?

We read and reply to every comment - let us know how we can help or improve this guide.

Let us know you are human: