Certbot is an ACME client that can request a free TLS certificate from Let's Encrypt, install it into an Nginx server block, configure an HTTP-to-HTTPS redirect, and renew the certificate automatically. On Ubuntu 24.04, the safest workflow is to verify DNS and Nginx first, keep port 80 reachable for HTTP-01 validation, install a current Certbot build, request the certificate with the Nginx plugin, and test renewal before treating HTTPS as complete.
Raff users can apply this workflow to a Linux VPS running Nginx on Ubuntu 24.04. The tutorial assumes your domain already resolves to the VM and Nginx serves the site over HTTP. If Nginx is not installed yet, complete Install Nginx on Ubuntu 24.04 first.
Let's Encrypt recommends keeping port 80 open for general web servers and redirecting HTTP to HTTPS rather than blocking HTTP entirely. Certbot's current Nginx instructions also support having Certbot edit the Nginx configuration directly, then testing automatic renewal with certbot renew --dry-run.
Prerequisites:
- A Raff Linux VM running Ubuntu 24.04
- Nginx installed and serving the intended hostname over HTTP
- A domain name with DNS records pointing to the VM
- A non-root user with sudo privileges
- Public access to TCP ports 80 and 443
Step 1 — Verify DNS Before Running Certbot
Check the IPv4 records for every hostname you want on the certificate:
dig +short A example.com dig +short A www.example.com
If the domain publishes IPv6, check the AAAA records too:
dig +short AAAA example.com dig +short AAAA www.example.com
Each hostname included in the certificate request must resolve to this server. A stale AAAA record can send validation traffic to the wrong IPv6 host even when the A record is correct.
Compare the DNS result with the VM's public address. If a hostname should not be used, do not include it in the Certbot command.
Verify: All requested hostnames should resolve to the intended server, and any published AAAA record should reach the same Nginx deployment.
Step 2 — Verify Nginx Serves the Domain Over HTTP
Check the active Nginx configuration:
sudo nginx -t
Confirm the site responds over HTTP:
curl -I http://example.com
Inspect the server block if needed:
sudo nginx -T 2>/dev/null | grep -A8 -B3 'server_name example.com'
The active server block should contain the hostname you plan to request with Certbot, for example:
server { listen 80; listen [::]:80; server_name example.com www.example.com; root /var/www/example.com/public; }
Certbot's Nginx plugin needs to identify the matching server block before it can install the certificate cleanly.
Verify: sudo nginx -t should succeed and curl -I http://example.com should return an HTTP response from the intended Nginx site.
Step 3 — Keep Ports 80 and 443 Reachable
Check UFW status:
sudo ufw status numbered
If UFW is active, allow SSH and the Nginx profile for HTTP and HTTPS:
sudo ufw allow OpenSSH sudo ufw allow 'Nginx Full'
Review the result:
sudo ufw status numbered
Do not close port 80 after enabling HTTPS when using the HTTP-01 validation path. Let's Encrypt recommends serving HTTP and redirecting it to HTTPS.
Also verify that any upstream cloud firewall or network policy allows TCP 80 and 443 to this VM. For platform firewall versus guest UFW responsibilities, consult Cloud Firewall Best Practices.
Verify: The server remains reachable over SSH, HTTP reaches port 80, and HTTPS traffic is allowed on port 443.
Step 4 — Install Certbot for Nginx on Ubuntu 24.04
Certbot's current Linux instructions support installing the Certbot snap maintained by the Certbot team. Avoid mixing multiple Certbot installation methods on the same server.
First check for an existing installation:
command -v certbot || true snap list certbot 2>/dev/null || true dpkg -l | grep -E 'certbot|python3-certbot-nginx' || true
If Certbot is already managing production certificates successfully, do not replace it only for this tutorial. Continue with the existing supported installation and verify renewal.
For a new installation, make sure snap is available:
command -v snap || sudo apt install -y snapd
Install Certbot:
sudo snap install --classic certbot
Create the standard command path if needed:
sudo ln -sf /snap/bin/certbot /usr/local/bin/certbot
Check the installed version and Nginx plugin:
certbot --version certbot plugins | grep -A3 nginx
Do not depend on a specific Certbot version string in automation because the package is updated over time.
Verify: certbot --version should succeed and certbot plugins should list the Nginx plugin.
Step 5 — Request and Install a Let's Encrypt Certificate with Certbot and Nginx
Request the certificate and let Certbot update the matching Nginx server block:
sudo certbot --nginx --redirect \ -d example.com \ -d www.example.com
Certbot will ask for an email address and agreement to the Let's Encrypt terms. The --redirect option configures HTTP requests to redirect to HTTPS after successful issuance.
If you use only the apex hostname, request only that name:
sudo certbot --nginx --redirect -d example.com
Do not request hostnames that do not resolve to this server.
After issuance, list managed certificates:
sudo certbot certificates
Do not manually edit files inside /etc/letsencrypt/live/ or /etc/letsencrypt/renewal/; Certbot manages those paths.
Verify: sudo certbot certificates should list the requested hostname and sudo nginx -t should still pass.
Step 6 — Verify HTTPS, the HTTP Redirect, and the Certificate
Test HTTPS:
curl -I https://example.com
Test the HTTP redirect:
curl -I http://example.com
The HTTP response should redirect to the HTTPS URL, commonly with 301 or 308.
Inspect the certificate presented by Nginx:
openssl s_client \ -connect example.com:443 \ -servername example.com \ </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates
Check that the certificate matches the hostname and has valid start and expiry dates.
Verify: HTTPS should complete without a certificate error, HTTP should redirect to HTTPS, and the certificate dates should be valid.
Step 7 — Test Certbot Automatic Renewal for Nginx
Most Certbot installations include a scheduled renewal task. Check both common scheduling paths:
systemctl list-timers --all | grep -i certbot || true sudo grep -R 'certbot renew' /etc/crontab /etc/cron.* 2>/dev/null || true
Run Certbot's renewal simulation:
sudo certbot renew --dry-run
This tests the renewal path without replacing your active production certificate.
Review managed certificate details again:
sudo certbot certificates
You normally should not create an extra custom cron job when your Certbot installation already provides automatic renewal.
Verify: sudo certbot renew --dry-run should complete successfully and a scheduled renewal mechanism should be present for the installation method in use.
Step 8 — Add Security Headers Without Breaking the Site
TLS does not automatically configure application security headers. Add only headers that match your application's requirements. For CSP, HSTS, WAF-versus-firewall, and TLS-termination decisions beyond this Nginx setup, see TLS & Application Edge Security.
Open the active HTTPS server block and add a conservative baseline inside the server block:
add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header X-Frame-Options "SAMEORIGIN" always;
X-Frame-Options: SAMEORIGIN is not appropriate when the site must be embedded by another origin.
Treat HSTS separately. Enable it only after HTTPS, redirects, certificate renewal, and every required hostname are working reliably. Start with a short test duration:
add_header Strict-Transport-Security "max-age=300" always;
Do not add includeSubDomains until every required subdomain supports HTTPS.
Validate and reload:
sudo nginx -t sudo systemctl reload nginx
Check the headers:
curl -I https://example.com
Verify: nginx -t should pass, the site should remain reachable over HTTPS, and only the intended headers should appear.
Step 9 — Troubleshoot Common Certbot and Nginx Errors
Certbot cannot find a matching Nginx server block
Confirm the hostname appears in an enabled server block:
sudo nginx -T 2>/dev/null | grep -n 'server_name'
Correct server_name, then run:
sudo nginx -t sudo systemctl reload nginx
The Nginx plugin is not installed
Check available plugins:
certbot plugins
With the Certbot snap, the Nginx plugin should be included. If Certbot comes from another installation method, follow the instructions for that method rather than mixing packages.
HTTP-01 validation fails
Check DNS and port 80:
dig +short A example.com dig +short AAAA example.com sudo ss -ltnp | grep ':80' sudo ufw status numbered curl -I http://example.com
A wrong A/AAAA record, blocked port 80, or incorrect Nginx routing can all break validation.
/.well-known/acme-challenge/ returns 404
If a custom Nginx rule intercepts hidden paths or rewrites all requests, inspect the active configuration before retrying:
sudo nginx -T 2>/dev/null | grep -n -E 'well-known|rewrite|return|location'
Fix the conflicting routing rule instead of repeatedly requesting new certificates.
Certbot hits a Let's Encrypt rate limit
Stop retrying the same broken production request. Fix DNS, firewall, or Nginx first. Use Certbot's dry-run or staging workflow while validating renewal behavior.
Renewal works but Nginx serves an old certificate
Check the certificate Certbot manages, validate Nginx, and reload it:
sudo certbot certificates sudo nginx -t sudo systemctl reload nginx
Then inspect the live certificate again with openssl s_client.
Verify: After troubleshooting, sudo nginx -t, curl -I https://example.com, and sudo certbot renew --dry-run should all succeed.
Step 10 — Run the Final End-to-End HTTPS Verification
Run the complete verification sequence:
sudo nginx -t systemctl is-active nginx curl -I http://example.com curl -I https://example.com sudo certbot certificates sudo certbot renew --dry-run openssl s_client \ -connect example.com:443 \ -servername example.com \ </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates
The deployment is complete when Nginx configuration is valid, HTTP redirects to HTTPS, the HTTPS endpoint presents the expected certificate, and the renewal dry run succeeds.
If this Nginx instance proxies a Node.js application, keep the application port private and let Nginx own the public HTTPS edge. See Install PM2 and Deploy Node.js on Ubuntu 24.04 for that architecture.
Verify: Every command above should succeed without certificate, redirect, Nginx syntax, or renewal errors.
Cleanup (optional)
Do not delete a certificate that is still serving a production hostname.
List Certbot-managed certificates first:
sudo certbot certificates
If this was only a disposable test hostname, first inspect references while the certificate still exists:
sudo grep -RFn '/etc/letsencrypt/live/example.com/' /etc/nginx
Remove or update only the decommissioned site's server block. Remove every reference to this certificate, then validate and reload before deleting it:
sudo nginx -t && sudo systemctl reload nginx
Continue only after validation and reload succeed and no active service depends on the certificate. Then remove the certificate through Certbot:
sudo certbot delete --cert-name example.com sudo nginx -t
Do not uninstall Certbot while it still manages certificates for other sites on the server.
Verify: sudo certbot certificates should no longer list the deleted test certificate, and sudo nginx -t should still succeed.
Conclusion
You installed Certbot for Nginx on Ubuntu 24.04, requested a Let's Encrypt certificate, configured HTTP-to-HTTPS redirection, verified the live certificate, tested automatic renewal, and added a conservative security-header baseline.
The most important production checks are simple: keep DNS correct, keep port 80 available for the HTTP-01 workflow, validate Nginx before reloads, do not mix Certbot installation methods casually, and treat certbot renew --dry-run as part of the deployment rather than an optional afterthought.
For a new site, configure DNS and the web server on a Raff Linux VM before requesting a certificate. The Linux VM product page is linked in the prerequisites. Existing sites can apply the Certbot steps to their current Nginx host without migrating providers.
For an end-to-end application example, continue with Install WordPress on Ubuntu 24.04 with Nginx. The Nginx and PM2 setup procedures are already linked at the relevant implementation steps.