Carbonio 申請 SSL 憑證 (DNS-01)
使用 acme.sh 搭配 Cloudflare DNS API。 這種方式不需要開放 Port 80,它是透過驗證您的 DNS 擁有權來發憑證,非常適合內網或防火牆後的伺服器。
操作步驟 (在 Carbonio VM 內,root 權限):
A. 基本操作
- 安裝 acme.sh:
curl https://get.acme.sh | sh
source ~/.bashrc- 設定 Cloudflare API Key: (去 Cloudflare 後台 > My Profile > API Tokens > 建立一個有編輯 DNS 權限的 Token)
export CF_Token="您的_Cloudflare_API_Token"
export CF_Account_ID="您的_Account_ID"- Account ID 要到 cloudflare 帳戶首頁 > [email protected]'s Account 旁邊的 ... > 複製帳戶 ID
- 申請憑證 (自動驗證 DNS):
acme.sh --issue --dns dns_cf -d mail.yourdomain.com- 自動部署到 Carbonio (關鍵腳本): Carbonio 的憑證格式比較特殊,不能只申請,還要安裝。可以寫一個 Hook 腳本讓 acme.sh 每次更新時自動執行:
# 這是讓 acme.sh 自動把憑證裝進 Carbonio 的指令
acme.sh --install-cert -d mail.yourdomain --cert-file /opt/zextras/ssl/carbonio/commercial/commercial.crt --key-file /opt/zextras/ssl/carbonio/commercial/commercial.key --ca-file /opt/zextras/ssl/carbonio/commercial/commercial_ca.crt --reloadcmd "wget -O /tmp/ISRG-Root-X1.pem https://letsencrypt.org/certs/isrgrootx1.pem.txt && cat ~/.acme.sh/mail.yourdomain_ecc/ca.cer /tmp/ISRG-Root-X1.pem > /opt/zextras/ssl/carbonio/commercial/commercial_ca.crt && chown zextras:zextras /opt/zextras/ssl/carbonio/commercial/* && su - zextras -c 'zmcertmgr deploycrt comm /opt/zextras/ssl/carbonio/commercial/commercial.crt /opt/zextras/ssl/carbonio/commercial/commercial_ca.crt' && systemctl restart carbonio.target"設定好之後,acme.sh 會每 60 天自動幫您做完這些事,您再也不用管它。
B. 驗證設定
要確認 acme.sh 的自動續期任務(Cron Job)是否成功建立,可以從三個層次來檢查:系統定時任務、acme.sh 配置清單,以及 續期日誌。
- 檢查系統 Cron 任務
- acme.sh 在安裝時會自動在當前使用者的 crontab 中加入一條指令。這條指令每天會執行兩次,檢查憑證是否快過期。
crontab -l | grep acme.sh- 預期結果: 你應該會看到類似下面這一行,這代表系統會定時去觸發
acme.sh的續期檢查:0 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null
- 檢查憑證清單 (List)
- 你可以直接詢問
acme.sh目前管理了哪些憑證,以及它們的續期時間。
acme.sh --list
- 預期結果: 你應該會看到類似下面的內容
Main_Domain KeyLength SAN_Domains Profile CA Created Renew
mail.yourdomain "ec-256" no LetsEncrypt.org <date>T<time>Z <date+60>T<time>Z- 確認重點:
- Main_Domain: 是否包含
mail.yourdomain.com。 - Renew: 是否顯示了下一次預計續期的日期。
- 如果出現在清單中,代表該網域已成功進入自動管理流程。
- Main_Domain: 是否包含
- 查看網域詳細配置 (Config)
- 如果你想確認你剛剛輸入的那串長長的路徑(
--cert-file等參數)是否有被正確紀錄,可以查看該網域的設定檔。
cat ~/.acme.sh/mail.yourdomain_ecc/mail.yourdomain.conf | grep Le_
- 預期結果: 你應該會看到類似下面的內容
Le_Domain='mail.yourdomain'
Le_Alt='no'
Le_Webroot='dns_cf'
Le_PreHook=''
Le_PostHook=''
Le_RenewHook=''
Le_API='https://acme-v02.api.letsencrypt.org/directory'
Le_Keylength='ec-256'
Le_OrderFinalize='https://acme-v02.api.letsencrypt.org/acme/finalize/'
Le_LinkOrder='https://acme-v02.api.letsencrypt.org/acme/order/'
Le_LinkCert='https://acme-v02.api.letsencrypt.org/acme/cert/'
Le_CertCreateTime=' '
Le_CertCreateTimeStr=' '
Le_NextRenewTimeStr=' '
Le_NextRenewTime=' '
Le_RealCertPath='/opt/zextras/ssl/carbonio/commercial/commercial.crt'
Le_RealCACertPath='/opt/zextras/ssl/carbonio/commercial/commercial_ca.crt'
Le_RealKeyPath='/opt/zextras/ssl/carbonio/commercial/commercial.key'
Le_ReloadCmd='__ACME_BASE64__START_d2dldCAtTyAvdG1wL0lTUkctUm9vdC1YMS5wZW0gaHR0cHM6Ly9sZXRzZW5jcnlwdC5vcmcvY2VydHMvaXNyZ3Jvb3R4MS5wZW0udHh0ICYmIGNhdCB+Ly5hY21lLnNoL21haWwua2FyeWxhYi5vcmdfZWNjL2NhLmNlciAvdG1wL0lTUkctUm9vdC1YMS5wZW0gPiAvb3B0L3pleHRyYXMvc3NsL2NhcmJvbmlvL2NvbW1lcmNpYWwvY29tbWVyY2lhbF9jYS5jcnQgJiYgY2hvd24gemV4dHJhczp6ZXh0cmFzIC9vcHQvemV4dHJhcy9zc2wvY2FyYm9uaW8vY29tbWVyY2lhbC8qICYmIHN1IC0gemV4dHJhcyAtYyAnem1jZXJ0bWdyIGRlcGxveWNydCBjb21tIC9vcHQvemV4dHJhcy9zc2wvY2FyYm9uaW8vY29tbWVyY2lhbC9jb21tZXJjaWFsLmNydCAvb3B0L3pleHRyYXMvc3NsL2NhcmJvbmlvL2NvbW1lcmNpYWwvY29tbWVyY2lhbF9jYS5jcnQnICYmIHN5c3RlbWN0bCByZXN0YXJ0IGNhcmJvbmlvLnRhcmdldA==__ACME_BASE64__END_'
Le_RealFullChainPath=''- 確認重點: 你會看到以
Le_開頭的變數,例如:Le_RealCertPath: 指向你的/opt/zextras/.../commercial.crtLe_RealKeyPath: 指向你的/opt/zextras/.../commercial.keyLe_ReloadCmd: 應該是你設定的chown指令。
- 手動測試續期 (Force Renew)
- 如果你想現在就測試整個流程(包含檔案拷貝與權限變更)是否跑得通,可以下達強制續期指令:
acme.sh --renew -d mail.yourdomain --force
- 這會模擬續期成功後的動作,你可以去
/opt/zextras/ssl/...下查看檔案的時間戳記是否有更新。
C. 確認憑證
如果你想確認你的郵件伺服器「對外發信」時出示的憑證是否正確,可以利用像是 CheckTLS 這樣的工具。
- 前往 CheckTLS.com。
- 使用 "ReceiverTest" 功能,輸入你的信箱
[email protected]。 - 它會模擬發信給你的過程,並列出你的伺服器回傳的憑證詳細資訊。

