SSD Nodes Learn
指南 Matt Connor作者: Matt Connor · 已更新 2026-07-24

Certbot 如何申請 DNS-01 驗證的萬用憑證

本文教學如何使用 Certbot 透過 DNS-01 驗證方式申請 Wildcard 憑證。說明 TXT 紀錄的工作原理、如何選擇正確的 DNS 插件,並解決手動建立紀錄導致無法自動續期的問題。

為什麼萬用憑證需要 DNS-01

萬用憑證(Wildcard certificate)涵蓋網域下的所有第一層次子網域:*.example.com 可匹配 app.example.comblog.example.com 以及任何其他單層標籤名稱。Let's Encrypt 僅透過 DNS-01 驗證方式核發萬用憑證,因此 Certbot 必須在 _acme-challenge.example.com 發布 TXT 紀錄,以證明對該網域 DNS 的控制權。HTTP-01 驗證無法滿足需求,因為提供 token 檔案僅能證明對單一主機名稱(即驗證伺服器抓取檔案的該主機名稱)擁有控制權。萬用憑證是對該網域下所有可能名稱的聲明,而 DNS 是唯一能代表整個命名空間的公開紀錄。

這項要求決定了本頁面的所有其他內容。若要通過 DNS-01 驗證,您必須能夠在該網域的區域(zone)中建立 TXT 紀錄,無論是手動建立或透過 DNS 提供商的 API(應用程式介面)。手動建立的方式僅能使用一次,隨後在續期時會失敗,具體原因如下文所示。透過 Certbot DNS 插件進行的 API 方式可實現自動續期,這才是建議的設定方式。

這是我們 Certbot 指南中的萬用憑證章節。一般的單一主機名稱憑證、web server 設定以及 port 80 規則,請參閱 Certbot with nginx on Ubuntu 24.04Certbot with Apache on Ubuntu 24.04

_acme-challenge TXT 紀錄的工作原理

當 Certbot 要求 *.example.com 時,Let's Encrypt 會回傳一個隨機 token。Certbot 會將該 token 與您的 ACME (automatic certificate management environment) 帳戶金鑰結合,並使用 SHA-256 進行雜湊運算,最後產生一段簡短的文字值。該值必須作為 TXT 紀錄出現在 _acme-challenge.example.com。接著,Let's Encrypt 會從其基礎設施查詢您網域的權威名稱伺服器 (authoritative name servers)。若讀取到的紀錄與預期值相符,即代表您已證明擁有該 zone 的控制權;擁有該 zone 的控制權即等同擁有其下所有名稱的控制權。

以下兩個細節會導致大多數失敗:

  • 在同一張憑證上同時要求 example.com*.example.com,代表存在兩個獨立的驗證 (challenges),且兩者的 TXT 紀錄都位於相同的名稱 _acme-challenge.example.com。兩者必須同時存在。正確做法是新增第二筆紀錄;若用第二筆紀錄取代第一筆,則會導致第一個驗證失敗。
  • 驗證程序是讀取您的權威伺服器,但供應商的控制面板可能需要一分鐘或更長時間才能將新紀錄同步至伺服器。在執行驗證前,請先從外部進行檢查:
dig +short TXT _acme-challenge.example.com @1.1.1.1

當輸出結果顯示 Certbot 所要求的數值時,驗證即可成功。若輸出結果為空,請稍候後再次執行。

進行一次手動測試:手動模式

手動模式需由您自行編輯 DNS,這是自動化之前理解其機制的最佳方式:

sudo certbot certonly --manual --preferred-challenges dns -d example.com -d '*.example.com'

在萬用字元(wildcard)兩側加上引號,可防止 shell 將 * 視為檔案名稱模式。Certbot 會暫停並顯示指令:

Please deploy a DNS TXT record under the name:
_acme-challenge.example.com.
with the following value:
Jx9mQ2wLr8vTn5cKp0aYdG3hB7fZs4eN1oiRuXqMk6E

請在您的 DNS 提供商控制台中建立該 TXT 紀錄,並使用上述 dig 指令確認其已生效,接著再按下 Enter。由於此執行程序同時要求基礎網域與萬用字元,Certbot 會提示兩次;在憑證核發完成前,請務必保留這兩筆紀錄。成功完成後會顯示以下內容:

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem

為什麼手動模式無法自動續期

