ACME là viết tắt của:
Automatic Certificate Management Environment
Đây là một giao thức tiêu chuẩn cho phép:
Tự động cấp chứng chỉ SSL
Tự động gia hạn
Không cần xác nhận thủ công qua email
Certbot là client phổ biến nhất triển khai giao thức ACME.
ACME challenge là cơ chế xác thực quyền sở hữu tên miền do Let’s Encrypt (và các CA tự động khác) sử dụng trước khi cấp hoặc gia hạn chứng chỉ SSL/TLS.
1. Mục tiêu của bài 11.1
Khi hệ thống có hàng trăm domain, việc cấp/gia hạn chứng chỉ Let’s Encrypt phải đáp ứng 3 yêu cầu:
Đồng nhất: domain nào cũng xác thực được theo cùng một cơ chế.
Tách biệt: ACME challenge không phụ thuộc backend (QMS/AI) đang sống hay chết.
Vận hành đơn giản: thêm domain mới không cần “nghĩ lại” cách làm.
Giải pháp tốt nhất trong mô hình Reverse Proxy là:
ACME challenge được phục vụ trực tiếp trên Reverse Proxy, từ một thư mục webroot dùng chung, thông qua đường dẫn chuẩn:
/.well-known/acme-challenge/
2. Vì sao không nên để ACME phụ thuộc backend
Nếu anh để Nginx proxy toàn bộ request (kể cả .well-known) về backend, thì khi:
Backend QMS lỗi,
Hoặc chuyển failover sang AI chưa kịp,
Hoặc backend đang deploy/restart,
Let’s Encrypt có thể không xác thực được domain, dẫn đến:
Không cấp được cert mới,
Không renew được cert sắp hết hạn,
Tăng rủi ro downtime hàng loạt.
Do đó, ACME challenge phải “độc lập” với backend.
3. Chuẩn hóa một webroot dùng chung cho toàn hệ thống
3.1. Tạo thư mục webroot dùng cho Let’s Encrypt
Ghi chú:
www-datalà user chạy Nginx trên Debian.Thư mục
_letsencryptđược đặt riêng để tránh trộn với nội dung web khác.
3.2. Tạo file test để kiểm tra nhanh
4. Chuẩn hóa snippet ACME dùng chung
4.1. Tạo snippet ACME
File: /etc/nginx/snippets/letsencrypt-acme.conf
# Serve ACME challenge locally on Reverse Proxy (independent from backend)
location ^~ /.well-known/acme-challenge/ {
root /var/www/_letsencrypt;
default_type "text/plain";
allow all;
}Vai trò:
Mọi request đến
/.well-known/acme-challenge/sẽ được trả trực tiếp từ proxy.Không đi qua backend.
Dùng chung cho toàn bộ domain.
5. Gắn snippet ACME vào mọi server block HTTP (80)
5.1. Mẫu server block HTTP chuẩn (kịch bản B)
server {
listen 80;
server_name qlcl.example.com;
include snippets/letsencrypt-acme.conf;
return 301 https://$host$request_uri;
}
Lý do đặt ở HTTP (80):
Let’s Encrypt HTTP-01 challenge mặc định xác thực qua cổng 80.
Dù domain đã chạy HTTPS, ACME vẫn cần “đường” trên port 80 khi gia hạn theo HTTP-01.
6. Gắn ACME cho mọi domain mà không sửa từng file: dùng include chung
Với hàng trăm site, nếu phải tự thêm include snippets/letsencrypt-acme.conf; vào từng file, rủi ro quên là rất cao. Có hai cách chuẩn hóa ở cấp hệ thống.
Cách 1 (khuyến nghị): include ở nginx.conf trong http {}
Mở file:
/etc/nginx/nginx.conf
Trong block http { ... }, thêm:
Nhưng lưu ý kỹ thuật:
Snippet này chứa location, nên chỉ include được trong context server {}, không include trực tiếp ở http {}.
Vì vậy, cách 1 chỉ đúng khi snippet không dùng location. Với ACME dùng location, ta nên dùng cách 2.
Mình dùng cách 2
Cách 2 (thực tế nhất): tạo “HTTP template” dùng chung cho tất cả site
Ta chuẩn hóa cấu trúc để mọi file site đều có block 80 và include snippet ACME như một “quy ước bắt buộc”.
Ví dụ: mọi file site đều bắt đầu bằng:
Ưu điểm:
Rõ ràng, dễ audit.
Không phụ thuộc thủ thuật include phức tạp.
7. Kiểm tra ACME hoạt động đúng
Sau khi cấu hình, reload Nginx:
Kiểm tra từ bên ngoài Internet (hoặc từ máy có thể truy cập domain):
Kết quả mong đợi:
HTTP 200
Body:
acme-ok
Nếu trả về 301 sang HTTPS vẫn ổn, miễn là:
Let’s Encrypt vẫn truy cập được nội dung (thường vẫn OK).
Tuy nhiên để chắc chắn, khuyến nghị để location ACME đứng trước return redirect như mẫu.
8. Chọn phương thức Certbot phù hợp sau khi đã chuẩn hóa ACME
Sau khi có webroot dùng chung, anh có thể dùng 2 kiểu:
8.1. Dùng --nginx (tiện, nhanh)
8.2. Dùng --webroot (kiểm soát tuyệt đối, phù hợp hệ thống lớn)
Khuyến nghị với hệ thống hàng trăm domain:
Ưu tiên
certonly --webrootđể Certbot không tự sửa file cấu hình.Nginx cấu hình theo chuẩn kịch bản B.
9. Các lỗi thường gặp và cách xử lý
Lỗi 1: 404 khi truy cập đường dẫn challenge
Nguyên nhân:
Thiếu include snippet ACME trong server block 80
Sai
root
Cách xử lý:
Kiểm tra file site có dòng:
include snippets/letsencrypt-acme.conf;
Lỗi 2: 403 forbidden
Nguyên nhân:
Permission thư mục không cho Nginx đọc
Cách xử lý:
Lỗi 3: Domain trỏ sai DNS / NAT chưa đúng
Nguyên nhân:
Domain chưa trỏ về IP public của modem/router
NAT chưa forward port 80 về proxy
Cách xử lý:
Xác thực DNS trước (A record đúng).
Xác thực port 80 từ ngoài Internet truy cập được.
Kết luận
Chuẩn hóa ACME challenge theo cơ chế:
một webroot dùng chung (
/var/www/_letsencrypt)một snippet dùng chung (
snippets/letsencrypt-acme.conf)mọi domain đều include snippet trong server block 80
giúp hệ thống:
Renew cert ổn định ngay cả khi backend lỗi,
Mở rộng hàng trăm domain không tăng rủi ro vận hành,
Giữ cấu hình Nginx sạch, đồng nhất theo template.
- Đăng nhập để gửi ý kiến