你的網站還沒用上 HTTPS 嗎

迪斯馬斯克發表於2019-04-01

前言

“如果能把 SSL 證書附加在域名上,那該多酷啊!” —— 凱麗

Certbot 是 Let's Encrypt 的官方工具。

本文主要介紹如何使用 Let's Encrypt 的 Certbot 工具免費生成、修改、更新和撤銷 SSL 證書

簡略介紹一點證書的配置。

本文沒有提及泛域名證書的生成。

要求網站已經正確配置了伺服器、DNS 等,已經能夠正常訪問。

本文操作環境為 Ubuntu。

安裝

部分參照官網
在官網首頁,選擇伺服器和作業系統後,會給出相應的安裝以及生成證書的命令。

這裡只看安裝的部分:

sudo apt-get update
sudo apt-get install software-properties-common
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install certbot
複製程式碼

檢視是否安裝成功:

certbot --version
複製程式碼

letsencrypt --version
複製程式碼

輸出的都是 certbot 的版本號:

certbot 0.25.0
複製程式碼

生成證書

重要:在開始之前,先看一下本文末尾關於頻率限制的說明。

在前一節裡,官網給出安裝命令後,也給出了生成證書的命令,比如:

為 Nginx 伺服器生成:

sudo certbot --nginx
複製程式碼

為 Apache 伺服器生成:

sudo certbot --apache
複製程式碼

在生成證書後,可以選擇讓 certbot 自動修改對應伺服器軟體的配置檔案,包括將 80 埠的請求重定向至 443,啟用相應模組,啟用配置檔案等。
自動修改後配置檔案的寫法是值得參考一下的。

但是!為了更深入地瞭解 Let's Encrypt,也為了能夠更靈活地操作證書,我們不採用這種快捷方式。而是僅僅生成證書,並手動配置。

方法有 standalonewebroot 兩種。

standalone 與 webroot 的區別

無論哪種方式,certbot 都需要驗證域名,但是實現的方式不同,這也是兩者有區別的根本原因。

  • standalone 方法生成和更新證書的時候,certbot 需要使用 443 或者 80 埠來驗證域名,因此導致需要暫時停止伺服器。這種方式不需要給出網站根目錄
  • webroot 方法沒有上述問題。不過 webroot 方法配置略微複雜,並且需要給出網站根目錄

webroot 方式之所以不需要 80443 埠,是因為它的實現方式是,在網站根目錄中生成一個臨時子目錄 .well-known/acme-challenge,然後從 certbot 的伺服器向這個路徑傳送請求,如果請求成功,那麼驗證通過。

這篇文章簡單介紹了幾個 webroot 模式可能會遇到的問題。

standalone 模式

基本命令為:

sudo letsencrypt certonly --standalone
複製程式碼

需要使用 80443 埠,可以通過 --preferred-challenges 指定要使用的埠,只要其中一個埠空閒就可以。

但是說實話,難道存在其中一個埠是空閒的情況嗎

使用 80 埠:

--preferred-challenges http
複製程式碼

使用 443 埠:

--preferred-challenges tls-sni
複製程式碼

使用 -d 指定要生成證書的域名。可以新增多個域名,使用逗號分隔,或者使用多個 -d 。兩種方法效果相同。

多個域名時,同一個主域名下的多個子域名是可以的,沒有試過多個不同的主域名是什麼效果。

執行生成命令:

sudo letsencrypt certonly --standalone -d example.com,www.example.com
複製程式碼

第一次使用時,會詢問郵箱、是否同意服務條款、是否接受推送內容。
推薦如實填寫郵箱,因為證書即將過期時會通過郵件通知。
推送內容不接受就好了。

證書即將過期的通知郵件:

你的網站還沒用上 HTTPS 嗎

感覺這個通知不太準,很多次收到郵件,但是登入檢視了一下並沒有。

也(很)可能是因為當時沒用 --staging 導致生成了很多證書...

如果看到以下資訊說明證書生成成功:

Obtaining a new certificate
Performing the following challenges:
http-01 challenge for example.com
Waiting for verification...
Cleaning up challenges
IMPORTANT NOTES:

 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/example.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/example.com/privkey.pem
   Your cert will expire on 2018-09-25. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot
   again. To non-interactively renew *all* of your certificates, run
   "certbot renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le
