用 Shell 腳本自動申請與續期 SSL 憑證
在現代 Web 開發中,HTTPS 已不再是選項,而是標配。雖然 Let's Encrypt 提供了免費且自動化的憑證簽發服務,但如何將申請、部署與續期過程自動化,仍是許多系統管理員的痛點。本文将介紹如何使用 Shell 腳本搭配 certbot,在 Ubuntu 22.04 或 Debian 12 上實現全自動化的 SSL 憑證管理。
環境準備與依賴安裝
首先,確保您的系統已安裝必要的軟體。在 Debian/Ubuntu 系發行版中,certbot 是官方推薦的 ACME 客戶端。
sudo apt update
sudo apt install -y certbot python3-certbot-nginx
註:若您使用 Apache,請安裝 python3-certbot-apache;若僅需獲取憑證檔案而不直接配置 Web 伺服器,可僅安裝 certbot。
自動化腳本設計思路
為了避免手動干預,我們需要一個腳本完成以下任務:
- 檢查憑證是否即將過期(例如剩餘 30 天內)。
- 若需續期,自動執行申請流程。
- 重新載入 Web 伺服器以套用新憑證。
- 記錄日誌以便追蹤。
以下是一個完整且可執行的 Shell 腳本範例:
完整 Shell 腳本範例
建立檔案 /usr/local/bin/auto-renew-ssl.sh:
#!/bin/bash
# 設定變數
DOMAIN="example.com" # 請替換為您要保護的網域
EMAIL="admin@example.com" # 請替換為您的聯絡信箱
CERT_PATH="/etc/letsencrypt/live/${DOMAIN}/fullchain.pem"
KEY_PATH="/etc/letsencrypt/live/${DOMAIN}/privkey.pem"
NGINX_CONF="/etc/nginx/sites-available/${DOMAIN}"
LOG_FILE="/var/log/ssl-renewal.log"
# 函式:記錄日誌
log_message() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
# 檢查憑證剩餘天數
check_cert_expiry() {
if [ ! -f "$CERT_PATH" ]; then
log_message "錯誤:憑證檔案不存在,將執行首次申請。"
return 1
fi
# 使用 openssl 查詢憑證到期日
EXPIRY_DATE=$(openssl x509 -enddate -noout -in "$CERT_PATH" | cut -d= -f2)
EXPIRY_TIMESTAMP=$(date -d "$EXPIRY_DATE" +%s)
CURRENT_TIMESTAMP=$(date +%s)
# 計算剩餘天數
DAYS_LEFT=$(( (EXPIRY_TIMESTAMP - CURRENT_TIMESTAMP) / 86400 ))
log_message "憑證剩餘天數:${DAYS_LEFT} 天"
if [ "$DAYS_LEFT" -lt 30 ]; then
return 0 # 需要續期
else
return 1 # 不需處理
fi
}
# 執行續期或申請
renew_or_issue() {
log_message "開始申請/續期憑證..."
# 使用 certbot 申請憑證,並設定 webroot 模式以兼容非標準配置
# --dry-run 可用於測試,正式環境請移除
certbot certonly --webroot \
-w /var/www/html \
-d "${DOMAIN}" \
--email "${EMAIL}" \
--agree-tos \
--no-eff-email \
--force-renewal \
--non-interactive 2>&1 | tee -a "$LOG_FILE"
if [ $? -eq 0 ]; then
log_message "憑證申請成功!"
# 重新載入 Nginx
nginx -t && systemctl reload nginx
log_message "Nginx 已重新載入。"
else
log_message "錯誤:憑證申請失敗,請檢查日誌。"
exit 1
fi
}
# 主程式流程
main() {
log_message "=== SSL 憑證檢查開始 ==="
if check_cert_expiry; then
renew_or_issue
else
log_message "憑證狀態良好,無需處理。"
fi
log_message "=== SSL 憑證檢查結束 ==="
}
# 執行主程式
main
腳本使用說明
- 修改變數:請務必將
DOMAIN、EMAIL、CERT_PATH等變數替換為您的實際環境資訊。 - 權限設定:
sudo chmod +x /usr/local/bin/auto-renew-ssl.sh - 手動測試:
sudo /usr/local/bin/auto-renew-ssl.sh觀察
/var/log/ssl-renewal.log輸出,確認無錯誤。
設定 Cron 定時任務
為了實現自動化,我們將腳本加入 Crontab。建議每 12 小時執行一次,讓系統有足夠時間在憑證過期前觸發續期。
sudo crontab -e
在檔案末尾加入以下行:
0 */12 * * * /usr/local/bin/auto-renew-ssl.sh >> /var/log/ssl-cron.log 2>&1
常見問題與解決方案
1. 憑證申請失敗,提示 403 或 404 錯誤
這通常與 Webroot 路徑配置錯誤有關。Certbot 會透過 http://domain/.well-known/acme-challenge/ 驗證域名所有權。請確保:
- Nginx 的
serverblock 中,root指向的目錄確實存在且可寫。 - 防火牆允許 HTTP (80) 和 HTTPS (443) 流量。
- 若使用 CDN,需確認 CDN 支援 ACME 驗證或暫時關閉 CDN。
2. 憑證續期後 Web 伺服器未更新
部分服務(如 Nginx、Apache)在憑證檔案內容變更時,不會自動重新讀取。因此,腳本中必須包含重新載入服務的指令(如 systemctl reload nginx)。若您的應用是靜態網頁或需手動觸發的後端服務,請在腳本中補充相應的觸發機制。
小結
透過撰寫簡單的 Shell 腳本並結合 certbot 與 cron,我們可以輕鬆建立一套可靠的 SSL 憑證自動化管理系統。這不僅消除了手動續期的遺忘風險,也確保了網站始終處於安全的 HTTPS 狀態。對於更複雜的架構,建議進一步研究 certbot 的 hook 參數,以支援更靈活的部署流程。