Let's Encrypt SSL Setup with Automatic Renewal
Let's Encrypt — free certificate authority issuing DV certificates valid for 90 days. Certbot automates obtaining and renewal: certificate updates without manual intervention.
Certbot Installation
# Ubuntu/Debian
apt install certbot python3-certbot-nginx
# CentOS/RHEL
dnf install certbot python3-certbot-nginx
# Snap (universal)
snap install --classic certbot
ln -s /snap/bin/certbot /usr/bin/certbot
Obtaining a Certificate
# Automatic mode — Certbot modifies nginx config
certbot --nginx -d example.ru -d www.example.ru
# Obtain certificate only (without modifying nginx)
certbot certonly --nginx -d example.ru -d www.example.ru
# Wildcard certificate (DNS challenge only)
certbot certonly --manual \
--preferred-challenges=dns \
-d example.ru \
-d *.example.ru
Wildcard requires adding _acme-challenge.example.ru TXT record to DNS. Automation supported via plugins (certbot-dns-cloudflare, certbot-dns-route53).
Automatic Renewal via DNS Challenge (Cloudflare)
pip install certbot-dns-cloudflare
# /etc/letsencrypt/cloudflare.ini
dns_cloudflare_api_token = YOUR_CLOUDFLARE_API_TOKEN
certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
-d example.ru \
-d *.example.ru
Automatic Renewal
Certbot adds systemd timer or cron on installation. Check:
# Check timer
systemctl list-timers | grep certbot
# Test renewal (without actual renewal)
certbot renew --dry-run
# Manual renewal
certbot renew
If hook not added automatically — add to cron:
# Crontab
0 3 * * * certbot renew --quiet --post-hook "systemctl reload nginx"
--post-hook reloads Nginx after certificate update — without it Nginx continues using old certificate.
Nginx Configuration After Certbot
# /etc/nginx/sites-available/example.ru.conf
# (certbot adds ssl_certificate and ssl_certificate_key automatically)
server {
listen 443 ssl;
server_name example.ru www.example.ru;
# Added by certbot
ssl_certificate /etc/letsencrypt/live/example.ru/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.ru/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# Additionally
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
ssl_stapling on;
ssl_stapling_verify on;
}
Monitoring Expiration Date
# Check expiration
openssl x509 -enddate -noout -in /etc/letsencrypt/live/example.ru/cert.pem
# Via curl
echo | openssl s_client -servername example.ru -connect example.ru:443 2>/dev/null \
| openssl x509 -noout -dates
Monitor via Zabbix, Prometheus (blackbox_exporter), or UptimeRobot (SSL expiration check).
Timeline: 30–60 minutes for one domain with Nginx.