複製程式碼

可以使用 certbot certificates 命令檢視當前證書的資訊:

Found the following certs:
  Certificate Name: example.com
    Domains: example.com, www.example.com
    Expiry Date: 2018-09-26 00:42:47+00:00 (VALID: 89 days)
    Certificate Path: /etc/letsencrypt/live/example.com/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/example.com/privkey.pem
複製程式碼

可以看到,生成了1個證書,-d 後面的第一個域名為證書名和所在目錄的目錄名,該證書包含了兩個域名 example.comwww.example.com
這些域名都可以使用該證書。

共生成了四個檔案:

  • cert.pem
  • chain.pem
  • fullchain.pem
  • privkey.pem

/etc/letsencrypt/archive/example.com 目錄儲存原件。
/etc/letsencrypt/live/example.com 目錄儲存檔案的軟連結,可以理解為快捷方式。

live/中的檔案貌似不只是原件的軟連結那麼簡單,但是沒有仔細研究。

privkey.pem 為私鑰,務必妥善保管。

webroot 模式

這種方式需要給出網站根目錄作為引數。從這名字 webroot 應該也能看出來。

基本命令:

certbot certonly --webroot -w /path/to/webroot -d www.example.com -d example.com
複製程式碼

其中,-w 是網站的根目錄,-d 是要生成證書的域名。
注意,-d 列出的域名的根路徑必須全部與 -w 的值相同

如果要為根路徑不同的多個域名生成證書,那麼只需要在後面再新增 -w 及其對應的 -d 即可:

certbot certonly --webroot -w /path/to/webroot1 -d www.example.com -d example.com -w /path/to/webroot2 -d other.example.net -d another.other.example.net
複製程式碼

其他內容不再贅述,參考前面 standalone 部分。

泛域名證書

0.22.0 版本開始,Let's Encrypt 支援生成泛域名證書

TODO

配置伺服器

以 Apache 和 Nginx 為例。這裡只介紹一下最基本的配置。

首先,這裡是官方文件給出的上面生成的4個檔案與伺服器配置項的對應關係

Apache 配置

# apache < 2.4.8
SSLCertificateKeyFile   privkey.pem
SSLCertificateFile      cert.pem
SSLCertificateChainFile chain.pem
複製程式碼
# apache >= 2.4.8
SSLCertificateKeyFile   privkey.pem
SSLCertificateFile      fullchain.pem
複製程式碼

官方文件是這麼寫的,但是現在最新版本才2.4.3,哪來的2.4.8?

啟用 SSL 模組:

a2enmod ssl
複製程式碼

修改配置檔案:

<VirtualHost *:443>
  ServerName              example.com
  SSLCertificateKeyFile   privkey.pem
  # apache < 2.4.8
  SSLCertificateFile      cert.pem
  SSLCertificateChainFile chain.pem
  # apache >= 2.4.8
  SSLCertificateFile      fullchain.pem
  ...
</VirtualHost>
複製程式碼

重啟 Apache:

service apache2 restart
複製程式碼

Nginx 配置

ssl_certificate_key  privkey.pem;
ssl_certificate      fullchain.pem;
複製程式碼

修改配置檔案:

server {
  listen              443 ssl;
  server_name         example.com;
  ssl_certificate     fullchain.pem;
  ssl_certificate_key privkey.pem;
  ...
}
複製程式碼

重啟伺服器:

service nginx restart
複製程式碼

更進一步的配置:《分享一個 HTTPS A+ 的 nginx 配置》

修改證書

上面使用 standalone 方法已經生成了域名 example.comwww.example.com 的證書,證書名為 example.com
如果現在又要為 a.example.com 生成證書,那麼可以生成一張新的證書,也可以選擇新增到現有的證書 example.com 裡。

certbot 官方文件提供了簡單的示例:

certbot --expand -d existing.com -d example.com -d newdomain.com
複製程式碼

雖然示例使用了 --expand 選項,但是後面推薦使用的是 --cert-name,因為 --expand 只能用來新增域名,而 --cert-name 更靈活,既可以新增也可以刪除。

官方文件沒有提供 --cert-name 的示例,下面介紹一下。

命令的大致結構是:

