ACME 協定與自動化憑證管理

ACME Protocol and Automated Certificate Management

ACME 協定概述

ACME(Automatic Certificate Management Environment)是一個由 IETF 標準化的協定,定義於 RFC 8555。這個協定的主要目的是自動化憑證授權單位(CA)與網站伺服器之間的互動,實現 SSL/TLS 憑證的自動申請、驗證與更新。

Let’s Encrypt 是最知名的 ACME 協定實作,提供免費的 SSL/TLS 憑證服務,讓 HTTPS 普及化成為可能。

ACME 協定的優點

  • 自動化:無需人工介入即可完成憑證管理
  • 免費:Let’s Encrypt 等 CA 提供免費憑證
  • 安全:透過自動化減少人為錯誤
  • 標準化:IETF 標準確保相容性

ACME 運作流程

ACME 協定的運作流程如下:

  1. 帳戶註冊:客戶端向 ACME 伺服器註冊帳戶
  2. 訂單建立:提交憑證申請訂單
  3. 驗證挑戰:完成網域所有權驗證
  4. 憑證簽發:驗證通過後簽發憑證
  5. 憑證下載:下載並安裝憑證
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
客戶端                          ACME 伺服器
   |                                |
   |------ 1. 帳戶註冊 ------------>|
   |<----- 帳戶建立確認 ------------|
   |                                |
   |------ 2. 建立訂單 ------------>|
   |<----- 驗證挑戰資訊 ------------|
   |                                |
   |------ 3. 完成驗證 ------------>|
   |<----- 驗證結果 ----------------|
   |                                |
   |------ 4. 請求憑證 ------------>|
   |<----- 簽發憑證 ----------------|

驗證類型

ACME 協定支援三種主要的驗證方式:

HTTP-01 驗證

HTTP-01 是最常見的驗證方式,透過在網站根目錄放置特定檔案來證明網域所有權。

運作方式:

  1. ACME 伺服器提供一個 token
  2. 客戶端將 token 放置於 /.well-known/acme-challenge/ 路徑
  3. ACME 伺服器透過 HTTP 請求驗證檔案內容

優點:

  • 設定簡單
  • 不需要 DNS 存取權限

限制:

  • 需要 80 端口開放
  • 無法申請萬用字元憑證

DNS-01 驗證

DNS-01 透過在 DNS 記錄中新增 TXT 記錄來驗證網域所有權。

運作方式:

  1. ACME 伺服器提供驗證值
  2. 客戶端在 _acme-challenge.yourdomain.com 新增 TXT 記錄
  3. ACME 伺服器查詢 DNS 驗證

優點:

  • 可申請萬用字元憑證
  • 不需要對外開放任何端口

限制:

  • 需要 DNS 存取權限
  • DNS 傳播可能需要時間

TLS-ALPN-01 驗證

TLS-ALPN-01 透過 TLS 連線中的 ALPN 擴展進行驗證。

運作方式:

  1. 客戶端設定特殊的 TLS 憑證
  2. ACME 伺服器透過 443 端口連線驗證

優點:

  • 只需要 443 端口
  • 適合反向代理環境

限制:

  • 客戶端支援度較低
  • 設定較為複雜

ACME 客戶端選擇

常見的 ACME 客戶端:

客戶端語言特點
CertbotPython官方推薦,功能完整
acme.shShell輕量級,純 Shell 腳本
LegoGo跨平台,支援多種 DNS 提供商
CaddyGo內建 ACME 支援的網頁伺服器

Certbot 使用範例

安裝 Certbot

1
2
3
4
5
6
7
8
9
# Ubuntu/Debian
sudo apt update
sudo apt install certbot

# CentOS/RHEL
sudo dnf install certbot

# macOS
brew install certbot

申請憑證(Standalone 模式)

1
2
3
4
5
6
7
8
9
# 使用 standalone 模式申請憑證
sudo certbot certonly --standalone -d example.com -d www.example.com

# 指定 email 和同意服務條款
sudo certbot certonly --standalone \
    -d example.com \
    --email admin@example.com \
    --agree-tos \
    --no-eff-email

申請憑證(Webroot 模式)

1
2
3
4
5
# 使用 webroot 模式(網站運行中)
sudo certbot certonly --webroot \
    -w /var/www/html \
    -d example.com \
    -d www.example.com

Nginx 整合

1
2
3
4
5
# 自動設定 Nginx
sudo certbot --nginx -d example.com -d www.example.com

# 只取得憑證,不修改 Nginx 設定
sudo certbot certonly --nginx -d example.com

查看憑證資訊

1
2
3
4
5
# 列出所有憑證
sudo certbot certificates

# 測試續約
sudo certbot renew --dry-run

acme.sh 使用範例

