Chứng chỉ SSL/TLS miễn phí từ Let's Encrypt có thời hạn mặc định là 90 ngày. Trong điều kiện vận hành thông thường, tiện ích Certbot chạy tự động qua systemd timer hoặc crontab hai lần mỗi ngày để tự động gia hạn khi chứng chỉ còn dưới 30 ngày.
Tuy nhiên, sau khi bạn bật tính năng ủy quyền (Proxy - đám mây màu cam) trên Cloudflare để bảo vệ IP gốc và tăng tốc độ tải trang, quá trình tự động gia hạn này thường bị gián đoạn. Nhiều quản trị viên chỉ phát hiện ra sự cố khi trình duyệt cảnh báo chứng chỉ hết hạn (tham khảo thêm cách chẩn đoán tại bài Chứng chỉ SSL hết hạn hoặc lỗi chuỗi chứng chỉ: cách kiểm tra), hoặc Cloudflare trả về màn hình lỗi Error 526: Invalid SSL certificate do chế độ SSL/TLS trên Cloudflare đang đặt ở mức Full (Strict).
Khi chạy thử lệnh gia hạn thủ công trên máy chủ VPS:
sudo certbot renew --dry-runLệnh thường kết thúc với thông báo lỗi xác thực thất bại: Certbot failed to authenticate some domains (HTTP-01): Invalid response from https://example.com/.well-known/acme-challenge/...
Nguyên nhân không xuất phát từ phần mềm Certbot bị lỗi, mà nằm ở sự xung đột giữa cơ chế xác thực quyền sở hữu tên miền của Let's Encrypt và các lớp bảo vệ mạng biên của Cloudflare Proxy.
Cơ chế xác thực HTTP-01 challenge bị chặn bởi lớp proxy trung gian của Cloudflare.
Vì sao cơ chế HTTP-01 Challenge thất bại sau Cloudflare Proxy?
Mặc định, Certbot sử dụng phương thức xác thực HTTP-01 Challenge (theo tài liệu kỹ thuật tại Let's Encrypt - Challenge Types). Quy trình này hoạt động theo 3 bước:
- Certbot tạo một tệp tin tạm thời chứa chuỗi mã hóa ngẫu nhiên trong thư mục web root của máy chủ (thường tại
/.well-known/acme-challenge/<TOKEN>). - Certbot gửi yêu cầu tới máy chủ xác thực của Let's Encrypt CA để thông báo tệp tin đã sẵn sàng.
- Let's Encrypt CA thực hiện phân giải DNS của tên miền để lấy địa chỉ IP, sau đó gửi một yêu cầu HTTP GET đến cổng 80 (
http://example.com/.well-known/acme-challenge/<TOKEN>) để đọc nội dung tệp tin đó. Nếu nội dung khớp với mã hóa, chứng chỉ mới sẽ được cấp phát.
Khi tên miền chưa bật proxy (đám mây màu xám trên Cloudflare), bản ghi DNS trỏ trực tiếp về địa chỉ IP của máy chủ VPS. Let's Encrypt kết nối thẳng tới web server (Nginx/Apache) và đọc file thành công.
Tuy nhiên, ngay khi bạn bật proxy đám mây màu cam:
- Địa chỉ IP bị che giấu: Máy chủ Let's Encrypt phân giải tên miền sẽ nhận về dải địa chỉ IP mạng biên (Anycast IP) của Cloudflare chứ không phải IP của máy chủ VPS. Yêu cầu HTTP GET buộc phải đi qua hạ tầng Cloudflare trước khi đến được máy chủ của bạn.
- Tính năng Always Use HTTPS: Nếu Cloudflare được bật tùy chọn tự động chuyển hướng toàn bộ kết nối HTTP sang HTTPS, yêu cầu kiểm tra cổng 80 của Let's Encrypt sẽ nhận về mã chuyển hướng 301/302. Một số cấu hình Nginx phía sau xử lý chuyển hướng lặp vòng hoặc chứng chỉ cũ đã hết hạn khiến kết nối HTTPS bị từ chối ngay tại biên.
- Lớp tường lửa WAF và Bot Management: Các tính năng bảo vệ như Bot Fight Mode, Under Attack Mode hoặc quy tắc chặn truy cập theo quốc gia trên Cloudflare có thể nhận diện các máy chủ kiểm tra tự động của Let's Encrypt là lưu lượng bot bất thường, từ đó phản hồi mã chặn
403 Forbiddenhoặc hiển thị trang thử thách bảo mật (Turnstile / Managed Challenge). Khi không đọc được file token, Let's Encrypt lập tức hủy phiên xác thực.
Bước 1: Kiểm tra log xác thực và mã lỗi cụ thể của Certbot
Khi quá trình tự động gia hạn gặp sự cố, bạn không nên thử chạy lệnh gia hạn thực tế nhiều lần liên tiếp để tránh chạm trần giới hạn tần suất yêu cầu (Rate Limit: 5 lần thất bại mỗi giờ cho cùng một tài khoản) của Let's Encrypt.
Thay vào đó, bạn sử dụng tham số --dry-run để chạy mô phỏng trên môi trường kiểm thử (Staging Server) của Let's Encrypt:
# Chạy mô phỏng gia hạn để kiểm tra lỗi mà không ảnh hưởng tới chứng chỉ hiện tại
sudo certbot renew --dry-runNếu lệnh báo lỗi, mở file nhật ký chi tiết tại /var/log/letsencrypt/letsencrypt.log để đọc nguyên nhân từ máy chủ CA:
# Xem 50 dòng log cuối cùng của phiên kiểm tra
sudo tail -n 50 /var/log/letsencrypt/letsencrypt.logDựa vào mã phản hồi HTTP từ Let's Encrypt, bạn có thể xác định chính xác điểm nghẽn:
1. Mã lỗi 403 Forbidden hoặc xuất hiện trang thử thách bảo mật
Thông báo log có dạng:
Detail: 104.21.xx.xx: Invalid response from https://example.com/.well-known/acme-challenge/abc...: 403Địa chỉ IP 104.21.xx.xx hiển thị trong log chính là IP của Cloudflare Edge. Điều này cho thấy yêu cầu từ Let's Encrypt đã đến được Cloudflare nhưng bị hệ thống tường lửa của Cloudflare chặn lại trước khi kịp chuyển tiếp về máy chủ VPS của bạn.
Nguyên nhân thường do:
- Tính năng Bot Fight Mode hoặc Super Bot Fight Mode trên Cloudflare đang phân loại bot xác thực tự động của Let's Encrypt vào nhóm bot độc hại và tự động chặn.
- Cấu hình WAF Custom Rules chặn các dải IP nước ngoài hoặc chặn User-Agent không phổ biến.
2. Mã lỗi 404 Not Found
Thông báo log có dạng:
Detail: 104.21.xx.xx: Invalid response from https://example.com/.well-known/acme-challenge/xyz...: 404Mã 404 cho biết yêu cầu đã được Cloudflare chuyển tiếp thành công về đến web server (Nginx/Apache) trên máy chủ VPS, nhưng web server không tìm thấy file token tương ứng trong thư mục lưu trữ.
Trường hợp này xảy ra khi:
- Đường dẫn
webrootcấu hình trong file/etc/letsencrypt/renewal/example.com.conftrỏ sai thư mục gốc của website (ví dụ cấu hình trỏ vào/var/www/htmltrong khi mã nguồn thực tế nằm tại/var/www/example.com/public). - File cấu hình Nginx có các chỉ thị rewrite hoặc reverse proxy (
proxy_pass) ôm toàn bộ các request (kể cả đường dẫn/.well-known/) chuyển tiếp vào ứng dụng backend (như Node.js, Python, Go) vốn không xử lý các file tĩnh này.
3. Mã lỗi Connection Refused hoặc Timeout
Thông báo log có dạng:
Detail: 104.21.xx.xx: Fetching http://example.com/.well-known/acme-challenge/...: Timeout during connectLỗi này xuất hiện khi máy chủ Cloudflare không thể kết nối tới máy chủ VPS của bạn qua cổng 80, thường do tường lửa máy chủ (ufw hoặc iptables) chỉ mở cổng 443 mà chặn cổng 80, hoặc do dịch vụ Nginx bị dừng.
Bước 2: Cấu hình thông luồng xác thực HTTP-01 qua Cloudflare và Nginx
Nếu bạn vẫn muốn duy trì phương thức xác thực HTTP-01 truyền thống, bạn cần cấu hình đồng thời trên bảng điều khiển Cloudflare và máy chủ web Nginx để các yêu cầu từ Let's Encrypt đi qua an toàn.
1. Tạo quy tắc WAF bỏ qua kiểm tra cho thư mục ACME trên Cloudflare
Để ngăn tường lửa Cloudflare và cơ chế chống bot chặn các yêu cầu xác thực, bạn tạo một quy tắc ngoại lệ (WAF Custom Rule):
- Truy cập vào bảng điều khiển Cloudflare, chọn tên miền tương ứng.
- Điều hướng tới mục Security > WAF > tab Custom Rules (hoặc Configuration Rules).
- Nhấp vào Create Rule và thiết lập điều kiện lọc (Expression):
- Field:
URI Path - Operator:
starts with - Value:
/.well-known/acme-challenge/
- Ở mục hành động (Action):
- Chọn Skip (hoặc Bypass).
- Đánh dấu chọn bỏ qua các tính năng: Bot Fight Mode, Security Level, Rate Limiting, và Managed Challenge.
- Nhấp Deploy để quy tắc có hiệu lực ngay lập tức.
Quy tắc này đảm bảo mọi yêu cầu có đường dẫn bắt đầu bằng /.well-known/acme-challenge/ sẽ được Cloudflare chuyển tiếp thẳng về máy chủ VPS mà không phải qua bất kỳ bước xác minh người dùng hay chặn bot nào.
2. Cấu hình Nginx xử lý riêng biệt đường dẫn ACME Challenge
Trên máy chủ VPS, file cấu hình Nginx của website cần có một khối location riêng biệt dành cho ACME challenge. Khối này phải được đặt trước các quy tắc rewrite chuyển hướng sang HTTPS và trước các khối proxy_pass.
Mở file cấu hình Nginx của tên miền (thường nằm tại /etc/nginx/sites-available/example.com):
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
# 1. Khối xử lý xác thực ACME Challenge (Không chuyển hướng sang HTTPS)
location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
root /var/www/letsencrypt;
allow all;
}
# 2. Toàn bộ các yêu cầu khác mới chuyển hướng sang HTTPS
location / {
return 301 https://$host$request_uri;
}
}Ý nghĩa kỹ thuật của cấu hình trên:
- Ký tự
^~là chỉ thị ưu tiên khớp tiền tố (prefix match). Khi URL bắt đầu bằng/.well-known/acme-challenge/, Nginx sẽ dừng ngay việc tìm kiếm các quy tắc regex khác và xử lý trực tiếp tại khối này. - Thư mục gốc được chỉ định cố định tại
/var/www/letsencryptthay vì dùng chung với thư mục mã nguồn website. Điều này giúp tiến trình của ứng dụng backend không bao giờ can thiệp vào file xác thực.
Tạo thư mục lưu trữ và phân quyền phù hợp:
# Tạo thư mục dùng chung cho toàn bộ chứng chỉ trên máy chủ
sudo mkdir -p /var/www/letsencrypt/.well-known/acme-challenge
sudo chown -R www-data:www-data /var/www/letsencrypt
# Kiểm tra cú pháp và tải lại Nginx
sudo nginx -t && sudo systemctl reload nginxCập nhật lại lệnh gia hạn của Certbot để sử dụng thư mục webroot mới:
sudo certbot renew --webroot -w /var/www/letsencrypt --dry-runNếu kết quả trả về Congratulations, all simulated renewals succeeded, quá trình thông luồng HTTP-01 đã thành công.
Bước 3: Giải pháp tự động hóa qua DNS-01 Challenge
Dù phương pháp HTTP-01 ở Bước 2 có thể hoạt động, nó vẫn tiềm ẩn rủi ro bị gián đoạn mỗi khi Cloudflare cập nhật các tính năng bảo mật mới, hoặc khi bạn vô tình thay đổi cấu hình Nginx.
Để giải quyết vấn đề này trên máy chủ đứng sau Cloudflare, bạn nên chuyển sang phương thức DNS-01 Challenge.
Cơ chế hoạt động của DNS-01 Challenge
Thay vì tạo file trên ổ đĩa và đọc qua cổng 80, Certbot sẽ kết nối trực tiếp đến Cloudflare thông qua giao diện lập trình ứng dụng (API) để:
- Tự động tạo một bản ghi DNS dạng
TXTvới tên_acme-challenge.example.comchứa chuỗi mã hóa xác thực. - Let's Encrypt CA kiểm tra bản ghi TXT này trực tiếp từ máy chủ tên miền (Nameserver) của Cloudflare.
- Sau khi xác thực thành công, Certbot tự động xóa bản ghi TXT đó đi.
Ưu điểm của phương thức này:
- Độc lập với web server: Không cần mở cổng 80, không bị ảnh hưởng bởi Nginx rewrite, WAF hay Bot Fight Mode.
- Hỗ trợ cấp chứng chỉ Wildcard: Cho phép cấp một chứng chỉ duy nhất dùng chung cho cả tên miền chính và toàn bộ tên miền con (
*.example.com).
1. Cài đặt plugin Cloudflare cho Certbot
Cài đặt tiện ích mở rộng tương ứng trên máy chủ Linux (theo tài liệu hướng dẫn certbot-dns-cloudflare documentation):
# Trên Ubuntu / Debian
sudo apt update && sudo apt install -y python3-certbot-dns-cloudflare
# Hoặc cài đặt qua Snap (nếu bạn sử dụng Certbot bản Snap)
sudo snap install certbot-dns-cloudflare
sudo snap set certbot trust-plugin-with-root=ok
sudo snap connect certbot:plugin certbot-dns-cloudflare2. Tạo API Token trên Cloudflare với quyền tối thiểu
Bạn không nên sử dụng khóa bí mật toàn cục (Global API Key) vì lý do an toàn bảo mật. Hãy tạo một API Token riêng biệt với phạm vi giới hạn:
- Đăng nhập Cloudflare, vào trang cá nhân (My Profile) > mục API Tokens.
- Chọn Create Token > sử dụng mẫu Edit zone DNS.
- Cấu hình chi tiết quyền hạn:
- Permissions:
Zone-DNS-Edit - Zone Resources:
Include-Specific zone- Chọn đúng tên miền của bạn.
- Nhấp Continue to summary và Create Token. Sao chép mã token hiển thị trên màn hình.
3. Lưu trữ Token an toàn trên máy chủ VPS
Tạo file chứa thông tin cấu hình tại thư mục bí mật của Certbot:
sudo mkdir -p /etc/letsencrypt
sudo nano /etc/letsencrypt/cloudflare.iniThêm nội dung sau vào file:
# Cloudflare API token dùng cho Certbot DNS-01 challenge
dns_cloudflare_api_token = DIEN_MA_API_TOKEN_CUA_BAN_VAO_DAY4. Cấp phát chứng chỉ mới qua DNS-01
Chạy lệnh cấp chứng chỉ sử dụng plugin DNS:
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
--dns-cloudflare-propagation-seconds 30 \
-d example.com \
-d *.example.comTham số --dns-cloudflare-propagation-seconds 30 yêu cầu Certbot đợi 30 giây để bản ghi DNS kịp đồng bộ trên toàn cầu trước khi gửi tín hiệu cho Let's Encrypt kiểm tra.
Sau khi lệnh hoàn tất thành công, các file cấu hình gia hạn sẽ tự động ghi nhớ phương thức này. Mọi lần gia hạn định kỳ trong tương lai sẽ diễn ra tự động qua API mà không cần can thiệp lại.
Khi nào nên chuyển sang Cloudflare Origin Certificate?
Nếu website của bạn luôn hoạt động sau lớp proxy của Cloudflare và không cần cho người dùng truy cập trực tiếp vào địa chỉ IP của máy chủ gốc, việc duy trì Certbot của Let's Encrypt trên máy chủ là không cần thiết.
Cloudflare cung cấp tính năng Cloudflare Origin CA Certificate (chi tiết tại Cloudflare Documentation - Origin CA Certificates) hoàn toàn miễn phí cho máy chủ gốc với những đặc điểm vận hành sau:
- Thời hạn chứng chỉ lên tới 15 năm: Bạn chỉ cần tạo và cấu hình một lần vào web server, không cần thiết lập tiến trình tự động gia hạn định kỳ sau mỗi 90 ngày.
- Bảo mật với chế độ Full (Strict): Hỗ trợ mã hóa hai chiều từ trình duyệt người dùng đến Cloudflare Edge và từ Cloudflare Edge về máy chủ VPS, ngăn ngừa nguy cơ can thiệp dữ liệu trên đường truyền.
- Hỗ trợ Wildcard mặc định: Một chứng chỉ áp dụng đồng thời cho tên miền chính và toàn bộ tên miền con (
example.comvà*.example.com).
Cách tạo và cấu hình Origin Certificate
- Trên bảng điều khiển Cloudflare, vào mục SSL/TLS > Origin Server.
- Nhấp Create Certificate > chọn thời hạn (khuyến nghị 15 năm) > nhấp Create.
- Cloudflare sẽ tạo ra hai đoạn mã:
- Origin Certificate: Lưu thành file
/etc/ssl/certs/cloudflare_origin.pemtrên VPS. - Private Key: Lưu thành file
/etc/ssl/private/cloudflare_origin.keytrên VPS.
Khóa quyền đọc cho file khóa riêng tư:
sudo chmod 600 /etc/ssl/private/cloudflare_origin.keyCập nhật đường dẫn chứng chỉ vào khối HTTPS của Nginx:
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /etc/ssl/certs/cloudflare_origin.pem;
ssl_certificate_key /etc/ssl/private/cloudflare_origin.key;
# Cấu hình bảo mật TLS khuyến nghị
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# Các cấu hình reverse proxy khác bên dưới...
}Kiểm tra và tải lại Nginx:
sudo nginx -t && sudo systemctl reload nginxCuối cùng, quay lại mục SSL/TLS > Overview trên Cloudflare và chuyển chế độ mã hóa sang Full (Strict).
Tóm tắt quy trình kiểm tra và xử lý
Khi Certbot không thể gia hạn chứng chỉ SSL sau Cloudflare Proxy, bạn thực hiện theo 4 bước:
- Kiểm tra mô phỏng: Chạy
sudo certbot renew --dry-runđể đọc thông báo lỗi từ Let's Encrypt mà không ảnh hưởng tới giới hạn yêu cầu. - Khoanh vùng nguyên nhân: Kiểm tra mã lỗi trong
/var/log/letsencrypt/letsencrypt.logđể xác định điểm nghẽn do WAF (403), cấu hình Nginx (404) hay kết nối cổng 80 (timeout). - Chọn phương án xử lý:
- Nếu giữ HTTP-01: Tạo quy tắc bypass WAF cho đường dẫn
/.well-known/acme-challenge/và cấu hình khốilocation ^~trên Nginx. - Nếu muốn tự động hóa lâu dài: Chuyển sang xác thực DNS-01 qua Cloudflare API Token với quyền
Zone.DNS:Edit.
- Cân nhắc giải pháp thay thế: Sử dụng Cloudflare Origin CA Certificate với thời hạn 15 năm và bật chế độ mã hóa Full (Strict) nếu website luôn chạy sau proxy.
Để chủ động theo dõi vòng đời chứng chỉ và tránh bị động khi hết hạn, bạn nên kết hợp công cụ giám sát tự động; tham khảo chi tiết tại bài Theo dõi thời hạn SSL và domain: cách thiết lập cảnh báo sớm. Nếu vừa thay đổi bản ghi DNS hoặc proxy nhưng gặp hiện tượng phản hồi không đồng nhất, hãy xem thêm bài DNS đã đổi nhưng website vẫn trỏ về máy chủ cũ: cách kiểm tra.



