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

Last updated Friday, March 13, 2026 1:46 pm 9 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. This section covers the preflight checks, the Ubuntu package install, and the certificate request itself.

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 and the Nginx integration package from Ubuntu’s universe repository:

sudo apt install certbot python3-certbot-nginx -y

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, --hsts, and --staple-ocsp flags used below.

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 status nginx --no-pager
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: enabled)
     Active: active (running) since Fri 2026-03-13 13:33:12 AWST; 2min 8s ago
 Invocation: 640c2301698b4f66a79151d3db741769
       Docs: man:nginx(8)
   Main PID: 4432 (nginx)

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;.

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 --hsts --staple-ocsp --email admin@example.com -d example.com -d www.example.com

That command keeps the common path short, but each flag still matters:

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.
--hstsSends the Strict-Transport-Security header after HTTPS is active.
--staple-ocspTurns on OCSP stapling in the generated SSL configuration.
--emailRegisters the certificate contact email for expiry and security notices.
-dLists every hostname you want on the same certificate.

When the request succeeds, Certbot prints the certificate path and expiry date:

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
This certificate expires on 2026-06-11.
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
Found the following certs:
  Certificate Name: example.com
    Domains: example.com www.example.com
    Expiry Date: 2026-06-11 (VALID: 89 days)
    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:

curl -I http://example.com
HTTP/1.1 301 Moved Permanently
Server: nginx/1.28.2 (Ubuntu)
Date: Fri, 13 Mar 2026 05:40:00 GMT
Content-Type: text/html
Content-Length: 178
Connection: keep-alive
Location: https://example.com/

Once the redirect works, you can move from basic TLS to tighter web hardening with guides on 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

If you run the dry run before your 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 status certbot.timer --no-pager
systemctl list-timers certbot.timer --all --no-pager
● certbot.timer - Run certbot twice daily
     Loaded: loaded (/usr/lib/systemd/system/certbot.timer; enabled; preset: enabled)
     Active: active (waiting) since Fri 2026-03-13 13:33:14 AWST; 6s ago
    Trigger: Sat 2026-03-14 00:02:12 AWST; 10h left
   Triggers: ● certbot.service
NEXT                         LEFT LAST PASSED UNIT          ACTIVATES
Sat 2026-03-14 00:02:12 AWST  10h -         - certbot.timer certbot.service

1 timers listed.

If the timer is disabled on your server, bring it back with sudo systemctl enable --now certbot.timer and rerun the status check.

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 -I 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

If you need a quick refresher on Ubuntu’s Nginx file layout before editing the site file, 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, and clean up orphaned dependencies:

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

Check that APT no longer shows Certbot as installed:

apt-cache policy certbot
certbot:
  Installed: (none)
  Candidate: 2.9.0-1
  Version table:

The Installed: (none) line confirms the Ubuntu package itself is gone.

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 is still staying online for other work, keep the certificate directories you still need and only remove the specific site config you are retiring.

Nginx and Let’s Encrypt on Ubuntu FAQ

Do I need Snap for Certbot on Ubuntu?

No. Ubuntu’s apt packages are enough for this workflow and already include the python3-certbot-nginx plugin. Snap is mainly useful when you want Certbot’s newest upstream release instead of the version tied to your Ubuntu LTS package set.

Can the Nginx plugin issue a wildcard certificate on Ubuntu?

No. Wildcard certificates require Let’s Encrypt’s DNS-01 challenge, not the HTTP-01 flow used by certbot --nginx. If you need *.example.com, use a DNS plugin that can create the required _acme-challenge TXT record through your DNS provider.

Why does certbot renew –dry-run say no simulated renewals were attempted?

That message means Certbot has no certificate renewal files yet. It usually appears when you test renewal before the first successful certificate request on that server. Issue the certificate first, then rerun the dry run.

Does Let’s Encrypt need port 80 open on Ubuntu?

Yes for the standard Nginx plugin flow. Let’s Encrypt’s HTTP-01 challenge reaches your site over port 80, even if the goal is an HTTPS certificate on port 443. If port 80 cannot be opened, switch to DNS-01 instead of forcing the HTTP method.

Conclusion

Nginx is now ready to serve HTTPS on Ubuntu with a Let’s Encrypt certificate that Certbot can renew automatically. From here, tighten the web stack with configure security headers in Nginx, control abusive traffic with rate limiting in Nginx, or move into a full application stack with install WordPress with Nginx, MariaDB, and PHP on Ubuntu.

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 coffee Buy 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:

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

Leave a Comment

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

Let us know you are human: