Featured image of post acme.sh 透過 http 和 dnsapi 申請網站 SSL 證書

acme.sh 透過 http 和 dnsapi 申請網站 SSL 證書

acme.sh 實現了 acme 協議,可以從 letsencrypt […]

acme.sh 實現了 acme 協議,可以從 letsencrypt 生成免費的證書。

主要步驟:

  1. 安裝 acme.sh
  2. 生成證書
  3. 將證書複製到 nginx/apache 或其他服務
  4. 更新證書
  5. 更新 acme.sh
  6. 出錯該怎麼辦,如何調試

acme.sh http 和 dnsapi 申請網站 SSL 證書 下面將詳細介紹。

1. 安裝 acme.sh

安裝非常簡單,只需要一條命令:

1
curl https://get.acme.sh | sh -s email=[email protected]

普通用戶和 root 用戶均可安裝使用。安裝過程進行了以下幾步:

  1. 將 acme.sh 安裝到你的 home 目錄下:
1
~/.acme.sh/

並在如 .bashrc 中創建一個 shell 的別名,方便使用:alias acme.sh=~/.acme.sh/acme.sh

  1. 自動為你創建 cronjob,每天 0:00 自動檢測所有的證書,如果快過期需要更新,則會自動更新證書。

更高級的安裝選項請參考:https://github.com/Neilpang/acme.sh/wiki/How-to-install

安裝過程不會污染已存在的系統任何功能和文件,所有的修改都限制在安裝目錄中:~/.acme.sh/

2. 生成證書

acme.sh 實現了 acme 協議支持的所有驗證協議。一般有兩種方式驗證:http 和 dns。

1. http 方式需要在你網站根目錄下放置一個文件,以驗證你的域名所有權,完成驗證。然後就可以生成證書了。

1
acme.sh --issue -d mydomain.com -d www.mydomain.com --webroot /home/wwwroot/mydomain.com/

只需指定域名,並指定頂級域名所在的網站根目錄。acme.sh 會全自動生成驗證文件,並放到網站的根目錄,然後自動完成驗證。最後會自動刪除驗證文件,整個過程沒有任何副作用。

如果你使用的是 apache 伺服器,acme.sh 還可以智能地從 apache 的配置中自動完成驗證,你不需要指定網站根目錄:

1
acme.sh --issue -d mydomain.com --apache

如果你使用的是 nginx 伺服器或反向代理,acme.sh 同樣可以從 nginx 的配置中自動完成驗證,你不需要指定網站根目錄:

1
acme.sh --issue -d mydomain.com --nginx

注意,無論是 apache 還是 nginx 模式,acme.sh 在完成驗證後,會恢復到之前的狀態,不會私自更改你的配置。好處是你不用擔心配置被搞壞,但也有一個缺點:你需要自己配置 ssl,否則只會成功生成證書,而你網站仍無法透過 https 訪問。但為了安全起見,建議還是手動修改配置。

如果你尚未運行任何 web 服務,80 端口是空閒的,那麼 acme.sh 還可以假裝成一個 web server,暫時在 80 端口上運行,以完成驗證:

1
acme.sh --issue -d mydomain.com --standalone

更高級的用法請參考:https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert

2. 手動 dns 方式,手動在域名上添加一條 txt 解析記錄,以驗證域名所有權。

這種方式的好處是,你不需要任何伺服器,不需要任何公網 IP,只需有 dns 的解析記錄即可完成驗證。壞處是,如果不同步配置 Automatic DNS API,使用此方式 acme.sh 將無法自動更新證書,每次都需手動重新解析以驗證域名所有權。

1
2
acme.sh --issue --dns -d mydomain.com \
--yes-I-know-dns-manual-mode-enough-go-ahead-please

之後,acme.sh 會生成相應的解析記錄顯示出來,你只需在域名管理面板中添加這條 txt 記錄即可。

等待解析完成後,重新生成證書:

1
2
acme.sh --renew -d mydomain.com \
--yes-I-know-dns-manual-mode-enough-go-ahead-please

注意第二次這裡用的是 --renew

dns 方式真正的強大之處在於可以使用域名解析商提供的 api 自動添加 txt 記錄以完成驗證。