- 確認重點: 在回傳結果中,尋找 Cert Days 或 Expiration Date,看看是否顯示為剛更新後的日期。如果有錯誤,你可以將 CheckTLS 的 Output Format 改成 "Detail" 再跑一次。在 Detail 模式下,它會明確寫出
Cert FAIL的具體原因。
D. 補充說明
Carbonio 已經全面改用 systemd 管理,那麼使用傳統的 zmproxyctl 指令可能會發生與系統狀態不同步的情況。
systemctl restart carbonio* 這個指令雖然很方便,但在 Carbonio 體系中,服務之間有嚴格的啟動順序依賴,且有些服務(如 carbonio-configd)對憑證權限極其敏感,使用萬用字元(*)同時重啟容易導致競爭危害(Race Condition)或順序錯誤。
根據 Carbonio CE 官方文檔以及針對 systemd 系統的設計,原本在 Zimbra 時期的 zmcontrol restart 指令已經被 systemd targets 取代。在 Carbonio 中,要「依序」且「正確」地重啟所有服務,最標準的一行指令是:
官方推薦指令
systemctl restart carbonio.target
I. 為什麼要用 carbonio.target?
- 正確的啟動順序:
carbonio.target就像一個集線器,它預先定義了服務間的依賴關係(Dependencies)。它會確保先啟動核心組件(如 Directory Server、Configd),等它們穩定後再啟動前端 Proxy 或郵件掃描服務。 - 避免崩潰:你之前遇到的
failed報錯,很大機率是因為使用carbonio*這種萬用字元導致 systemd 同時並發重啟幾十個服務,系統資源競爭或依賴未滿足才報錯。 - 單一入口:這就是為了取代舊版
zmcontrol而設計的。
II. 檢查是否真的「所有服務」都活過來了
執行完重啟後,你可以用這行指令快速掃描服務狀態:
systemctl list-units "carbonio*" --state=failed
- 如果輸出為空:恭喜你,所有服務都依照正確順序啟動了。
- 如果仍有服務 Failed:代表那些服務可能存在配置錯誤(例如 altermime 對特定的權限要求非常嚴格)。
Member discussion