Enable HTTPS with Certbot
HTTPS encrypts traffic between the browser and the server and avoids warnings from modern browsers. Let's Encrypt issues free certificates valid for ninety days, which Certbot obtains and renews. The hard part is not the command but DNS and ports: one forgotten record makes validation fail.
Prepare DNS and Nginx
Before Certbot, your-domain.com and www.your-domain.com must resolve to the VPS over A and AAAA, and Nginx must answer on port 80 with the correct server_name. Open the ports:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
curl -I http://your-domain.com/A wrong AAAA record makes the HTTP-01 challenge fail: Let's Encrypt tries IPv6 first. Fix DNS and wait for the TTL before retrying. If another server block captures the domain, Certbot writes the certificate in the wrong place.
Obtain the certificate
sudo apt update
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.com -d www.your-domain.comThe Nginx plugin changes the block to listen on 443, adds certificate paths and offers the HTTP to HTTPS redirect. Files live in /etc/letsencrypt/live/your-domain.com/. Do not copy them by hand: Certbot manages links and renewals.
Renew and test
sudo systemctl list-timers certbot.timer
sudo certbot renew --dry-runThe systemd timer replaces old cron scripts. --dry-run tests renewal without consuming quota. After renewal, the plugin reloads Nginx. Check the certificate actually served:
curl -I https://your-domain.com/
openssl s_client -connect your-domain.com:443 -servername your-domain.com </dev/null 2>/dev/null | openssl x509 -noout -datesIf renewal fails, keep port 80 open: the HTTP-01 challenge needs it. Logs are in /var/log/letsencrypt/letsencrypt.log.
HSTS, carefully
Enable HSTS only when the whole domain and its subdomains work over HTTPS:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;Start with max-age=300, verify, then increase it. includeSubDomains breaks a subdomain still on HTTP; preload is hard to undo. Test with sudo nginx -t and reload.
Troubleshooting
Challenge failed: DNS, wrong AAAA, closed port 80 or a higher-priorityserverblock.Too many requests: Let's Encrypt rate limit; wait before retrying, do not loop.Certificate not yet due for renewal: normal, renewal happens thirty days before expiry.- Browser still on HTTP: check the redirect and cache, then test from another network.
Do not change TLS protocols blindly: the configuration generated by Certbot is a good starting point for Nginx.
Advertisement
Was this article helpful?
Read next
- Keep a Node.js app online with PM2Run a Node.js application under PM2, restart it at boot and read its logs.
- Install PHP-FPM for a websiteConnect Nginx to PHP 8.4-FPM over a Unix socket, with correct permissions and a test page.
- Deploy a stack with Docker ComposeDeploy an application and its database with compose.yaml, persistent volumes and variables outside Git.