在西元2015年之後,我們所熟悉的HTTP網站已經被大多數人認為是不安全的網站了,許多瀏覽器甚至會直接針對沒有使用HTTPS協定的網站打上「不安全」的標籤,就連搜尋引擎也會降低HTTP網站的排名。因此讓網站支援SSL,並使用HTTPS協定進行傳輸,已經是再基本不過的事了。在過去使用公開的SSL時,通常都需要去向第三方安全認證機構購買所謂的「SSL憑證」,一直到2015年,Let's Encrypt逐漸興起後,免費公開的SSL憑證才流行起來。



由於向Let's Encrypt申請到的免費SSL憑證只有三個月的有效期,如果要繼續使用就必須要重新申請,因此為了要加速這件重複申請Let's Encrypt的日常工作,選擇一個適當的工具是很重要的!

acme.sh

「acme.sh」是一個利用Unix Shell Script來完成Let's Encrypt的SSL憑證申請的開源工具,ACME為「Automated Certificate Management Environment」的縮寫,中文譯作「自動證書管理環境」,簡單來說,我們可以透過JSON文件格式和HTTPS協定來按照ACME的規範(例如驗證網域的所有權的方式),完成Let's Encrypt的SSL憑證申請。

GitHub:

安裝acme.sh

執行以下指令即可安裝「acme.sh」:

curl -fsSL https://get.acme.sh | sh -s

接著執行以下指令,可以讓「acme.sh」在將來自動更新:

acme.sh --upgrade --auto-upgrade

使用acme.sh

「acme.sh」通常會直接在伺服器上跟著伺服器程式(如Nginx和Apache)和Web應用程式一同使用,使用者在使用「acme.sh」的「--issue」參數申請到SSL憑證之後,即可放著不管它,每隔60天它都會自動作SSL憑證的延展,避免憑證過期而導致網站失效。

以下區分幾種「acme.sh」的使用情境:

「acme.sh」存在於公開的網站伺服器
網站的根目錄是公開存取的

假設網域名稱是「example.com」,在能「公開存取」的網站根目錄下新增「file.txt」檔案時,使用「http://example.com/file.txt」或是「https://example.com/file.txt」可以存取到「file.txt」檔案。

這時候就可以使用以下指令來申請SSL憑證:

acme.sh --issue -d 網域名稱 -w 網站根目錄路徑

如果在申請的過程中,需要驗證網域所有權的話,「acme.sh」就會自動在網站根目錄下新增「.well-known/acme-challenge」目錄和一個帶有雜湊訊息的檔案。如此一來,Let's Encrypt就能從外部夠透過網址來嘗試存取這個檔案。如果能存取得到,而且雜湊訊息也沒錯的話,就會頒發憑證。

注意這邊「-d」選項可以是複數個,而且也支援「Wildcard」,可以使用星號來表示所有子網域。

使用Nginx作為前端伺服器程式

如果網站並沒有能「公開存取」的網站根目錄,但網站是使用Nginx來作為前端伺服器的話,可以使用以下指令來申請SSL憑證:

acme.sh --issue --nginx -d 網域名稱
使用Apache作為前端伺服器程式

如果網站並沒有能「公開存取」的網站根目錄,但網站是使用Apache來作為前端伺服器的話,可以使用以下指令來申請SSL憑證:

acme.sh --issue --apache -d 網域名稱
獨立的驗證伺服器程式

如果網站並沒有能「公開存取」的網站根目錄,同時也沒有使用Nginx或是Apache作為前端伺服器的話,可以使用「acme.sh」自帶的前端伺服器,指令如下:

acme.sh --issue --standalone -d 網域名稱

這個自帶的前端伺服器必須使用HTTP的80連接埠。

「acme.sh」存在於私人的電腦,且我們擁有網域的記錄修改權限

如果我們並未將「acme.sh」直接用於伺服器主機上,而是想在自己開發、測試用的電腦上作業,可以使用使用以下指令:

acme.sh --issue --dns --yes-I-know-dns-manual-mode-enough-go-ahead-please -d 網域名稱

指令執行之後,「acme.sh」會回傳DNS的TXT記錄需要修改的項目。我們在手動完成DNS的修改之後,還需等待DNS對應(通常要兩分鐘以上)。之後再使用以下指令來告訴Let's Encrypt來驗收我們的設定。

acme.sh --renew --yes-I-know-dns-manual-mode-enough-go-ahead-please -d 網域名稱

但如果網域有幾十個或是幾百個,一個一個手動設定DNS的話實在是太麻煩。所幸「acme.sh」有提供各大DNS服務廠商的API支援。

以CloudFlare來舉例,如果我們的網域是CloudFlare代管的,需要先到CloudFlare的帳號設定頁面取得API Key。

simple-ssl-acme-cloudflare

simple-ssl-acme-cloudflare

接著將這個API Key設成「CF_Key」環境變數,並再把我們登入CloudFlare所用的電子郵件信箱設成「CF_Email」環境變數,即可使用以下指令來申請SSL憑證,而不需要手動設定DNS記錄:

acme.sh --issue --dns dns_cf -d 網域名稱
申請到的SSL憑證在哪?

SSL憑證申請成功之後,會得到cert、CA cert、full chain certs和key這四個檔案,並儲存在家目錄中的「.acme.sh/網域名稱」下,檔名分別為「網域名稱.cer」、「ca.cer」、「fullchain.cer」、「網域名稱.key」。接著使用伺服器程式或是Web應用程式來讀取並套用即可。

Nginx

如果使用Nginx作為前端伺服器的話,只要在設定檔中加上:

ssl_certificate "家目錄/.acme.sh/網域名稱/fullchain.cer"
ssl_certificate_key "家目錄/.acme.sh/網域名稱/網域名稱.key"

使用以下指令重啟之後即可套用:

sudo service nginx reload
Apache

如果使用Apache作為前端伺服器的話,只要在設定檔中加上:

SSLCertificateFile "家目錄/.acme.sh/網域名稱/fullchain.cer"
SSLCertificateKeyFile "家目錄/.acme.sh/網域名稱/網域名稱.key"

使用以下指令重啟之後即可套用:

sudo service httpd reload

如果以上不行(因為常用的Apache服務名稱有兩種),則:

sudo service apache2 reload
設定伺服器程式或是Web應用程式自動套用新的SSL憑證檔案

「.acme.sh」官方並不是很建議直接使用「.acme.sh/網域名稱」下的SSL憑證檔案。因為這樣的作法無法讓持續運作的伺服器程式或是Web應用程式,自動套用到新的SSL憑證檔案。

官方建議的作法是將憑證檔透過「.acme.sh」的「--install-cert」指令「安裝」到某個路徑,再透過某個指令去通知伺服器程式或是Web應用程式去使用新的SSL憑證檔案。如此一來,就會每隔60天自動作SSL憑證的安裝和通知。

Nginx

如果使用Nginx作為前端伺服器的話,安裝SSL憑證的指令如下:

acme.sh --install-cert -d 網域名稱 --key-file /path/to/key.pem --fullchain-file /path/to/fullchain.pem --reloadcmd "service nginx reload"

在設定檔中加上:

ssl_certificate "/path/to/key.pem"
ssl_certificate_key "/path/to/fullchain.pem"

注意這邊的「service nginx reload」,如果沒有root權限的話是無法成功執行的。可以改為「sudo service nginx reload」,並在「/etc/sudoers」設定檔中加上:

使用者名稱 ALL=(ALL) NOPASSWORD: /usr/sbin/service nginx reload
Apache

如果使用Apache作為前端伺服器的話,安裝SSL憑證的指令如下:

acme.sh --install-cert -d 網域名稱 --cert-file /path/to/cert.pem --key-file /path/to/key.pem --ca-file /path/to/ca.pem --reloadcmd "service httpd reload"