每次續期都會產生新的 token,因此 TXT 值每次都會變動。您今天貼上的紀錄在 60 天後將失效。Certbot 的續期計時器每天會自動執行兩次,屆時沒有人能手動貼上新值,因此手動核發的憑證會因以下錯誤而導致續期失敗:

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.')

您可以透過編寫呼叫 DNS 提供商 API 的 --manual-auth-hook 腳本來滿足此需求,但這等同於手動重建 DNS plugin。手動模式僅適用於學習流程,或用於尚無法自動化 DNS 的單次需求。請務必在第 90 天前設定提醒,因為 Let's Encrypt 不再發送過期通知郵件。除此之外的所有情況,請使用 plugin。

插件路徑:Ubuntu 24.04 上的 certbot-dns-cloudflare

DNS 插件會持有 DNS 提供商的 API 憑證,並在憑證核發與每次續期時,自動完成所有 TXT 紀錄的變更作業。本範例以 Cloudflare 為例,因為這是大多數使用者最需要的提供商插件,且已包含在 Ubuntu 套件中。

我們的 Certbot 指南建議在 Ubuntu 24.04 上使用 apt 套件,此建議同樣適用於 Cloudflare:

sudo apt update
sudo apt install certbot python3-certbot-dns-cloudflare

關於版本的說明。24.04 軟體庫提供的此插件版本為 2.0.0,搭配 Certbot 2.9.0;apt policy python3-certbot-dns-cloudflare 顯示您目前的版本。版本不一致並無影響,且具備權限範圍的 API tokens 可正常運作,因為 24.04 底層的 python3-cloudflare 函式庫版本為 2.11.1,高於插件支援 tokens 所需的 2.3.1。在舊版 Ubuntu 中,該函式庫版本過低無法支援 tokens,這也是網路上常見「apt 插件會強制使用 Global API Key」警告的原因。在 24.04 上,這些問題已不再存在。

請在 Cloudflare 控制台建立具備權限範圍的 API token,而非使用 Global API Key:進入 My Profile,接著選擇 API Tokens,然後點擊 Create Token,僅設定單一權限 Zone / DNS / Edit,並限制在您要核發憑證的單一 zone。請將其存放在僅限 root 讀取的檔案中:

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.ini

Certbot 會檢查檔案權限,若檔案可被他人讀取,則會針對 Unsafe permissions on credentials configuration file 發出警告。接著執行核發:

sudo certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
  -d example.com -d '*.example.com'

插件會透過 API 建立 TXT 紀錄,等待短暫的傳播延遲,執行驗證,最後再次刪除紀錄。若您 zone 的 name servers 偵測變更的速度較慢,請使用 --dns-cloudflare-propagation-seconds 60 增加等待時間。憑證會存放於 /etc/letsencrypt/live/example.com/,您可以依照基礎指南中的說明,將 nginx 或 Apache 指向 fullchain.pemprivkey.pem,並包含 deploy hook。

若您的供應商套件未包含在 apt 中

24.04 存檔僅針對少數供應商提供套件,其中包含 Cloudflare、Route 53、DigitalOcean 以及通用的 RFC 2136 介面。請執行 apt search certbot-dns 以查看列表。若您的供應商不在列表中,則須打破我們「apt 優先」的建議:請改用 snap 安裝 Certbot 與對應套件,並先移除 apt 版的 Certbot,以避免兩個更新排程同時爭奪 /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-yourprovider

snap 套件僅能連接至 snap 版的 Certbot;它無法擴充 apt 版的套件,因此這兩個安裝版本不能同時存在。若您的 DNS 主機完全不提供 API,您可行的方案包括:將網域的 DNS 遷移至提供 API 的供應商,或是自行運行 name server 並將 rfc2136 套件指向該伺服器。

續期:立即驗證,而非等待 60 天後

Certbot 會將每張憑證的核發資訊記錄於 /etc/letsencrypt/renewal/example.com.conf,包含 authenticator = dns-cloudflare 與憑證路徑,因此標準的每日兩次排程即可自動完成續期。請針對 staging 環境進行完整演練:

sudo certbot renew --dry-run

