Tóm tắt: Cài certbot (snap hoặc gói distro), chọn challenge: http-01 (cổng 80 mở ra internet, plugin --nginx hoặc --webroot) hoặc dns-01 (bắt buộc cho wildcard, dùng plugin DNS như dns-cloudflare). Certbot tạo timer systemd tự renew; thêm --deploy-hook để reload Nginx. Luôn thử với --dry-run / --test-cert trước.
Luồng hoạt động
flowchart LR A[certbot] -->|"tạo order"| B[Let's Encrypt ACME] B -->|"challenge token"| A A -->|"http-01: ghi file"| C["/.well-known/acme-challenge/"] A -->|"dns-01: tạo TXT"| D["_acme-challenge.example.com"] B -->|"kiểm tra"| C B -->|"kiểm tra"| D B -->|"cấp cert"| E["/etc/letsencrypt/live/example.com/"] E --> F["nginx reload (deploy-hook)"]
| Challenge | Yêu cầu | Wildcard | Khi nào dùng |
|---|---|---|---|
http-01 |
Cổng 80 của domain trỏ về server, truy cập được từ internet | Không | Web server public thông thường |
dns-01 |
API token sửa DNS zone | Có | Wildcard, server nội bộ không mở cổng 80, nhiều server dùng chung cert |
tls-alpn-01 |
Cổng 443 | Không | Ít dùng với certbot |
Cấu hình
Cài đặt
# Cách được certbot khuyên dùng: snap
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
# Hoặc gói distro (Ubuntu/Debian), thường cũ hơn
sudo apt install certbot python3-certbot-nginxhttp-01 với Nginx
# Plugin nginx: tự sửa server block, thêm redirect HTTPS
sudo certbot --nginx -d example.com -d www.example.com \
-m ops@example.com --agree-tos --non-interactive
# Chỉ lấy cert, tự cấu hình Nginx (an toàn hơn khi config Nginx được quản lý bằng Ansible/Git)
sudo certbot certonly --webroot -w /var/www/letsencrypt \
-d example.com -d www.example.com --deploy-hook "systemctl reload nginx"Với --webroot, Nginx phải phục vụ thư mục challenge qua HTTP:
server {
listen 80;
server_name example.com www.example.com;
location /.well-known/acme-challenge/ {
root /var/www/letsencrypt;
}
location / { return 301 https://$host$request_uri; }
}
server {
listen 443 ssl;
http2 on;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
}Luôn dùng fullchain.pem (leaf + intermediate), không dùng cert.pem. Dùng cert.pem là nguyên nhân phổ biến của lỗi thiếu chain, xem TLS troubleshooting.
http2 on; cần Nginx ≥ 1.25.1; bản cũ hơn viết listen 443 ssl http2;. Cấu hình reverse proxy đầy đủ xem Nginx reverse proxy + TLS.
dns-01 và wildcard (Cloudflare)
# Cài plugin (bản snap)
sudo snap set certbot trust-plugin-with-root=ok
sudo snap install certbot-dns-cloudflare# API token chỉ có quyền Zone:DNS:Edit cho zone cần thiết
dns_cloudflare_api_token = <CLOUDFLARE_API_TOKEN>sudo chmod 600 /root/.secrets/cloudflare.ini
sudo certbot certonly --dns-cloudflare \
--dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
-d example.com -d '*.example.com' \
--deploy-hook "systemctl reload nginx"DNS provider không có plugin: --manual --preferred-challenges dns cho phép tạo TXT bằng tay, nhưng không tự renew được (trừ khi viết --manual-auth-hook).
Auto renew
| Mục đích | Lệnh |
|---|---|
| Liệt kê cert, ngày hết hạn | sudo certbot certificates |
| Thử renew không cấp thật | sudo certbot renew --dry-run |
| Xem timer (snap) | systemctl list-timers | grep certbot |
| Log renew | sudo less /var/log/letsencrypt/letsencrypt.log |
| Ép renew một cert | sudo certbot renew --cert-name example.com --force-renewal |
| Thêm domain vào cert sẵn có | sudo certbot certonly --cert-name example.com -d example.com -d api.example.com ... |
| Xoá cert | sudo certbot delete --cert-name example.com |
| Thử trên môi trường staging (không tính rate limit) | thêm --test-cert |
Hook chạy sau mỗi lần renew thành công có thể đặt cố định thay vì truyền tham số:
#!/bin/sh
nginx -t && systemctl reload nginxsudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.shCấu hình renew của từng cert nằm ở /etc/letsencrypt/renewal/<cert-name>.conf. Certbot renew khi cert còn dưới 30 ngày.
Lỗi thường gặp
| Triệu chứng | Nguyên nhân | Cách xử lý |
|---|---|---|
Timeout during connect (likely firewall problem) |
Cổng 80 bị chặn (firewall, security group, NAT) | Mở 80 từ internet, hoặc chuyển sang dns-01 |
Invalid response from .../acme-challenge/...: 404 |
Webroot sai, hoặc location / redirect/proxy nuốt request challenge |
Kiểm tra -w khớp root trong Nginx; đặt location /.well-known/acme-challenge/ riêng |
DNS problem: NXDOMAIN / sai IP |
Bản ghi A/AAAA chưa trỏ đúng; có AAAA cũ trỏ IPv6 không phục vụ | dig +short A example.com, dig +short AAAA example.com |
dns-01 fail Incorrect TXT record |
DNS chưa propagate hoặc token thiếu quyền | Tăng --dns-cloudflare-propagation-seconds; kiểm tra quyền token |
too many certificates already issued |
Chạm rate limit khi test lặp lại | Dùng --test-cert/--dry-run khi thử; chờ hết cửa sổ rate limit |
| Renew thành công nhưng site vẫn dùng cert cũ | Nginx chưa reload | Thêm deploy hook, systemctl reload nginx |
| Cert hết hạn dù có timer | Timer bị disable, hook lỗi, hoặc cert --manual |
systemctl list-timers, certbot renew --dry-run, đọc log |