certbot certonly --cert-name certname -d a.domain.com,b.domain.com
複製程式碼

--cert-name 選項的引數是現有證書的證書名,-d 選項的引數是證書包含的域名。

注意,多個域名用逗號分隔,並且中間不能有空格。

即,不能是:-d a.domain.com, b.domain.com,而應該是 -d a.domain.com,b.domain.com

新增域名

現在開始為證書名為 example.com、包含 example.comwww.example.com 兩個域名的證書新增一個新的域名 a.example.com

certbot certonly --cert-name example.com -d example.com,www.example.com,a.example.com
複製程式碼

會出現提示:

Saving debug log to /var/log/letsencrypt/letsencrypt.log

How would you like to authenticate with the ACME CA?
-------------------------------------------------------------------------------
1: Spin up a temporary webserver (standalone)
2: Place files in webroot directory (webroot)
-------------------------------------------------------------------------------
Select the appropriate number [1-2] then [enter] (press 'c' to cancel):
複製程式碼

選擇 1。或者在命令中新增 --standalone 選項,可以跳過這一步。

Plugins selected: Authenticator standalone, Installer None

-------------------------------------------------------------------------------
You are updating certificate example.com to include new domain(s):
+ a.example.com

You are also removing previously included domain(s):
(None)

Did you intend to make this change?
-------------------------------------------------------------------------------
(U)pdate cert/(C)ancel:
複製程式碼

選擇 u,執行更新即可。

刪除域名

現在證書中包含了三個域名,如果要從中刪除域名www.example.com,執行的命令為:

certbot certonly --cert-name example.com -d example.com,a.example.com
複製程式碼

想要刪除的域名,不在 -d 後列出來即可。

其他

可以發現,上面在修改由 standalone 方式生成的證書時,仍然可以選擇 standalonewebroot
那麼看來證書的生成方式是可以改變的。

但是沒有試過,感興趣的同學可以試一下。

更新證書

從證書資訊中可以看到,證書有效期為90天。在證書到期前需要進行更新。

可以手動進行更新:

certbot renew
複製程式碼

根據 certbot 官方文件,該命令只會更新30天內即將過期的證書。對其他的證書沒有影響。

證書更新可以使用 crontab 等設定計劃任務實現自動更新,比如每天執行一次 renew 命令。

但是注意,由 standalone 方法生成的證書,更新時也需要使用 80443 埠,因此可能需要(不如說一定需要)在執行 renew 前先關閉伺服器,結束後再重新開啟。

撤銷證書

使用 revoke 選項:

sudo certbot revoke --cert-path /etc/letsencrypt/live/CERTNAME/cert.pem
複製程式碼

前面說過,archive 目錄儲存了證書原件,live 目錄儲存了證書的軟連結。
這裡的路徑只能是 live,不能是 archive,否則會報錯。

撤銷成功後,會詢問是否刪除證書檔案和證書所在目錄:

-------------------------------------------------------------------------------
Would you like to delete the cert(s) you just revoked?
-------------------------------------------------------------------------------
(Y)es (recommended)/(N)o:
複製程式碼

推薦選擇 Yes 自動刪除。如果選擇 No,之後需要執行 certbot delete 來刪除檔案。

根據 certbot 官方文件,無論自動還是手動,最後都需要把相關檔案刪掉。

如果沒有刪除,那麼 archivelive 兩個目錄及其中的檔案就仍然存在。執行 certbot certificates 仍然能顯示該證書的資訊,不過後面會註明已經失效 INVALID。但是,在執行證書更新的時候,已經撤銷的證書還會被更新。

其他

頻率限制

Staging Environment - Let's Encrypt 官方文件

Let's Encrypt 為證書申請的頻率做了限制,每個主域名每週不超過20次
如果達到這個 rate limits,不能夠再繼續生成了,會報錯。

所以如果只是為了學習和測試,最好使用 Let's Encrypt 提供的 Staging Environment(模擬環境),沒有頻率限制。
只要在執行命令時加上 --staging 選項就可以了。

等會用了再玩真的。

關於 HTTPS

百度 LAVAS 專案中關於 HTTPS 的介紹:使用 HTTPS,寫得挺好的。

打個廣告

我的其他文章:

《polipo/privoxy 實現 Linux 系統全域性/自動代理》

相關文章