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 協定的運作流程如下:
- 帳戶註冊:客戶端向 ACME 伺服器註冊帳戶
- 訂單建立:提交憑證申請訂單
- 驗證挑戰:完成網域所有權驗證
- 憑證簽發:驗證通過後簽發憑證
- 憑證下載:下載並安裝憑證
1
2
3
4
5
6
7
8
9
10
11
12
13
| 客戶端 ACME 伺服器
| |
|------ 1. 帳戶註冊 ------------>|
|<----- 帳戶建立確認 ------------|
| |
|------ 2. 建立訂單 ------------>|
|<----- 驗證挑戰資訊 ------------|
| |
|------ 3. 完成驗證 ------------>|
|<----- 驗證結果 ----------------|
| |
|------ 4. 請求憑證 ------------>|
|<----- 簽發憑證 ----------------|
|
驗證類型
ACME 協定支援三種主要的驗證方式:
HTTP-01 驗證
HTTP-01 是最常見的驗證方式,透過在網站根目錄放置特定檔案來證明網域所有權。
運作方式:
- ACME 伺服器提供一個 token
- 客戶端將 token 放置於
/.well-known/acme-challenge/ 路徑 - ACME 伺服器透過 HTTP 請求驗證檔案內容
優點:
限制:
DNS-01 驗證
DNS-01 透過在 DNS 記錄中新增 TXT 記錄來驗證網域所有權。
運作方式:
- ACME 伺服器提供驗證值
- 客戶端在
_acme-challenge.yourdomain.com 新增 TXT 記錄 - ACME 伺服器查詢 DNS 驗證
優點:
限制:
TLS-ALPN-01 驗證
TLS-ALPN-01 透過 TLS 連線中的 ALPN 擴展進行驗證。
運作方式:
- 客戶端設定特殊的 TLS 憑證
- ACME 伺服器透過 443 端口連線驗證
優點:
限制:
ACME 客戶端選擇
常見的 ACME 客戶端:
| 客戶端 | 語言 | 特點 |
|---|
| Certbot | Python | 官方推薦,功能完整 |
| acme.sh | Shell | 輕量級,純 Shell 腳本 |
| Lego | Go | 跨平台,支援多種 DNS 提供商 |
| Caddy | Go | 內建 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 伺服器
| CA | ACME 端點 | 特點 |
|---|
| Let’s Encrypt | https://acme-v02.api.letsencrypt.org/directory | 最廣泛使用,免費 |
| ZeroSSL | https://acme.zerossl.com/v2/DV90 | 免費,需註冊帳戶 |
| Buypass | https://api.buypass.com/acme/directory | 免費,憑證有效期 180 天 |
| Google Trust Services | https://dv.acme-v02.api.pki.goog/directory | Google 提供的免費 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
|
延伸閱讀
參考資料