在設定檔中加上:

SSLCertificateFile "/path/to/fullchain.pem"
SSLCertificateKeyFile " /path/to/key.pem"

注意這邊的「service httpd reload」,如果沒有root權限的話是無法成功執行的。可以改為「sudo service httpd reload」,並在「/etc/sudoers」設定檔中加上:

使用者名稱 ALL=(ALL) NOPASSWORD: /usr/sbin/service httpd reload

若Apache的服務名稱不是叫「httpd」,應該就是叫「apache2」。

Web應用程式

如果沒有使用Nginx或是Apache作為前端伺服器的話,那就要看該Web應用程式有沒有支援HTTPS且有沒有支援不斷線更新SSL憑證的功能了。如果有的話,應該也要提供某種能夠用指令通知的方式,來替換運作中的Web應用程式所使用的舊SSL憑證。

Simple SSL with ACME and CloudFlare

Simple SSL with ACME and CloudFlare是筆者用Rust程式語言開發的開源工具,簡化「acme.sh」和CloudFlare的使用方式,除了能夠輕易地使用OpenSSL的設定檔來產生出自己的CSR檔案外,還支援4096位元的dhparam(Diffie-Hellman Parameter)的產生。此外「CF_Key」和「CF_Email」不是透過環境變數來設定,而是直接透過CLI介面從命令列參數傳給程式來使用,如此一來就算有多個CloudFlare帳號也很容易切換。

GitHub:

安裝Simple SSL with ACME and CloudFlare

如果系統環境中有安裝「Cargo」的話,可以直接使用以下指令來下載「Simple SSL with ACME and CloudFlare」的原始碼專案,並進行編譯安裝。

cargo install simple-ssl-acme-cloudflare

如果是使用Linux作業系統的話,可以直接到以下頁面取得「Simple SSL with ACME and CloudFlare」的執行檔,手動放置到「/usr/local/bin」目錄中即可。網址如下:

使用Simple SSL with ACME and CloudFlare前,必須先安裝好OpenSSL和「.acme.sh」。

使用Simple SSL with ACME and CloudFlare

執行以下指令,即可開始使用Simple SSL with ACME and CloudFlare:

simple-ssl-acme-cloudflare --cf-email CloudFlare電子郵件信箱 --cf-key CloudFlare的APIKey

simple-ssl-acme-cloudflare

Simple SSL with ACME and CloudFlare需要輸出一些檔案,預設會放在目前工作目錄下的「ssl」目錄內,如果想更改的話,可以加上「-o」選項來設定。

如果輸出目錄中並沒有「dhparam」檔案,程式就會開始建立。

simple-ssl-acme-cloudflare

建立「dhparam」檔案需要一些時間,請耐心等待。

simple-ssl-acme-cloudflare

接著程式會提示需要去設定輸出目錄中的「config.txt」,那個就是OpenSSL的設定檔案,用來產生CSR和key。

simple-ssl-acme-cloudflare

simple-ssl-acme-cloudflare

「config.txt」的設定方式如下圖:

simple-ssl-acme-cloudflare

然後再重新執行剛才的Simple SSL with ACME and CloudFlare指令,就可以開始申請SSL憑證啦!

simple-ssl-acme-cloudflare

SSL憑證申請成功後,憑證的相關檔案都會匯出到輸出目錄中,程式還會印出Nginx和Apache設定檔套用「dhparam」檔案和SSL憑證檔案的撰寫方式,複製貼上即可使用。

simple-ssl-acme-cloudflare

另外,之後若要延展憑證,只要重新執行剛才的Simple SSL with ACME and CloudFlare指令即可。如果有需要修改「config.txt」設定檔的話,在修改完畢後,重新申請SSL憑證時,指令需加上「--force-csr-key」選項,不然還是會沿用先前產生出來的CSR和key哦!

檢查SSL的設定

參考以下這篇文章來檢查SSL設定有沒有問題: