HTTPS giờ là mặc định. Trình duyệt đánh dấu trang HTTP là "Không an toàn", và nhiều tính năng web chỉ chạy trên HTTPS. Let's Encrypt cấp chứng chỉ SSL/TLS miễn phí, còn Certbot là công cụ tự xin, cài và gia hạn chứng chỉ đó. Bài này giúp bạn bật HTTPS cho website chạy Nginx trên Ubuntu, tự động chuyển HTTP sang HTTPS và chắc chắn chứng chỉ tự gia hạn đúng hạn.
Bạn cần chuẩn bị:
- VPS Ubuntu 22.04 hoặc 24.04 đã cài Nginx, có server block với
server_name example.com www.example.com;. - Bản ghi A của
example.comvàwww.example.comtrỏ về IP VPS (ví dụ203.0.113.10), đã lan truyền xong. - Cổng 80 và 443 mở trên tường lửa. Let's Encrypt cần truy cập cổng 80 để xác thực.
Bước 1: Kiểm tra DNS và cổng 80
Certbot thất bại phần lớn vì DNS chưa trỏ đúng. Kiểm tra trước:
dig +short example.com A
dig +short www.example.com A
sudo ufw status | grep -E '80|443|Nginx'
Cả hai tên phải trả về 203.0.113.10. Nếu có bản ghi AAAA (IPv6), nó cũng phải trỏ đúng VPS, vì Let's Encrypt ưu tiên IPv6 khi có. Bản ghi AAAA sai là nguyên nhân lỗi khó phát hiện.
dig +short example.com AAAA
Bước 2: Cài Certbot qua snap
Tài liệu chính thức của Certbot khuyến nghị cài qua snap để luôn có bản mới. Gỡ bản cài từ apt nếu có, tránh xung đột:
sudo apt remove -y certbot
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
certbot --version
Snap đã có sẵn trên Ubuntu Server. Nếu lệnh ln báo file đã tồn tại, bạn có thể bỏ qua.
Bước 3: Xin và cài chứng chỉ cho Nginx
Plugin --nginx tự đọc server block, xác thực tên miền và sửa cấu hình để bật HTTPS.
sudo certbot --nginx -d example.com -d www.example.com
Lần đầu, Certbot hỏi email và yêu cầu đồng ý điều khoản. Email dùng cho thông báo quan trọng về tài khoản. Khi xong, bạn sẽ thấy đường dẫn chứng chỉ:
/etc/letsencrypt/live/example.com/fullchain.pem
/etc/letsencrypt/live/example.com/privkey.pem
Certbot bản mới mặc định thêm chuyển hướng HTTP sang HTTPS. Mở lại file cấu hình để xem các dòng được thêm, có ghi chú # managed by Certbot:
sudo cat /etc/nginx/sites-available/example.com
sudo nginx -t && sudo systemctl reload nginx
Nếu chỉ muốn lấy chứng chỉ mà không cho Certbot sửa cấu hình Nginx, dùng sudo certbot certonly --nginx -d example.com -d www.example.com, sau đó tự khai báo ssl_certificate và ssl_certificate_key.
Bước 4: Kiểm tra cơ chế tự gia hạn
Bản snap cài sẵn một systemd timer chạy hai lần mỗi ngày. Certbot chỉ gia hạn khi chứng chỉ gần hết hạn, nên chạy thường xuyên không gây hại.
systemctl list-timers | grep certbot
sudo certbot renew --dry-run
Lệnh --dry-run thử gia hạn với máy chủ staging, không cấp chứng chỉ thật. Nếu kết quả báo Congratulations, all simulated renewals succeeded, cơ chế tự gia hạn đã ổn. Xem danh sách chứng chỉ và ngày hết hạn:
sudo certbot certificates
Bước 5: Thêm hook reload dịch vụ sau khi gia hạn
Với plugin --nginx, Certbot tự reload Nginx. Nhưng nếu chứng chỉ còn dùng cho dịch vụ khác (mail server, ứng dụng Docker…), bạn cần hook. Script trong thư mục renewal-hooks/deploy chạy sau mỗi lần gia hạn thành công:
sudo nano /etc/letsencrypt/renewal-hooks/deploy/reload-services.sh
#!/bin/sh
systemctl reload nginx
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-services.sh
Bước 6: Cấp chứng chỉ wildcard bằng xác thực DNS (tùy chọn)
Chứng chỉ *.example.com chỉ cấp được qua DNS-01. Cách thủ công:
sudo certbot certonly --manual --preferred-challenges dns -d example.com -d '*.example.com'
Certbot sẽ yêu cầu tạo bản ghi TXT _acme-challenge.example.com với một chuỗi ngẫu nhiên. Đợi bản ghi lan truyền rồi mới nhấn Enter. Kiểm tra bằng:
dig +short TXT _acme-challenge.example.com @1.1.1.1
Lưu ý: chứng chỉ cấp bằng --manual không tự gia hạn được. Để tự động, hãy dùng plugin DNS phù hợp với nơi quản lý DNS của bạn, ví dụ certbot-dns-cloudflare, kèm API token.
Bước 7: Theo dõi hạn chứng chỉ
Let's Encrypt đã ngừng gửi email nhắc hết hạn từ năm 2025. Theo kế hoạch đã công bố, thời hạn chứng chỉ mặc định sẽ giảm từ 90 ngày xuống 64 ngày (tháng 2/2027) rồi 45 ngày (tháng 2/2028). Vì vậy bạn nên:
- Không tự viết cron gia hạn theo số ngày cố định. Hãy để Certbot quyết định thời điểm.
- Dùng một dịch vụ giám sát uptime có kiểm tra hạn SSL để nhận cảnh báo.
- Tự kiểm tra định kỳ bằng lệnh dưới đây.
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates -issuer
Kiểm tra lại
- Truy cập
http://example.com: phải tự chuyển sanghttps://example.comvới mã 301. curl -I http://example.comtrả về301và headerLocation: https://example.com/.sudo certbot renew --dry-runthành công.- Trong WordPress, vào Settings, General, đổi cả hai địa chỉ sang
https://. - Mở DevTools, tab Console, xem có cảnh báo "Mixed Content" không.
Lỗi thường gặp và cách xử lý
Timeout during connect (likely firewall problem)
Let's Encrypt không kết nối được cổng 80. Kiểm tra UFW, firewall của nhà cung cấp (security group) và chắc chắn Nginx đang lắng nghe: sudo ss -tlnp | grep ':80'.
Invalid response from http://example.com/.well-known/acme-challenge/... 404
Yêu cầu xác thực tới nhầm máy chủ hoặc nhầm server block. Nguyên nhân hay gặp: bản ghi AAAA trỏ sai, DNS chưa lan truyền, hoặc có quy tắc chặn file ẩn mà không loại trừ .well-known.
Could not automatically find a matching server block
Certbot không tìm thấy server_name khớp với tên miền. Thêm đúng server_name example.com www.example.com; vào server block, chạy sudo nginx -t, reload rồi chạy lại Certbot.
Too many certificates already issued
Bạn đã chạm giới hạn tần suất cấp chứng chỉ, thường do thử đi thử lại. Khi thử nghiệm, hãy thêm --dry-run hoặc --test-cert để dùng máy chủ staging, không tính vào giới hạn.
Mixed Content sau khi bật HTTPS
Nội dung cũ còn liên kết http://. Với WordPress, dùng WP-CLI: wp search-replace 'http://example.com' 'https://example.com' --all-tables --dry-run, kiểm tra kết quả rồi chạy lại không có --dry-run. Nhớ sao lưu database trước.