因協助某專案所遇到的狀況:
某主機放置在防火牆後面,提供 Web 服務,因「資安政策」原因,對外僅開放 443 埠(https) 連線。
所以,目前情況是要在對外連線僅有 443 埠狀況下,申請 SSL 憑證。
要解決這個問題,先了解一下,若只透過 443 埠申請 SSL 有哪些途徑。
- DNS-01 驗證 (最推薦)
- 原理:
- 優點:
- 作法:
- TLS-ALPN-01 驗證
- 原理:
- 限制:
- 作法:
- 手動離線申請 (Manual Mode)
目前這是解決防火牆限制的最佳方案。DNS-01 驗證完全不需要開放伺服器的 80 或 443 埠。
ZeroSSL 或 Let’s Encrypt 會要求你在 DNS 紀錄中加入一筆特定的 TXT 紀錄。驗證主機直接檢查你的 DNS 供應商,而非連接你的伺服器。
伺服器不需要對外開放 80 埠。也可以申請 萬用字元憑證 (Wildcard Certificates)。
使用支援 DNS API 的工具(如 certbot 搭配外掛程式,或 acme.sh)。
若無法使用 DNS API,但 443 埠是通的,可以選用 TLS-ALPN-01 驗證。
這種驗證方式直接透過 443 埠進行 TLS 握手層級的驗證。
一般的 Certbot 支援度較低,通常需要使用 acme.sh 或內建此功能的 Web Server(如 Caddy 或 Traefik)。
防火牆必須允許 443 埠的 Inbound (進入) 流量。
若使用 Caddy Server,它會自動偵測並切換至此模式,完全不需手動干預。
就是真人手動代理人模式,簡單說就是在「另一台」沒有限制的機器上申請憑證。
在可以連外(80/443 皆通)的主機上執行 certbot certonly –manual,按照指示在 DNS 加入 TXT 紀錄或在目標網站放置驗證檔案。
在取得憑證檔案(.pem, .key)後,透過 SSH 或其他內部傳輸方式,手動拷貝到該台受限的伺服器上。
這個方式最大缺點: 每 90 天必須手動更新一次,維護成本極高。
| 方案 | 依賴埠口 | 自動化程度 | 適用場景 |
|---|---|---|---|
| DNS-01 | 無 (僅需 DNS API) | 極高 | 首選,適合有 API 權限的 DNS 供應商 |
| TLS-ALPN-01 | 443 Inbound | 高 | 80 埠被封死但 443 埠可用時 |
| 手動模式 | 無 | 低 | 萬不得已的最後手段 |
使用 DNS-01 驗證方案
了解之後,決定使用 DNS-01 驗證方案,搭配使用「acme.sh」(簽證到期可自動續簽)工具。
- 取得 DNS API 金鑰
- 安裝 acme.sh 與 設定
- 安裝 acme.sh:
- 設定環境與變數,在 ~/.bashrc 中,新增以下:
- 讓環境設定與變數動起來:
- 申請與安裝憑證
- 更新版本,先確定 acms.sh 為最新版本
- 更換 CA 機構:
- 申請憑證:
- 跑完申請憑證後,可以看一下是否成功(有點成就感)
- 先建個目錄以便安放憑證:
- 安裝憑證(注意並調整一下目錄權限):
- 設定好憑證檔案位置
- SSLEngine on
- SSLCertificateFile /etc/acme_ssl/example.com.crt
- SSLCertificateKeyFile /etc/acme_ssl/example.com.key
- SSLCertificateChainFile /etc/acme_ssl/example.com_fullchain.pem
- 如何確認到期前會自動續簽?
網路主機的 Domain Name 提供商為 Spaceship, 所以到該公司的 API Key 管理頁面:https://www.spaceship.com/zh/application/api-manager/ 去新增與取得 API Key, API Secret
curl https://get.acme.sh | sh
## acme ##
. "~/.acme.sh/acme.sh.env"
# 設定環境變數 (acme.sh 會自動記住,下次續期不用再設)
export SPACESHIP_API_KEY="API Key"
export SPACESHIP_API_SECRET="API Secret"
source ~/.bashrc
acme.sh 憑證申請,預設是向 ZeroSSL 申請。
但在申請的時候,等待對方回應時間太長,所以憑證申請一直失敗,因此決定改向 Let’s Encrypt 申請。
而且, Let’s Encrypt 憑證有效期間是 90 天,而 ZeroSSL 憑證有效期間是 60 天。所以,還是向 Let’s Encrypt 申請憑證。
acme.sh --upgrade
acme.sh --set-default-ca --server Letsencrypt
acme.sh --issue --dns dns_spaceship -d example.com -d *.example.com
acme.sh --list
sudo mkdir -p /etc/acme_ssl/
acme.sh --install-cert -d example.com \
--cert-file /etc/acme_ssl/example.com.crt \
--key-file /etc/acml_ssl/example.com.key \
--fullchain-file /etc/acme_ssl/example.com_fullchain.pem \
--reloadcmd "sudo systemctl reload apache2"
因為主機是使用 apache2,所以相關檔案應該是在 default-ssl.conf 上。確認與注意以下設定:
確認沒問題後,重啟 apache2 服務,sudo systemctl reload apache2
使用 TLS-ALPN-01 驗證方案
作法和步驟和上面幾乎相同,只有申請憑證的語法不同,而且不支援 *.example.com ,僅能申請單一網域。
- 停止佔用 443 埠的程式,例如 apache 或 nginx
- 申請憑證語法:
- 註:
sudo systemctl stop apache2
acme.sh --issue --alpn -d example.com
理論上可行,但在此網路主機實際執行,卻一再失敗。
錯誤訊息顯示,「可能被防火牆擋了」。