Ubuntu 24.04 安裝 Certbot 於 Apache 步驟教學
本文介紹在 Ubuntu 24.04 上使用 apt 安裝 Certbot 2.9.0 以取得 Let's Encrypt 憑證。重點解析 ServerName 設定錯誤、Port 80 驗證失敗以及 AAAA record 導致的 HTTP-01 challenge 失敗等常見問題。
建立目標
在 Ubuntu 24.04 上建立一個 Apache 網站,並透過 Let's Encrypt 提供 HTTPS 服務。該憑證由 Certbot 核發,並透過 systemd timer 自動續期,無需手動管理。執行核心作業僅需一行指令。若流程失敗,問題通常發生在該指令執行之前:例如 vhost 缺少 ServerName、供應商防火牆封鎖了 port 80,或是 DNS 指向舊的伺服器。因此,本指南將重點放在前置作業,並列出各項錯誤對應的錯誤字串。
兩點說明。若您使用的是 nginx,流程架構相同,但套件與設定檔不同,請參閱 nginx 版本指南。若您的目標僅供內部使用(例如私有位址上的管理介面或無人訪問的測試主機),則不需要憑證授權單位;使用 自簽憑證 結構更簡單且支援離線運作。
前置作業,以及 Certbot 執行前可能失敗的三種情況
- Apache 已透過 plain HTTP 提供網站服務。 Certbot 的 Apache plugin 會修改現有的網站設定,而非建立新網站。若您使用的是全新的 VPS,請先建立 Ubuntu 24.04 上的 LAMP stack,本指南是該架構缺失的 TLS 章節。
- 具備指向 VPS 位址 A record 的公開網域。 Let's Encrypt 的 HTTP-01 challenge 要求其驗證伺服器從網路連線至您的主機:未進行 port forward 的 NAT 環境(如 home lab)、
.local名稱或純 IP 皆無法通過。dig +short example.com必須回傳您的 VPS 位址;若您在過去一小時內更改過 DNS,請等待舊紀錄的 TTL 過期後再進行核發。 - 若存在 AAAA record,其內容必須正確。 當有 AAAA record 發布時,Let's Encrypt 會優先使用 IPv6。即使從您的筆電(通常使用 IPv4)進行
curl運作正常,過時的 AAAA record 仍會導致驗證失敗。請發布正確的 AAAA record,或完全不發布。
Port 80 與 443 必須同時在 ufw 以及供應商的網路防火牆中開啟 — 大多數主機控制台都有 OS 無法偵測到的第二層防火牆。HTTP-01 專門透過 port 80 進行驗證;您無法僅在 443 執行此操作。
sudo ufw allow "Apache Full"
sudo ufw status完成上述設定後,整個流程僅需 15 分鐘,其中 10 分鐘用於閱讀。
使用 Snap 或 apt 安裝 Certbot?在 24.04 版本中,apt 已可正常使用
Certbot 多年前轉向 snap 發行是基於合理考量:發行版套件更新緩慢。Ubuntu 20.04 仍停留在 Certbot 0.40 版本且未再更新,導致開發團隊必須處理過時的錯誤。在 24.04 版本中,此問題已解決 —— 軟體庫提供當代版本的 Certbot 2.9.0,且 unattended-upgrades 會持續提供修補程式。針對此作業系統,我的建議是:使用 apt。這樣可以省去 snapd 守護行程,Apache 插件會在同一個安裝程序中完成,且續期定時器會以標準的 Debian 方式整合至 systemd。
sudo apt update
sudo apt install -y certbot python3-certbot-apache
certbot --version正確結果:certbot 2.9.0。python3-certbot-apache 套件是負責讀取與編輯 Apache 設定檔的插件 —— 若缺少此套件,certbot --apache 會因 The requested apache plugin does not appear to be installed 而失敗。
在以下兩種情況下,使用 snap 仍是正確選擇:你需要在使用最新版 Certbot 的當天立即取得,或是你需要僅透過 snap 發行的 DNS 插件(certbot-dns-* 的多個供應商插件即是如此)。若選擇此方式:
sudo apt remove -y certbot python3-certbot-apache
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot無論選擇哪種方式,切勿同時執行兩者。同時安裝兩者會導致兩個續期排程器爭奪 /etc/letsencrypt,且 PATH 中 shell 找到的 certbot 可能並非管理憑證的對象。上述的 apt remove 行並非可省略的裝飾。
vhost 的 Certbot 編輯必須已存在 — ServerName 是關鍵
certbot --apache 的運作原理是尋找 port-80 的 virtual host,其 ServerName 或 ServerAlias 必須與您傳入的每個 -d 網域相符,藉此證明對該網域的控制權,接著為該 vhost 寫入一個 SSL 副本。若無匹配的 ServerName,則無法匹配 — 而 Ubuntu 預設的 000-default.conf 會將 ServerName 註解掉。這行被註解的設定,是導致本指南中單一指令失敗最常見的原因。
因此在操作 Certbot 之前,請先為網站設定正確的名稱型 vhost。建立 /etc/apache2/sites-available/example.com.conf:
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com
ErrorLog ${APACHE_LOG_DIR}/example.com-error.log
CustomLog ${APACHE_LOG_DIR}/example.com-access.log combined
</VirtualHost>啟用該設定,並確認 Apache 能正確解析並將名稱路由至該 vhost:
sudo a2ensite example.com.conf
sudo apache2ctl configtest
sudo systemctl reload apache2
sudo apache2ctl -Sconfigtest 必須輸出 Syntax OK。如果同時輸出 AH00558: apache2: Could not reliably determine the server's fully qualified domain name,那是針對 global ServerName 的警告,而非針對您的 vhost — 在此情況下無害,且會被 echo "ServerName $(hostname -f)" | sudo tee /etc/apache2/conf-available/servername.conf && sudo a2enconf servername && sudo systemctl reload apache2 靜音。
-S 的輸出才是關鍵檢查點。您應該看到類似 port 80 namevhost example.com (/etc/apache2/sites-enabled/example.com.conf:1) 且下方帶有 alias www.example.com 的行 — Apache 回報的是它實際讀取的 sites-enabled 符號連結,而非您在 sites-available 中編輯的檔案。若 port 80 下未列出 example.com,Certbot 也將無法找到它。
發行憑證:certbot --apache
sudo certbot --apache -d example.com -d www.example.com首次執行時會詢問三個項目:電子郵件地址(用於您的 ACME 帳戶與緊急 CA 通知;Let's Encrypt 不再發送過期警告,因此您必須自行監控續訂狀況)、是否同意 Let's Encrypt 條款,以及是否與 EFF 分享您的電子郵件。現在不再詢問重定向問題:自 Certbot 2.0 起,Apache 安裝程式預設會將 HTTP 重定向至 HTTPS,這符合一般需求。若您確實需要維持 plain HTTP 以提供內容,請傳遞 --no-redirect 參數。
成功完成的畫面如下,請仔細閱讀而非略讀:
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/example.com/privkey.pem
This certificate expires on 2026-10-14.
Deploying certificate
Successfully deployed certificate for example.com to /etc/apache2/sites-available/example.com-le-ssl.conf
Successfully deployed certificate for www.example.com to /etc/apache2/sites-available/example.com-le-ssl.conf
Congratulations! You have successfully enabled HTTPS on https://example.com and https://www.example.com在該訊息背後,Certbot 執行了四項操作:若 Apache 的 ssl 模組尚未啟用,則將其啟用;寫入 example.com-le-ssl.conf —— 這是位於 *:443 的 vhost 副本,包含 SSLEngine on 與憑證路徑;啟用該模組;並在原始的 port-80 vhost 中加入一個 RewriteRule 區塊,將所有請求 301 重定向至 HTTPS。系統會修改您的原始 vhost 檔案而非替換它,且 SSL 副本會與其並存,您可以閱讀其新增的每一行內容。
憑證的實際存放位置,以及為何絕不應進行複製
所有檔案皆存放於 /etc/letsencrypt/live/example.com/:fullchain.pem(包含憑證與中間憑證鏈,伺服器應指向此處)、privkey.pem(僅限 root 可讀取的私鑰),以及提供給需要獨立檔案之軟體的 cert.pem 與 chain.pem。這些檔案是指向 /etc/letsencrypt/archive/ 的 symlinks,此間接機制即為更新機制:更新程序會將新檔案寫入 archive/ 並重新指向 symlinks。若將其他軟體指向 live/ 路徑,即可自動取得更新後的憑證;若將檔案複製到其他地方,則會在 90 天後導致服務中斷。
另一個值得注意的檔案是 /etc/letsencrypt/renewal/example.com.conf,它記錄了此憑證的核發資訊 —— 包括 authenticator = apache、installer = apache 以及網域 —— 如此更新程序才能在無需人工干預的情況下重複執行,並在完成後重新載入 Apache。
續期已排定 — 請進行驗證,切勿重複建立
Let's Encrypt 憑證設計有效期為 90 天,且 apt 套件已安裝好相關機制:一個 systemd timer 會在每天隨機時間執行兩次 Certbot,並自動續期任何距離到期日不足 30 天的憑證。請勿額外新增 cron job;重複的排程器只會增加日誌雜訊並增加觸發速率限制(rate-limit)的風險。
systemctl list-timers certbot.timer
sudo certbot renew --dry-run第一條指令會顯示 timer 處於啟動狀態,且 NEXT 時間會在未來 24 小時內 — 排程為每天兩次且帶有隨機延遲,因此確切時間是刻意不可預測的(若使用 snap 安裝,timer 會是 snap.certbot.renew.timer)。dry run 會針對 Let's Encrypt 的 staging 環境進行完整的續期演練 — 會進行真實的驗證(challenge),但不會核發憑證,也不會消耗速率限制額度。正確結果會以以下內容結尾:
Congratulations, all simulated renewals succeeded:
/etc/letsencrypt/live/example.com/fullchain.pem (success)若 dry run 失敗,約 60 天後的實際續期也會以同樣方式失敗 — 請趁目前憑證仍有充足有效期時立即修復。常見原因是在核發憑證後新增了防火牆規則,導致 80 port 再次被封鎖。
使用 curl 驗證,以及鎖頭圖示應顯示的內容
curl -sI http://example.com | head -n 3
curl -I https://example.com
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -issuer -dates第一個指令應回傳 HTTP/1.1 301 Moved Permanently 並帶有 Location: https://example.com/ 標頭 — 這是 Certbot 安裝的重新導向。第二個指令應回傳 HTTP/1.1 200 OK 且 curl 不會出現 TLS 錯誤。第三個指令會印出發行者 — 即包含 R12 或 E7 等簡短 CN 的 O = Let's Encrypt 行 — 以及 notAfter 左右的有效期限。在瀏覽器中,你會看到鎖頭圖示,點擊後會顯示相同的發行者。如果 curl 運作正常但瀏覽器發出警告,問題幾乎可以確定是快取頁面或主機名稱錯誤,而非憑證問題。
多個網站:使用單一 SAN 憑證或每個網站使用獨立憑證
兩者皆可行,且續期方式相同。若同一台主機上有不相關的網站,請為每個網站分別執行一次指令。每個網站會在 live/ 下擁有獨立目錄與續期設定,且單一網域的問題不會阻礙其他網域的續期。這是我的預設做法。
若單一網站包含多個名稱,請將其整合至單一 SAN 憑證中 — 單一憑證最多可包含 100 個名稱。您先前在 example.com 與 www.example.com 的操作中已完成此動作。若日後需為現有憑證新增名稱,請重新發行並提供完整的全新名稱清單:
sudo certbot --apache --cert-name example.com -d example.com -d www.example.com -d blog.example.comCertbot 會偵測到網域集合已變更,並要求您確認擴充,接著會直接替換原有的憑證 — 使用相同的 live/ 路徑,因此無需更動其他設定。請注意,此清單是「替換」而非「新增」:若在指令中省略 www,新憑證將會直接移除該網域。
Wildcards 需要 DNS-01,且通常您並不需要 wildcard
HTTP-01 無法核發 *.example.com — 在 web server 放置檔案僅能證明對單一 hostname 的控制權,而非整個 namespace。Wildcards 需要使用 DNS-01 驗證:Certbot 會在 _acme-challenge.example.com 設定 TXT record。實務上,這代表需要使用具備 DNS provider API 憑證的 certbot-dns-* plugin,或是每次續期時都手動使用 --manual 編輯 TXT record(過程繁瑣,請勿以此作為作業流程)。從 TXT record 機制到可自動續期的 plugin 之完整指南,請參閱 wildcard certificates with Certbot over DNS-01。誠懇建議:若您有四個已知的 subdomains,核發包含這四個名稱的 SAN certificate 會比 wildcard 更簡單,且不需要在 server 上存放 DNS API keys。
Failure modes, with the strings you will see
Certbot refuses to start because Apache's config is broken.
The apache plugin is not working; there may be problems with your existing configuration.
The error was: MisconfigurationError('Error while running apache2ctl configtest.\n\nAction \'configtest\' failed.\nThe Apache error log may have more information.\n\nAH00526: Syntax error on line 12 of /etc/apache2/sites-enabled/example.com.conf')Plugin 會在執行任何操作前先執行 configtest,若 Apache 設定有誤則會停止執行 — \ns 是原始錯誤訊息,因為 Certbot 會直接印出 exception 的 repr。請自行執行 sudo apache2ctl configtest:它會顯示檔案名稱與行號 — 通常是因為手動編輯導致的打字錯誤、指向不存在路徑的 SSLCertificateFile,或是引用了未啟用的模組。請修正錯誤直到印出 Syntax OK,然後重新執行 Certbot。
No vhost matches the domain.
Unable to find a virtual host listening on port 80 which is currently the only challenge port.這是先前提到的缺少 ServerName 錯誤,會在執行 issue 時被偵測到。Certbot 搜尋了所有已啟用的 port-80 vhost,尋找與您的 -d 相符的 ServerName/ServerAlias,但未找到任何結果。sudo apache2ctl -S 會顯示 Apache 實際的路由設定;請在正確的 vhost 中加入 ServerName 行,重新載入並重試。另一種常見情況是驗證請求路由到了 錯誤的 vhost — 因為另一個網站接收了該請求,導致 challenge response 回傳 Invalid response ... 404。診斷方式與工具相同:apache2ctl -S。
Validation times out.
Certbot failed to authenticate some domains (authenticator: apache).
...
Detail: ...: Timeout during connect (likely firewall problem)Let's Encrypt 無法透過 DNS 解析的位址與 port 80 建立 TCP 連線。按發生機率排序:供應商的網路防火牆(與 ufw 不同,是在主機控制台設定)、僅允許 443 或僅允許 SSH 的 ufw 規則集、DNS 仍指向舊伺服器,或是 stale-AAAA 問題 — Let's Encrypt 伺服器嘗試使用 IPv6,但您的伺服器僅回應 IPv4。請從 VPS 外部 進行測試:從您的筆電執行 curl -I http://example.com 即可重現驗證器的錯誤。
You retried your way into a rate limit.
Error creating new order :: too many failed authorizations recently: see https://letsencrypt.org/docs/rate-limits/Let's Encrypt 限制每個帳戶的每個主機名稱每小時只能有 5 次失敗的驗證 — 自 2025 年限制機制重構後,這是一個「漏斗式」機制,大約每 12 分鐘會恢復一次重試額度 — 對著錯誤的防火牆不斷重試會迅速耗盡額度。等待是可行的,但真正的解決方法是改變行為:發生任何失敗後,請先使用 staging 環境進行除錯,直到成功為止。
sudo certbot certonly --apache --dry-run -d example.com -d www.example.com請注意 certonly:--dry-run 僅能由 certonly 與 renew 子指令接受,直接使用 certbot --apache --dry-run 形式會無法執行並顯示 --dry-run currently only works with the 'certonly' or 'renew' subcommands。dry run 會針對 staging 環境進行驗證,staging 有較寬鬆的限制且不發放正式憑證,因此您可以多次嘗試。只有在 staging 通過後,才重新執行正式指令。其他限制(每個註冊網域每週 50 張憑證、每個名稱集每週 5 次重複)只有在腳本陷入無止盡的重發迴圈時才會觸發。
HTTPS 啟用後,請記住憑證保護的是 傳輸層,而非伺服器本身:port 22 仍會持續遭受密碼暴力破解。建議接下來的 30 分鐘可以搭配 Fail2ban on Ubuntu 24.04 使用。
FAQ
在 Ubuntu 24.04 的 Apache 環境下,我應該使用 snap 還是 apt 來安裝 Certbot?
請使用 apt。Ubuntu 24.04 內建的 Certbot 版本為 2.9.0,足以應付本指南的所有需求,並透過 unattended-upgrades 取得安全性更新,且不需要安裝 snapd。僅在需要立即取得最新版本,或需要僅透過 snap 發行的 DNS plugin 時才選擇 snap;若決定切換,請先執行 apt remove certbot python3-certbot-apache,以避免同時存在兩個更新排程器。
為什麼 Certbot 顯示 "Unable to find a virtual host listening on port 80"?
因為目前沒有啟用的 port-80 vhost 包含與您透過 -d 傳入之網域名稱相符的 ServerName 或 ServerAlias。Ubuntu 預設的 vhost 會將 ServerName 註解掉。請執行 sudo apache2ctl -S,找到(或建立)應負責該名稱的 vhost,加入 ServerName example.com,重新載入 Apache,然後重新執行 Certbot。
如何修復 "Timeout during connect (likely firewall problem)"?
Let's Encrypt 無法透過您的 DNS 發布位址連線至 port 80。請檢查供應商控制台層級的網路防火牆以及 ufw,確認 dig +short example.com 回傳的是此 VPS,並刪除或修正過時的 AAAA 紀錄——若存在 IPv6,驗證程序會優先使用 IPv6。請在伺服器外部使用 curl -I http://example.com 確認修復結果,並在正式核發前使用 sudo certbot certonly --apache --dry-run -d example.com 進行測試。
Certbot 會在 Ubuntu 24.04 上自動更新憑證嗎?
會。apt 套件會安裝 certbot.timer,這是一個每日執行兩次的 systemd timer,會自動更新任何有效期剩餘 30 天以內的憑證,並在之後重新載入 Apache;snap 則是使用 snap.certbot.renew.timer 執行相同任務。請使用 systemctl list-timers certbot.timer 進行驗證,並使用 sudo certbot renew --dry-run 進行測試——請勿自行額外新增 cron job。
如何使用 Certbot 和 Apache 取得萬用字元憑證 (wildcard certificate)?
萬用字元憑證需要使用 DNS-01 驗證:Certbot 必須在 _acme-challenge.example.com 放置一筆 TXT 紀錄,這代表需要使用具備 DNS 供應商 API 憑證的 certbot-dns-* plugin(若使用 --manual 方案,每次更新都必須手動編輯 TXT 紀錄)。如果您只需要針對少數已知的子網域名稱,使用明確列出這些名稱的 SAN 憑證會更簡單,且能避免將 DNS API 金鑰儲存在伺服器上。