若測試通過,代表憑證驗證流程完全正確;60 天後的正式續期將遵循相同路徑。建議今日完成以下兩項後續作業。首先,磁碟上更新後的憑證在 Web server 重新載入前不會生效,因此請依照 nginx 與 Apache 指南設定 deploy hook。其次,請妥善保護憑證檔案:任何具備讀取權限的人都能修改您的 DNS zone,進而足以重新導向您的郵件或通過其自身的 DNS-01 驗證。請將該檔案於 /root 下設定為 mode 600,將 token 範圍限制在單一 zone,若懷疑憑證外洩,請立即進行輪換 (rotate)。

不需要使用萬用字元 (wildcard) 的情境

萬用字元適用於多個子網域,或無法預測的子網域。對於其他情境,不應將其作為預設選項。

  • 若僅需一個或少數幾個已知的子網域:使用一般的 SAN (subject alternative name) 憑證更簡單。透過 plain HTTP-01,certbot --nginx -d example.com -d www.example.com -d app.example.com 最多可涵蓋 100 個名稱,且伺服器端無需存放任何 DNS API 憑證。
  • 萬用字元僅匹配單一標籤。*.example.com 不包含 bare example.com,因此上述指令會同時請求兩者;此外,它也不包含 a.b.example.com,該需求需使用 *.b.example.com
  • 每個子網域都有對應的私鑰。若持有私鑰的機器遭入侵,萬用字元涵蓋的所有名稱都會同時受到影響。
  • 若 Traefik 為容器處理 TLS (transport layer security),則完全不需要使用 Certbot:Traefik 可透過 DNS-01 自行請求萬用字元憑證,並使用相同的 provider token。

萬用字元的真正用途:當子網域(針對特定客戶或應用程式)的建立速度快於憑證重新簽發的速度,或是針對沒有公開 80 port 的內部主機,例如僅能透過 WireGuard VPN 存取的服務。由於 DNS-01 不需要連接被認證的主機,因此即使是完全私有的機器也能持有公開信任的憑證。

FAQ

Certbot 是否能透過 HTTP-01 簽發 wildcard certificate?

不能。HTTP-01 僅能證明對單一 hostname 的控制權,因為驗證伺服器是從該特定名稱抓取 token 檔案。由於 wildcard 涵蓋該 domain 下的所有名稱,因此 Let's Encrypt 要求使用 DNS-01 challenge,而 --nginx--apache--webroot--standalone 驗證器皆基於 HTTP。唯一的途徑是在 _acme-challenge.example.com 建立 TXT record,並透過手動或 DNS plugin 進行配置。

wildcard certificate 是否涵蓋 root domain?

不會。Wildcard 僅匹配單一 label,因此 *.example.com 涵蓋 www.example.com,但不涵蓋 bare example.com 以及 a.b.example.com。請使用 -d example.com -d '*.example.com' 在單一證書中請求這兩個名稱。這會產生兩個 challenge,且兩個 TXT record 都位於相同的 _acme-challenge.example.com 名稱下,因此新增第二筆記錄時請勿刪除第一筆。

為什麼我的 wildcard certificate 無法自動續期?

因為該證書是使用 --manual 簽發的。每次續期都需要全新的 TXT 值,而 unattended timer 無法自動貼上該值,導致續期因錯誤 An authentication script must be provided with --manual-auth-hook when using the manual plugin non-interactively 而停止。請改用 DNS plugin(例如 certbot-dns-cloudflare)重新簽發證書,或是提供 --manual-auth-hook--manual-cleanup-hook 腳本,透過供應商的 API 來編輯記錄。

_acme-challenge TXT record 需要多久才會出現?

這取決於您的 DNS provider:從幾秒鐘到幾分鐘不等。驗證程序會讀取您 zone 的 authoritative servers,因此請使用 dig +short TXT _acme-challenge.example.com @1.1.1.1 進行檢查,並在預期值出現後再繼續手動執行。若驗證回報找不到記錄,請透過 plugin 的 propagation option(例如 --dns-cloudflare-propagation-seconds 60)來增加內建的等待時間。

wildcard certificate 的安全性比一般證書低嗎?

加密技術完全相同。差異在於維運層面:單一 private key 涵蓋所有 subdomain,因此一旦遭破解,影響範圍較廣;此外,自動化所需的 DNS API 憑證本身也是儲存在伺服器上的敏感機密。如果您僅運行少數已知的 subdomains,使用 SAN certificate 可避免上述問題,這也是本指南建議跳過 wildcard 的原因。