# acme.sh Docker 自動化管理 SSL 証書完整指南
# ACME 協議和 acme.sh 簡介
# 什麼是 ACME 協議?
ACME(Automated Certificate Management Environment)是 IETF 標準協議,用於自動化 SSL/TLS 証書的申請、驗證、安裝和續期。
核心優勢:
- 零成本:利用 Let's Encrypt 和 ZeroSSL 等免費簽發機構
- 自動化:無需手動操作,定時自動續期
- 安全:支持多種驗證方式(HTTP、DNS、TLSALPN)
- 標準化:符合行業標準,多工具支持
# acme.sh 是什麼?
acme.sh 是用 Bash 編寫的 ACME 客戶端,特點:
- 輕量級:純 Bash,占用資源少
- 無依賴:不依賴 Python、NodeJS 等重型運行時
- 功能全:支持 80+ 種 DNS API
- 容器友好:易于 Docker 化和自動化
- 活躍開發:社區維護,定期更新
# 簽證機構對比
| 機構 | 免費 | 驗證方式 | 証書有效期 | 續期難度 |
|---|---|---|---|---|
| Let's Encrypt | ✅ | HTTP/DNS/TLSALPN | 90 天 | 簡單 |
| ZeroSSL | ✅ | HTTP/DNS/ACME | 90 天 | 簡單 |
| Cloudflare | ✅ | DNS | 無限期 | 極簡 |
本教程重點:ZeroSSL(證書可視化管理,初學者友好)
# 環境準備
# 前置要求
# 系統:任何 Linux 或 Docker | |
# 網絡:需要訪問 ACME 伺服器(80/443 端口) | |
# DNS:使用 DNS 驗證時需要 DNS API 密鑰 | |
# 檢查 Bash 版本 | |
bash --version # 需要 >= 4.0 |
# 依賴項
ACME.sh 最小依賴:
curl # HTTP 客戶端(幾乎所有系統都有) | |
wget # 備選 HTTP 客戶端 | |
openssl # 密碼學運算 | |
socat # 用於 HTTP 驗證的 TCP 中繼 |
# 核心概念詳解
# ACME 驗證流程
ACME 協議使用以下驗證方式:
# 1. HTTP 驗證(最簡單)
1. acme.sh 生成驗證文件 → /.well-known/acme-challenge/xxxxx
2. ACME 伺服器訪問 http://example.com/.well-known/acme-challenge/xxxxx
3. 驗證成功 → 簽發証書
優點:無需 DNS 權限
缺點:必須開放 80 端口,需要 Web 伺服器配置
# 2. DNS 驗證(推薦用於自動化)
1. acme.sh 行使 DNS API → 向 DNS 記錄添加 TXT 驗證值
2. ACME 伺服器查詢 DNS 記錄,驗證所有權
3. acme.sh 刪除 TXT 記錄 → 簽發証書
優點:支持泛域名 (*.example.com)、無需暴露 80 端口、完全自動化
缺點:需要 DNS 服務商的 API 密鑰
# 3. TLSALPN 驗證(實驗性)
直接使用 TLS 443 端口驗證,適合只開放 HTTPS 的環境。
# 運行模式對比
| 模式 | 使用場景 | 優缺點 |
|---|---|---|
| 系統服務 | VPS 長期運行 | 全局 crontab;無容器開銷 |
| Docker 容器 | 多租戶、隔離環境 | 可複用;版本一致;易于管理 |
| K8s Job | 雲原生部署 | 自動微服務集成;複雜度高 |
本教程重點:Docker 容器方案
# Docker 化 acme.sh 完整方案
# 目錄結構
acme-sh-docker/
├── Dockerfile # 容器定義
├── docker-compose.yml # 容器編排
├── .env # 環境變量
├── scripts/
│ ├── entry.sh # 容器入口
│ ├── init.sh # 證書初始化
│ └── renew.sh # 手動續期腳本
└── volumes/
├── cert/ # 證書輸出目錄
└── acme-home/ # acme.sh 主目錄
# Step 1: Dockerfile
FROM ubuntu:22.04 | |
# 安裝依賴項 | |
RUN apt-get update && apt-get install -y \ | |
curl wget tar gzip cron socat jq ca-certificates && \ | |
rm -rf /var/lib/apt/lists/* | |
# 設置時區 | |
ENV TZ=Asia/Taipei | |
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \ | |
echo $TZ > /etc/timezone | |
# 工作目錄 | |
WORKDIR /app | |
# 複製腳本 | |
COPY scripts/entry.sh . | |
COPY scripts/init.sh . | |
RUN chmod +x ./*.sh | |
# 暴露日誌卷 | |
VOLUME /root/.acme.sh | |
VOLUME /cert | |
# 健康檢查 | |
HEALTHCHECK \ | |
CMD curl -f http://localhost/health || exit 1 | |
# 入口點 | |
ENTRYPOINT ["/bin/bash", "-c", "/app/entry.sh"] |
# Step 2: entry.sh (容器啟動入口)
#!/bin/bash | |
set -e | |
# 日誌函數 | |
log() { | |
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | |
} | |
# 1. 安裝 acme.sh(首次運行) | |
if [[ ! -f /root/.acme.sh/acme.sh ]]; then | |
log "Installing acme.sh..." | |
curl -sSL https://get.acme.sh | sh -s email="${ACME_EMAIL}" | |
ln -s /root/.acme.sh/acme.sh /usr/bin/acme.sh | |
fi | |
# 2. 設置默認 CA 和通知 | |
log "Configuring acme.sh..." | |
acme.sh --set-default-ca --server "${ACME_SERVER:-zerossl}" | |
acme.sh --set-default-notify-hook telegram 2>/dev/null || true | |
# 3. 設置 cron 自動續期 | |
log "Setting up cron for automatic renewal..." | |
(crontab -l 2>/dev/null || true; \ | |
echo "0 0 * * * /root/.acme.sh/acme.sh --cron --home /root/.acme.sh > /proc/1/fd/1 2>&1") | crontab - | |
# 4. 啟動 cron 服務 | |
service cron start | |
# 5. 初始化日誌文件 | |
touch /root/.acme.sh/acme.sh.log | |
log "acme.sh is ready!" | |
# 6. 监控日誌(保持容器運行) | |
tail -f /root/.acme.sh/acme.sh.log |
# Step 3: init.sh (證書初始化腳本)
#!/bin/bash | |
# 使用方法:./init.sh/cert/example.com dns_cf example.com www.example.com | |
set -e | |
CERT_LOCATION="${1%/}" | |
DNS_API="$2" | |
shift 2 | |
DOMAINS=("$@") | |
if [[ -z "$CERT_LOCATION" ]] || [[ -z "$DNS_API" ]] || [[ $ |