安裝 acme.sh

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 使用 curl 安裝
curl https://get.acme.sh | sh -s email=admin@example.com

# 或使用 git
git clone https://github.com/acmesh-official/acme.sh.git
cd acme.sh
./acme.sh --install -m admin@example.com

# 重新載入 shell
source ~/.bashrc

申請憑證(Standalone 模式)

1
2
3
4
5
# 使用 standalone 模式
acme.sh --issue --standalone -d example.com -d www.example.com

# 指定端口
acme.sh --issue --standalone --httpport 8080 -d example.com

申請憑證(DNS 模式)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 使用 Cloudflare DNS API
export CF_Token="your_cloudflare_api_token"
export CF_Zone_ID="your_zone_id"

acme.sh --issue --dns dns_cf -d example.com -d '*.example.com'

# 使用 AWS Route53
export AWS_ACCESS_KEY_ID="your_access_key"
export AWS_SECRET_ACCESS_KEY="your_secret_key"

acme.sh --issue --dns dns_aws -d example.com -d '*.example.com'

安裝憑證

1
2
3
4
5
# 安裝憑證到指定目錄
acme.sh --install-cert -d example.com \
    --key-file /etc/nginx/ssl/example.com.key \
    --fullchain-file /etc/nginx/ssl/example.com.crt \
    --reloadcmd "systemctl reload nginx"

切換 CA

1
2
3
4
5
6
7
8
# 切換到 Let's Encrypt
acme.sh --set-default-ca --server letsencrypt

# 切換到 ZeroSSL
acme.sh --set-default-ca --server zerossl

# 切換到 Buypass
acme.sh --set-default-ca --server buypass

自動續約設定

Certbot 自動續約

1
2
3
4
5
6
# Certbot 安裝時會自動設定 systemd timer 或 cron job
# 檢查 systemd timer 狀態
sudo systemctl status certbot.timer

# 手動設定 cron job(如果需要)
echo "0 0,12 * * * root certbot renew --quiet" | sudo tee /etc/cron.d/certbot

acme.sh 自動續約

1
2
3
4
5
6
7
8
9
# acme.sh 安裝時會自動加入 cron job
# 查看 cron job
crontab -l | grep acme

# 手動執行續約
acme.sh --cron

# 強制續約特定憑證
acme.sh --renew -d example.com --force

續約後執行腳本

1
2
3
4
5
6
7
8
9
# Certbot:使用 deploy hook
sudo certbot renew --deploy-hook "systemctl reload nginx"

# 在 /etc/letsencrypt/renewal-hooks/deploy/ 放置腳本
sudo cat > /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh << 'EOF'
#!/bin/bash
systemctl reload nginx
EOF
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

常見 ACME 伺服器

CAACME 端點特點
Let’s Encrypthttps://acme-v02.api.letsencrypt.org/directory最廣泛使用,免費
ZeroSSLhttps://acme.zerossl.com/v2/DV90免費,需註冊帳戶
Buypasshttps://api.buypass.com/acme/directory免費,憑證有效期 180 天
Google Trust Serviceshttps://dv.acme-v02.api.pki.goog/directoryGoogle 提供的免費 CA

測試環境

開發測試時建議使用 staging 環境,避免觸及正式環境的請求限制:

1
2
3
4
5
# Let's Encrypt Staging
certbot certonly --staging -d example.com

# acme.sh 使用 staging
acme.sh --issue --staging -d example.com --standalone

故障排除

常見錯誤與解決方案

1. DNS 解析失敗

1
2
3
4
5
6
# 檢查 DNS 解析
dig +short example.com
nslookup example.com

# 確認 DNS 記錄已正確設定
dig TXT _acme-challenge.example.com

2. 端口被佔用

1
2
3
4
5
6
# 檢查 80 端口使用狀況
sudo lsof -i :80
sudo netstat -tlnp | grep :80

# 暫停 web 伺服器
sudo systemctl stop nginx

3. 防火牆阻擋

1
2
3
4
5
6
7
# 檢查防火牆規則
sudo iptables -L -n
sudo ufw status

# 開放 80 和 443 端口
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

4. 請求限制

1
2
3
4
Let's Encrypt 請求限制:
- 每個註冊網域每週 50 張憑證
- 每個 IP 每 3 小時 10 個帳戶
- 每個帳戶每 3 小時 300 個待處理授權

5. 憑證路徑確認

1
2
3
4
5
# Certbot 憑證位置
ls -la /etc/letsencrypt/live/example.com/

# acme.sh 憑證位置
ls -la ~/.acme.sh/example.com/

除錯模式

1
2
3
4
5
# Certbot 詳細輸出
certbot certonly --standalone -d example.com -v

# acme.sh 除錯模式
acme.sh --issue -d example.com --standalone --debug 2

延伸閱讀

參考資料

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy