Cấp chứng chỉ wildcard với Certbot qua DNS-01
Cấu hình Certbot cấp wildcard qua DNS-01: tạo TXT tại _acme-challenge, chọn plugin DNS và tự động gia hạn thay vì nhập bản ghi thủ công.
Vì sao chứng chỉ wildcard cần DNS-01
Chứng chỉ wildcard bao phủ mọi subdomain cấp đầu tiên của một domain: *.example.com khớp với app.example.com, blog.example.com và mọi tên khác chỉ sâu một label. Let's Encrypt chỉ cấp chứng chỉ wildcard thông qua challenge DNS-01, vì vậy Certbot phải chứng minh quyền kiểm soát DNS của domain bằng cách công bố bản ghi TXT tại _acme-challenge.example.com. Challenge HTTP-01 không đáp ứng được yêu cầu này, vì việc cung cấp một file token chỉ chứng minh quyền kiểm soát một hostname, tức hostname mà validation server đã truy cập để lấy file. Wildcard là một khai báo áp dụng cho mọi tên có thể có dưới domain, và bản ghi công khai duy nhất đại diện cho toàn bộ namespace là DNS.
Yêu cầu này quyết định mọi phần còn lại trên trang. Để vượt qua DNS-01, bạn phải có khả năng tạo bản ghi TXT trong zone của domain, thủ công hoặc thông qua API (application programming interface) của DNS provider. Cách thủ công hoạt động một lần rồi thất bại khi gia hạn, vì lý do cụ thể được trình bày bên dưới. Cách dùng API, thông qua plugin DNS của Certbot, có thể gia hạn tự động và đây là cấu hình bạn nên sử dụng sau cùng.
Đây là chương về wildcard trong bộ hướng dẫn Certbot của chúng tôi. Chứng chỉ thông thường cho một hostname, cấu hình web server và các quy tắc cho port 80 được trình bày trong Certbot với nginx trên Ubuntu 24.04 và Certbot với Apache trên Ubuntu 24.04.
Cách hoạt động của bản ghi TXT _acme-challenge
Khi Certbot yêu cầu *.example.com, Let's Encrypt trả về một token ngẫu nhiên. Certbot kết hợp token đó với account key ACME (automatic certificate management environment) của bạn, băm kết quả bằng SHA-256 rồi tạo ra một giá trị văn bản ngắn. Giá trị đó phải xuất hiện dưới dạng bản ghi TXT tại _acme-challenge.example.com. Sau đó, Let's Encrypt truy vấn các name server authoritative của domain từ hạ tầng của chính họ. Nếu bản ghi mà hệ thống đọc được khớp với giá trị mà hệ thống mong đợi, bạn đã chứng minh quyền kiểm soát zone. Quyền kiểm soát zone được chấp nhận là quyền kiểm soát mọi name bên dưới zone đó.
Có 2 chi tiết gây ra phần lớn lỗi:
- Yêu cầu
example.comvà*.example.comtrong cùng một certificate nghĩa là có 2 challenge riêng biệt. Cả 2 bản ghi TXT đều nằm tại cùng một name,_acme-challenge.example.com. Cả 2 phải tồn tại đồng thời. Thêm bản ghi thứ hai là đúng; thay thế bản ghi thứ nhất bằng bản ghi thứ hai sẽ khiến challenge thứ nhất thất bại. - Validation đọc dữ liệu từ các server authoritative của bạn, nhưng control panel của provider có thể mất 1 phút hoặc lâu hơn để đẩy bản ghi mới đến các server đó. Hãy kiểm tra từ bên ngoài trước khi cho validation chạy:
dig +short TXT _acme-challenge.example.com @1.1.1.1Khi lệnh đó in ra giá trị mà Certbot yêu cầu, validation có thể thành công. Khi lệnh không in ra gì, hãy chờ rồi chạy lại.
Xem hoạt động một lần: chế độ thủ công
Chế độ thủ công yêu cầu bạn tự chỉnh sửa DNS. Đây là cách tốt nhất để hiểu cơ chế trước khi tự động hóa:
sudo certbot certonly --manual --preferred-challenges dns -d example.com -d '*.example.com'Dấu ngoặc kép quanh wildcard ngăn shell xử lý * như một mẫu tên tệp. Certbot sẽ tạm dừng và hiển thị hướng dẫn:
Please deploy a DNS TXT record under the name:
_acme-challenge.example.com.
with the following value:
Jx9mQ2wLr8vTn5cKp0aYdG3hB7fZs4eN1oiRuXqMk6ETạo bản ghi TXT đó trong bảng điều khiển của nhà cung cấp DNS, xác nhận bản ghi đã hiển thị bằng lệnh dig ở trên, rồi mới nhấn Enter. Vì lần chạy này yêu cầu domain gốc và wildcard, Certbot sẽ hỏi 2 lần. Giữ cả 2 bản ghi cho đến khi quá trình cấp chứng chỉ hoàn tất. Khi thành công, đầu ra sẽ kết thúc bằng các dòng quen thuộc:
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pemVì sao chế độ thủ công không thể tự gia hạn
Mỗi lần gia hạn là một thử thách mới với token mới, nên giá trị TXT thay đổi mỗi lần. Bản ghi bạn dán hôm nay sẽ vô dụng sau 60 ngày. Bộ hẹn giờ gia hạn chạy Certbot ở chế độ không cần giám sát 2 lần mỗi ngày, và không có ai ngồi trước bàn phím để dán giá trị mới. Vì vậy, chứng chỉ được cấp ở chế độ thủ công sẽ gia hạn thất bại với lỗi chính xác sau:
Failed to renew certificate example.com with error: The manual plugin is not
working; there may be problems with your existing configuration.
The error was: PluginError('An authentication script must be provided with
--manual-auth-hook when using the manual plugin non-interactively.')Bạn có thể đáp ứng yêu cầu đó bằng cách viết các script --manual-auth-hook gọi API của nhà cung cấp DNS, nhưng khi đó bạn đang tự xây dựng lại một DNS plugin. Hãy dùng chế độ thủ công để tìm hiểu quy trình, hoặc dùng cho một lần duy nhất trên domain mà bạn chưa thể tự động hóa DNS, đồng thời đặt lời nhắc trước ngày 90 thật lâu, vì Let's Encrypt không còn gửi email thông báo sắp hết hạn. Với mọi trường hợp khác, hãy dùng plugin.
Route dùng plugin: certbot-dns-cloudflare trên Ubuntu 24.04
Một DNS plugin lưu credential API của nhà cung cấp DNS và tự thực hiện toàn bộ quy trình tạo bản ghi TXT, khi cấp chứng chỉ và trong mỗi lần gia hạn. Ở đây dùng Cloudflare làm ví dụ vì đây là provider plugin mà nhiều người cần nhất và đã được đóng gói trong Ubuntu.
Các hướng dẫn Certbot của chúng tôi khuyến nghị dùng các gói apt trên Ubuntu 24.04. Khuyến nghị này cũng áp dụng cho Cloudflare:
sudo apt update
sudo apt install certbot python3-certbot-dns-cloudflareCó một điểm cần lưu ý về version. Kho lưu trữ của 24.04 cung cấp plugin này ở version 2.0.0 cùng với Certbot 2.9.0; apt policy python3-certbot-dns-cloudflare hiển thị version của bạn. Việc lệch version này không gây vấn đề. Scoped API token vẫn hoạt động vì thư viện python3-cloudflare bên dưới trong 24.04 là version 2.11.1, cao hơn version 2.3.1 mà plugin cần để hỗ trợ token. Trên các bản Ubuntu cũ hơn, thư viện đó quá cũ để hỗ trợ token. Đây là nguyên nhân của các cảnh báo bạn có thể thấy trên mạng về việc apt plugin buộc phải dùng Global API Key. Trên 24.04, các cảnh báo đó không còn áp dụng.
Trong Cloudflare dashboard, hãy tạo một scoped API token, không dùng Global API Key: vào My Profile, chọn API Tokens, rồi chọn Create Token. Chỉ cấp permission Zone / DNS / Edit và giới hạn token cho zone duy nhất bạn sẽ cấp chứng chỉ. Lưu token vào một file chỉ root có thể đọc:
sudo mkdir -p /root/.secrets
sudo tee /root/.secrets/cloudflare.ini > /dev/null <<'EOF'
dns_cloudflare_api_token = paste_your_scoped_token_here
EOF
sudo chmod 600 /root/.secrets/cloudflare.iniCertbot kiểm tra mode của file và cảnh báo về Unsafe permissions on credentials configuration file nếu những user khác có thể đọc file. Bây giờ hãy cấp chứng chỉ:
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
-d example.com -d '*.example.com'Plugin tạo các bản ghi TXT thông qua API, chờ một khoảng thời gian ngắn để DNS propagation, cho phép quá trình validation chạy, rồi xóa các bản ghi. Nếu name server của zone cập nhật thay đổi chậm, hãy tăng thời gian chờ bằng --dns-cloudflare-propagation-seconds 60. Certificate được lưu tại /etc/letsencrypt/live/example.com/. Bạn trỏ nginx hoặc Apache đến fullchain.pem và privkey.pem đúng như trong các hướng dẫn cơ bản, bao gồm cả deploy hook.
Nếu plugin của nhà cung cấp không có trong apt
Kho lưu trữ 24.04 chỉ đóng gói plugin cho một số nhà cung cấp, trong đó có Cloudflare, Route 53, DigitalOcean và giao diện RFC 2136 chung. Chạy apt search certbot-dns để xem danh sách. Nếu không có nhà cung cấp của bạn, đây là trường hợp duy nhất chúng tôi không áp dụng khuyến nghị ưu tiên apt: thay vào đó, hãy cài Certbot và plugin từ snap, đồng thời gỡ Certbot cài bằng apt trước để hai renewal timer không tranh nhau xử lý /etc/letsencrypt:
sudo apt remove certbot python3-certbot-dns-cloudflare
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
sudo snap set certbot trust-plugin-with-root=ok
sudo snap install certbot-dns-yourproviderPlugin snap chỉ kết nối với Certbot snap; nó không thể mở rộng Certbot apt. Vì vậy, không được để hai bản cài đặt cùng tồn tại. Nếu máy chủ DNS của bạn không cung cấp API, các lựa chọn thực tế là chuyển DNS của domain sang nhà cung cấp có API, hoặc tự chạy name server và trỏ plugin rfc2136 vào đó.
Gia hạn: chứng minh ngay bây giờ, không phải sau 60 ngày
Certbot ghi lại cách mỗi certificate được cấp trong /etc/letsencrypt/renewal/example.com.conf, bao gồm authenticator = dns-cloudflare và đường dẫn đến credentials, để timer chạy 2 lần mỗi ngày có thể gia hạn certificate mà không cần bạn can thiệp. Hãy diễn tập toàn bộ quy trình với staging environment:
sudo certbot renew --dry-runKết quả thành công cho biết credential hoạt động và quá trình validation hoàn tất từ đầu đến cuối; lần gia hạn thực tế sau 60 ngày sẽ đi theo cùng quy trình. Hôm nay nên thực hiện thêm 2 việc. Thứ nhất, certificate đã gia hạn trên disk chưa có hiệu lực cho đến khi web server reload certificate đó, vì vậy hãy cấu hình deploy hook được mô tả trong các hướng dẫn về nginx và Apache. Thứ hai, hãy bảo vệ credentials file: bất kỳ ai có thể đọc file này đều có thể chỉnh sửa DNS zone của bạn. Việc đó đủ để chuyển hướng mail hoặc tự vượt qua các DNS-01 challenge. Đặt file ở mode 600 trong /root, giới hạn token cho một zone và rotate token nếu bạn nghi ngờ credentials đã bị lộ.
Khi bạn không cần wildcard
Wildcard phù hợp với nhiều subdomain hoặc các subdomain bạn không thể dự đoán trước. Đây không phải lựa chọn mặc định phù hợp cho mọi trường hợp khác.
- Một subdomain hoặc một số ít subdomain đã biết: certificate SAN (subject alternative name) thông thường đơn giản hơn.
certbot --nginx -d example.com -d www.example.com -d app.example.comhỗ trợ tối đa 100 tên qua HTTP-01 thông thường và không cần lưu credential của DNS API trên server. - Wildcard chỉ khớp đúng một label.
*.example.comkhông bao phủexample.comkhông có label, vì vậy các lệnh ở trên yêu cầu cả hai tên này. Wildcard cũng không bao phủa.b.example.com; trường hợp đó cần*.b.example.com. - Một private key được dùng cho mọi subdomain. Nếu máy lưu private key đó bị breach, mọi tên được wildcard bao phủ sẽ đồng thời bị ảnh hưởng.
- Nếu Traefik xử lý TLS (transport layer security) cho các container, bạn không cần Certbot: Traefik tự yêu cầu wildcard certificate qua DNS-01, bằng loại provider token tương tự.
Wildcard thực sự hữu ích cho các subdomain theo từng khách hàng hoặc ứng dụng, được tạo nhanh hơn tốc độ bạn muốn issue lại certificate, và cho các host nội bộ không có port 80 public, chẳng hạn các service chỉ có thể truy cập qua VPN WireGuard. DNS-01 không bao giờ kết nối đến host đang được cấp certificate, vì vậy ngay cả một máy hoàn toàn private cũng có thể giữ certificate được public trust.
FAQ
Certbot có thể cấp chứng chỉ wildcard bằng HTTP-01 không?
Không. HTTP-01 xác minh quyền kiểm soát một hostname vì máy chủ xác minh sẽ tải tệp token từ đúng tên đó. Wildcard bao phủ mọi tên bên dưới domain, nên Let's Encrypt yêu cầu challenge DNS-01. Các authenticator --nginx, --apache, --webroot và --standalone đều hoạt động qua HTTP. Cách duy nhất là tạo bản ghi TXT tại _acme-challenge.example.com, thủ công hoặc bằng DNS plugin.
Chứng chỉ wildcard có bao phủ domain gốc không?
Không. Wildcard chỉ khớp đúng một label. Vì vậy, *.example.com khớp với www.example.com nhưng không khớp với example.com dạng trần và cũng không khớp với a.b.example.com. Hãy yêu cầu cả hai tên trên cùng một chứng chỉ bằng -d example.com -d '*.example.com'. Thao tác này tạo ra hai challenge. Cả hai bản ghi TXT đều nằm tại cùng tên _acme-challenge.example.com, nên hãy thêm bản ghi thứ hai mà không xóa bản ghi thứ nhất.
Vì sao chứng chỉ wildcard của tôi không tự động gia hạn?
Vì chứng chỉ được cấp bằng --manual. Mỗi lần gia hạn cần một giá trị TXT hoàn toàn mới. Timer chạy tự động không thể tự nhập giá trị này, nên quá trình gia hạn dừng với lỗi An authentication script must be provided with --manual-auth-hook when using the manual plugin non-interactively. Hãy cấp lại chứng chỉ bằng DNS plugin như certbot-dns-cloudflare, hoặc cung cấp các script --manual-auth-hook và --manual-cleanup-hook để chỉnh sửa bản ghi thông qua API của nhà cung cấp.
Mất bao lâu để bản ghi TXT _acme-challenge xuất hiện?
Thời gian phụ thuộc vào nhà cung cấp DNS, từ vài giây đến vài phút. Quá trình xác minh đọc các authoritative server của zone, nên hãy kiểm tra bằng dig +short TXT _acme-challenge.example.com @1.1.1.1 và chờ đến khi giá trị mong đợi xuất hiện trước khi tiếp tục lần chạy thủ công. Khi dùng plugin, hãy tăng thời gian chờ propagation tích hợp thông qua tùy chọn propagation của plugin, chẳng hạn --dns-cloudflare-propagation-seconds 60, nếu quá trình xác minh báo không tìm thấy bản ghi.
Chứng chỉ wildcard có kém an toàn hơn chứng chỉ thông thường không?
Mật mã học là như nhau. Khác biệt nằm ở vận hành: một private key bao phủ mọi subdomain, nên nếu bị lộ thì phạm vi ảnh hưởng rộng hơn. Ngoài ra, credential của DNS API mà automation cần cũng là một secret nhạy cảm được lưu trên server. Nếu bạn chỉ chạy một vài subdomain đã biết, chứng chỉ SAN tránh được cả hai vấn đề. Đây chính là trường hợp guide này khuyến nghị không dùng wildcard.