Let's Encrypt provides trusted TLS certificates that allow Nginx to serve a website over HTTPS. Certbot can request the certificate, update the matching Nginx server block, configure an HTTP-to-HTTPS redirect, and renew the certificate automatically.
In this tutorial, you will verify DNS, prepare Nginx and UFW, install Certbot on Ubuntu 24.04, issue a certificate, test HTTPS and renewal, and add security headers without enabling an unsafe HSTS policy too early.
Step 1 — Verify the Domain's DNS Records
Every hostname included in the certificate request must resolve to this Nginx server.
Check the IPv4 records:
dig +short A example.com dig +short A www.example.com
If your domain publishes IPv6 records, check them too:
dig +short AAAA example.com dig +short AAAA www.example.com
The A records should return the server's public IPv4 address. Any AAAA record must return an IPv6 address that reaches the same server.
A stale AAAA record can cause validation or visitor failures even when the A record is correct. Remove an unused AAAA record or configure IPv6 correctly before continuing.
Step 2 — Verify the Nginx Server Block
Your Nginx configuration needs a server_name matching the requested hostnames.
Open the site configuration:
sudo nano /etc/nginx/sites-available/example.com
A basic HTTP server block should contain:
server { listen 80; listen [::]:80; server_name example.com www.example.com; root /var/www/example.com/public; index index.html index.php; location / { try_files $uri $uri/ =404; } }
Enable the site if it is not already enabled:
sudo ln -s /etc/nginx/sites-available/example.com \ /etc/nginx/sites-enabled/example.com
If the symbolic link already exists, do not create it again.
Test the Nginx configuration:
sudo nginx -t
Reload only after the test succeeds:
sudo systemctl reload nginx
Confirm that the HTTP site responds:
curl -I http://example.com
The ACME HTTP-01 validation used in this tutorial needs the domain to reach the server over port 80.
Step 3 — Allow HTTP and HTTPS Through UFW
Check whether UFW is active:
sudo ufw status
When it is active, allow SSH and the Nginx profile covering ports 80 and 443:
sudo ufw allow OpenSSH sudo ufw allow 'Nginx Full'
If an older Nginx HTTP rule exists, it is redundant after allowing Nginx Full:
sudo ufw delete allow 'Nginx HTTP'
Review the result:
sudo ufw status numbered
Keep port 80 reachable. Let's Encrypt recommends redirecting HTTP to HTTPS rather than blocking HTTP entirely, and HTTP-01 renewals may still depend on port 80.
Step 4 — Install Certbot and the Nginx Plugin
Install Certbot from Ubuntu's repositories:
sudo apt update sudo apt install -y certbot python3-certbot-nginx
Confirm the command is available:
certbot --version
Do not depend on a specific version string in automation. Package versions change as Ubuntu publishes updates.
Step 5 — Request and Install the Certificate
Request a certificate for the apex domain and www hostname:
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. It then performs domain validation and updates the matching Nginx server block.
Only include hostnames that already resolve to this server. When you do not use www.example.com, request only the apex domain:
sudo certbot --nginx --redirect -d example.com
After a successful request, inspect the managed certificates:
sudo certbot certificates
The output shows the certificate names, covered domains, expiry dates, and file paths under /etc/letsencrypt/live/.
Do not manually copy or edit files inside /etc/letsencrypt/live/. Certbot manages the symbolic links and renewal versions.
Step 6 — Verify HTTPS and the Redirect
Check the HTTPS response:
curl -I https://example.com
A successful response may use HTTP/1.1, HTTP/2, or another protocol depending on your Nginx and client configuration. The important checks are a valid TLS connection and the expected application status.
Test the HTTP redirect:
curl -I http://example.com
You should receive a permanent redirect such as 301 or 308 with a Location header pointing to the HTTPS URL.
Inspect the certificate from the command line:
openssl s_client \ -connect example.com:443 \ -servername example.com \ </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates
This confirms the certificate's subject, issuer, start date, and expiry date.
Step 7 — Test Automatic Renewal
Ubuntu's Certbot package normally installs a systemd timer. Check for it:
systemctl list-timers --all | grep certbot
Run a simulated renewal:
sudo certbot renew --dry-run
The dry run should complete without validation or deployment errors. Certbot checks certificates regularly and renews them when they enter the configured renewal window.
Review the timer and service logs when troubleshooting:
sudo journalctl -u certbot.timer -n 50 --no-pager sudo journalctl -u certbot.service -n 100 --no-pager
You do not need to create a separate cron job when the systemd timer is active.
Step 8 — Add Security Headers Carefully
Certbot provides the certificate and redirect, but application security headers remain your responsibility.
Open the HTTPS server block created or updated by Certbot:
sudo nano /etc/nginx/sites-available/example.com
Inside the HTTPS server block, add:
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 unsuitable when the site must be embedded by another origin. Adjust it to your application's actual requirements.
For HSTS, begin with a short test period only after HTTPS works reliably:
add_header Strict-Transport-Security "max-age=300" always;
After confirming the site, redirects, certificates, and all required subdomains work over HTTPS, increase the duration gradually. Do not add includeSubDomains until every subdomain supports HTTPS, because browsers will enforce the policy for all of them.
Test and reload Nginx:
sudo nginx -t sudo systemctl reload nginx
Verify the headers:
curl -I https://example.com
Step 9 — Troubleshoot Common Certbot Errors
DNS points to the wrong server
Compare the resolved addresses with the VM's public addresses:
dig +short A example.com dig +short AAAA example.com
Correct stale A or AAAA records and wait for DNS caches to expire.
Port 80 is blocked
Check UFW and confirm Nginx listens on port 80:
sudo ufw status sudo ss -ltnp | grep ':80'
Also check upstream firewalls or network security rules outside the operating system.
Nginx configuration test fails
Run:
sudo nginx -t
Review the reported file and line number before reloading Nginx.
Certbot cannot find a matching server block
Make sure server_name contains the exact hostname passed with -d, then test and reload Nginx before retrying.
A certificate request hits a rate limit
Do not repeatedly retry a broken production request. Fix DNS, firewall, or Nginx issues first and use Certbot's staging or dry-run options while testing renewal behavior.
The certificate renewed but Nginx still serves the old one
Check the active certificate paths and reload Nginx:
sudo certbot certificates sudo nginx -t sudo systemctl reload nginx
Step 10 — Maintain the HTTPS Setup
Keep the setup reliable by:
- Leaving ports
80and443reachable. - Keeping Ubuntu, Nginx, and Certbot packages updated.
- Running
certbot renew --dry-runafter major DNS, firewall, proxy, or Nginx changes. - Monitoring certificate expiry externally as a backup signal.
- Avoiding manual changes to Certbot-managed certificate files.
- Reviewing HSTS before adding long durations or subdomain enforcement.
Raff Linux VMs start at $8.49 per month with 2 vCPU, 2 GB RAM, 40 GB NVMe storage, and 3 Gbps unmetered bandwidth. TLS traffic does not require a separate bandwidth add-on on these plans.
Conclusion
Your Nginx site now uses a Let's Encrypt certificate, redirects HTTP traffic to HTTPS, and has a tested automatic-renewal path.
Continue with WordPress on Ubuntu 24.04 with Nginx, build a complete LEMP stack, or review cloud security fundamentals before exposing additional services.