Certbot SSL Certificate: Cài Đặt Và Tự Động Gia Hạn Trong 5 Phút

Security tutorial - IT technology blog
Security tutorial - IT technology blog

Làm ngay: HTTPS cho domain trong 5 phút

Nếu bạn đang đọc bài này vì vừa thấy trình duyệt báo “Not Secure” trên website của mình — đừng lo, sửa được trong vài phút. Mình đi thẳng vào lệnh luôn.

Cài Certbot trên Ubuntu/Debian:

sudo apt update
sudo apt install certbot python3-certbot-nginx -y

Cấp certificate cho domain (thay yourdomain.com bằng domain thật):

sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

Certbot hỏi email để gửi cảnh báo khi cert sắp hết hạn, rồi tự sửa config Nginx để bật HTTPS. Xong. Trình duyệt hiện ổ khóa xanh ngay sau đó.

Kiểm tra tự động gia hạn đang chạy không:

sudo certbot renew --dry-run

Thấy Congratulations, all simulated renewals succeeded là ổn rồi.

Tại sao phải dùng SSL — và tại sao Let’s Encrypt lại khác

Sau khi audit security cho hơn 10 server, mình thấy một pattern lặp đi lặp lại: HTTP thuần, không mã hóa. Dữ liệu đi qua mạng dạng plain text — form đăng nhập, cookie session, thậm chí password admin WordPress. Ai ngồi cùng mạng với Wireshark đều bắt được, kể cả ở quán cà phê hay văn phòng dùng switch unmanaged.

SSL/TLS mã hóa toàn bộ traffic giữa trình duyệt và server. Concept đơn giản. Vấn đề là trước đây mua certificate tốn $50–$200/năm, cấu hình thủ công — nhiều người thấy phiền nên bỏ qua luôn.

Let’s Encrypt đến và phá luôn cái logic đó: cấp certificate miễn phí, tự động, được tin tưởng bởi toàn bộ trình duyệt lớn. Certbot là tool chính thức — lo hết từ xác minh domain, cấp cert, cài vào web server, đến gia hạn định kỳ. Sau bước setup đầu tiên, bạn không cần động tay vào nữa.

Hiểu cơ chế hoạt động (để debug khi lỗi)

Certbot xác minh bạn thực sự sở hữu domain bằng một trong hai cách:

HTTP-01 Challenge (phổ biến nhất)

Let’s Encrypt gửi request đến http://yourdomain.com/.well-known/acme-challenge/<token>. Certbot tạo file đó trên server. Nếu file trả về đúng nội dung — xác minh xong.

Port 80 phải mở, và domain phải trỏ đúng về IP server. Đây là nguyên nhân của 90% lỗi gặp phải — hoặc firewall chặn port 80, hoặc DNS chưa propagate xong.

DNS-01 Challenge (dùng khi không có web server)

Thay vì tạo file trên server, Certbot tạo TXT record trên DNS của domain. Phương pháp này hữu ích khi server không expose ra internet, hoặc khi cần wildcard certificate (*.yourdomain.com).

# Cấp wildcard certificate qua DNS challenge
sudo certbot certonly --manual --preferred-challenges dns \
  -d "*.yourdomain.com" -d yourdomain.com

Lệnh này yêu cầu bạn thêm TXT record vào DNS thủ công trước khi xác minh tiếp tục.

Các trường hợp thực tế hay gặp

Server dùng Apache thay vì Nginx

sudo apt install certbot python3-certbot-apache -y
sudo certbot --apache -d yourdomain.com

Không dùng web server (standalone mode)

Đang chạy app trực tiếp trên port 80/443 — Node.js, Python Flask, Go — thì dùng standalone mode. Certbot tạm chiếm port để xác minh, xong trả lại:

# Phải stop service đang dùng port 80 trước
sudo systemctl stop myapp
sudo certbot certonly --standalone -d yourdomain.com
sudo systemctl start myapp

Cấp nhiều domain một lúc

sudo certbot --nginx \
  -d yourdomain.com \
  -d www.yourdomain.com \
  -d api.yourdomain.com \
  -d admin.yourdomain.com

Tất cả nằm trong một certificate duy nhất qua Subject Alternative Names — tiện hơn cấp từng cert riêng lẻ.

Xem danh sách certificate đang có

sudo certbot certificates

Output cho biết domain, ngày hết hạn, và đường dẫn đến file cert.

Tự động gia hạn — đừng để quên

Cert của Let’s Encrypt hết hạn sau 90 ngày. Ngắn hơn cert thương mại (1–2 năm) là chủ tâm: Let’s Encrypt muốn ép bạn automate từ đầu, thay vì cấp cert 2 năm rồi để người ta quên đến khi site bị đỏ.

Cài Certbot qua apt sẽ tự tạo systemd timer, chạy kiểm tra 2 lần/ngày. Xem trạng thái:

sudo systemctl status certbot.timer
# Hoặc xem cronjob (nếu dùng cron thay vì systemd)
cat /etc/cron.d/certbot

Điều quan trọng hơn: sau khi gia hạn, Nginx phải được reload để dùng cert mới. Kiểm tra deploy hook:

cat /etc/letsencrypt/renewal-hooks/deploy/

Chưa có hook? Thêm luôn:

cat > /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh << 'EOF'
#!/bin/bash
systemctl reload nginx
EOF
chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

Tips thực tế từ kinh nghiệm vận hành

1. Kiểm tra certificate bằng lệnh openssl

# Xem ngày hết hạn
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com \
  < /dev/null 2>/dev/null | openssl x509 -noout -dates

# Xem toàn bộ thông tin cert
openssl s_client -connect yourdomain.com:443 < /dev/null 2>/dev/null \
  | openssl x509 -noout -text | grep -A 2 "Subject Alternative"

2. Xử lý lỗi thường gặp

“Connection refused” hoặc timeout khi certbot chạy
→ Kiểm tra firewall: sudo ufw status và đảm bảo port 80 mở.

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

“Too many certificates already issued for exact set of domains”
→ Let’s Encrypt giới hạn 5 cert/domain/tuần. Test trước bằng --staging:

sudo certbot --nginx --staging -d yourdomain.com

Nginx vẫn dùng cert cũ sau khi gia hạn
→ Reload Nginx thủ công: sudo nginx -s reload. Sau đó thêm deploy hook như hướng dẫn ở trên để không gặp lại lần sau.

3. Backup certificate

Cert nằm tại /etc/letsencrypt/ — backup thư mục này trước khi migrate server:

sudo tar -czf letsencrypt-backup-$(date +%Y%m%d).tar.gz /etc/letsencrypt/

4. Thu hồi certificate khi không cần nữa

sudo certbot revoke --cert-name yourdomain.com
sudo certbot delete --cert-name yourdomain.com

5. Monitoring tự động

Cron job này gửi log gia hạn vào email mỗi sáng — tiện để biết có lỗi gì không mà không cần vào server kiểm tra thủ công:

# Thêm vào crontab: kiểm tra hằng ngày lúc 9 giờ sáng
0 9 * * * /usr/bin/certbot renew --quiet --post-hook "systemctl reload nginx" 2>&1 | mail -s "Certbot renew log" [email protected]

Ghép thêm UptimeRobot hoặc Uptime Kuma để monitor từ bên ngoài — bạn sẽ biết cert có vấn đề trước khi user phàn nàn, không phải sau.

Share: