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
AorAAAArecord already points to this server. - Your Nginx site uses the real domain in its
server_namedirective on port80. - Ports
80and443are 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
sudofor 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:
| Option | What it changes |
|---|---|
--nginx | Uses the Nginx plugin for both validation and configuration edits. |
--agree-tos | Accepts Let’s Encrypt’s subscriber agreement without an extra prompt. |
--redirect | Adds the HTTP to HTTPS redirect automatically. |
--hsts | Sends the Strict-Transport-Security header after HTTPS is active. |
--staple-ocsp | Turns on OCSP stapling in the generated SSL configuration. |
--email | Registers the certificate contact email for expiry and security notices. |
-d | Lists 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
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.
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.
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.
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.
Formatting tips for your comment
You can use basic HTML to format your comment. Useful tags currently allowed:
<code>command</code>command<strong>bold</strong><em>italic</em><blockquote>quote</blockquote>