What you will achieve
Free TLS certificates from Let's Encrypt on Ubuntu with Certbot — Apache or Nginx plugin, auto-renewal via systemd timer.
1) Install Certbot
sudo apt install certbot python3-certbot-nginx
# or python3-certbot-apache
2) Obtain certificate
sudo certbot --nginx -d example.com -d www.example.com
DNS must point to this server; ports 80/443 open in UFW.
3) Dry run renewal
sudo certbot renew --dry-run
4) Timer
systemctl list-timers | grep certbot
Verify
sudo certbot certificates
curl -vI https://example.com 2>&1 | grep expire
5) Standalone mode (no web server yet)
sudo certbot certonly --standalone -d example.com
Stops port 80 binding — schedule during maintenance if Apache/nginx running.
6) DNS challenge (wildcard)
sudo apt install python3-certbot-dns-cloudflare
# credentials in /root/.secrets/cloudflare.ini
7) Post-renewal hook
# /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
#!/bin/bash
systemctl reload nginx
Rate limits
Let's Encrypt limits certificates per registered domain per week — use staging server (--staging) when testing automation.
8) EFF certbot terms
Automated renewals need port 80 or DNS API reachable — firewall changes breaking renewals expire certs silently until browsers complain.
Prerequisites
Public DNS pointing to server. Ports 80 and/or 443 reachable from internet. nginx or apache vhost with server_name matching cert domain. Email for expiry notices.
webroot mode with running server
sudo certbot certonly --webroot -w /var/www/html -d example.com
certbot renew hook
sudo certbot renew --deploy-hook 'systemctl reload nginx'Reload only when cert actually renewed — avoids unnecessary nginx reloads twice daily.
wildcard and internal names
Let's Encrypt won't issue for .local — use real domain or internal CA for lab. Wildcard needs DNS challenge — HTTP-01 cannot prove *.example.com ownership.
ACME v2 staging rate limits
Hitting failed validation rate limit blocks production attempts — always dry-run staging when automating new host pattern.
multi-domain san cert
One certbot invocation with -d app -d api -d www covers SAN cert — nginx server_name blocks can share single cert path in ssl_certificate directive.
certbot certificates renewal hook
Deploy hook reloads nginx only when cert within 30 days expiry renewed — check certbot logs in /var/log/letsencrypt for auth failure patterns after firewall change.
ipv6 AAAA record
Certbot validates all resolved addresses — broken AAAA pointing nowhere causes intermittent renewal failure — fix DNS or remove AAAA.
nginx plugin vs standalone
Plugin preferred on live site — standalone requires stopping nginx briefly on port 80 conflict.
Certificate transparency
After issuance verify cert appears in crt.sh for your domain — confirms legitimate CA path not mis-issued test cert left from staging botched run.