acme.sh 目前支援 cloudflare, dnspod, cloudxns, godaddy 以及 ovh 等數十種解析商的自動整合。

以 dnspod 為例,你需要先登錄到 dnspod 帳號,生成你的 api id 和 api key,這兩者都是免費的。然後:

1
2
3
export DP_Id="1234"
export DP_Key="sADDsdasdgdsf"
acme.sh --issue --dns dns_dp -d aa.com -d www.aa.com

證書將自動生成。這裡給出的 api id 和 api key 會被自動記錄,未來使用 dnspod api 時就不需再指定了,直接生成即可:

1
acme.sh --issue -d mydomain2.com --dns dns_dp

更詳細的 api 用法請參閱:https://github.com/Neilpang/acme.sh/blob/master/dnsapi/README.md

3. 複製/安裝證書

前面生成的證書後,接下來需要將證書複製到真正需要用到的地方。

注意,默認生成的證書都放在安裝目錄下:~/.acme.sh/,請勿直接使用此目錄下的文件,例如:不要直接讓 nginx/apache 的配置文件使用這裏的文件,因為這些文件都是內部使用,且目錄結構可能會變化。

正確的使用方式是使用 --install-cert 命令,並指定目標位置,這樣證書文件會複製到相應的位置,例如:

Apache 範例:

1
2
3
4
5
acme.sh --install-cert -d example.com \
--cert-file /path/to/certfile/in/apache/cert.pem \
--key-file /path/to/keyfile/in/apache/key.pem \
--fullchain-file /path/to/fullchain/certfile/apache/fullchain.pem \
--reloadcmd "service apache2 force-reload"

Nginx 範例:

1
2
3
4
acme.sh --install-cert -d example.com \
--key-file /path/to/keyfile/in/nginx/key.pem \
--fullchain-file /path/to/fullchain/nginx/cert.pem \
--reloadcmd "service nginx force-reload"

(小提醒,這裡使用的是 service nginx force-reload,而非 service nginx reload,經測試後發現 reload 並不會重新加載證書,所以使用的是 force-reload

Nginx 的配置 ssl_certificate 使用 /etc/nginx/ssl/fullchain.cer,而非 /etc/nginx/ssl/<domain>.cer,否則 SSL Labs 的測試會報 Chain issues Incomplete 錯誤。

--install-cert 命令可以攜帶許多參數,以指定目標文件,並且可以指定 reloadcmd,當證書更新後,reloadcmd 將會被自動調用,以使伺服器生效。

詳細參數請參考:https://github.com/Neilpang/acme.sh#3-install-the-issued-cert-to-apachenginx-etc

值得注意的是,這裡指定的所有參數都會被自動記錄下來,並在將來證書自動更新後,被再次自動調用。

4. 查看已安裝證書資訊

1
acme.sh --info -d example.com

會輸出如下內容:

DOMAIN_CONF=/root/.acme.sh/example.com/example.com.conf
Le_Domain=example.com
Le_Alt=no
Le_Webroot=dns_ali
Le_PreHook=
Le_PostHook=
Le_RenewHook=
Le_API=https://acme-v02.api.letsencrypt.org/directory
Le_Keylength=
Le_OrderFinalize=https://acme-v02.api.letsencrypt.org/acme/finalize/23xxxx150/781xxxx4310
Le_LinkOrder=https://acme-v02.api.letsencrypt.org/acme/order/233xxx150/781xxxx4310
Le_LinkCert=https://acme-v02.api.letsencrypt.org/acme/cert/04cbd28xxxxxx349ecaea8d07
Le_CertCreateTime=1649358725
Le_CertCreateTimeStr=Thu Apr 7 19:12:05 UTC 2022
Le_NextRenewTimeStr=Mon Jun 6 19:12:05 UTC 2022
Le_NextRenewTime=1654456325
Le_RealCertPath=
Le_RealCACertPath=
Le_RealKeyPath=/etc/acme/example.com/privkey.pem
Le_ReloadCmd=service nginx force-reload
Le_RealFullChainPath=/etc/acme/example.com/chain.pem