如何使用流行的免費解決方案 Let’s Encrypt 設置 HTTPS

如果你在自己的 VPS 上運行 Node.js 應用程式,你需要一個獲取 SSL 憑證的解決方案。

使用 Let’s EncryptCertbot 是當今的標準做法,它們是由 EFF(Electronic Frontier Foundation)提供的工具。EFF 是一家致力於保護隱私、自由言論和整個數位世界公民權利的領先非盈利組織。

我們將按照以下步驟進行:

安裝 Certbot

以下指令假設你使用 Ubuntu、Debian 或任何其他使用 apt-get 來管理套件的 Linux 發行版:

sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install certbot

你也可以在 Mac 上安裝 Certbot 進行測試(需要 Homebrew):

brew install certbot

然而,你需要將其連接到一個真實的域名,以便它有用。

使用 Certbot 生成 SSL 憑證

現在 Certbot 已安裝完成,你可以使用它來生成憑證。你必須以 root 身份運行此命令:

certbot certonly --manual

或者你也可以在非 root 使用者環境下使用 sudo:

sudo certbot certonly --manual

以下是詳細的過程:

安裝程式將要求你提供你的網站域名。

… 然後要求你提供你的電子郵件:

➜ sudo certbot certonly --manual
Password: XXXXXXXXXXXXXXXXXX
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Enter email address (used for urgent renewal and security notices) (Enter 'c' to cancel): [[email protected]](/cdn-cgi/l/email-protection)

… 並且要求你同意服務條款:

Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must
agree in order to register with the ACME server at
https://acme-v02.api.letsencrypt.org/directory

(A)gree/(C)ancel: A

… 以及是否允許共享你的電子郵件:

Would you be willing to share your email address with the Electronic Frontier
Foundation, a founding partner of the Let's Encrypt project and the non-profit
organization that develops Certbot? We'd like to send you email about our work
encrypting the web, EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: Y

… 最後,我們可以輸入要使用 SSL 憑證的域名:

Please enter in your domain name(s) (comma and/or space separated) (Enter 'c'
to cancel): copesflavio.com

安裝程式還會詢問是否記錄你的 IP 地址:

Obtaining a new certificate
Performing the following challenges:
http-01 challenge for copesflavio.com

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NOTE: The IP of this machine will be publicly logged as having requested this
certificate. If you're running certbot in manual mode on a machine that is not
your server, please ensure you're okay with that.

Are you OK with your IP being logged?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y

… 最後我們需要進行域名驗證!

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Create a file containing just this data:

TS\_oZ2-ji23jrio3j2irj3iroj\_U51u1o0x7rrDY2E.1DzOo\_voCOsrpddP\_2kpoek2opeko2pke-UAPb21sW1c

And make it available on your web server at this URL:

http://copesflavio.com/.well-known/acme-challenge/TS\_oZ2-ji23jrio3j2irj3iroj\_U51u1o0x7rrDY2E

現在,讓 Certbot 單獨執行一段時間。

我們需要通過創建一個名為 TS_oZ2-ji23jrio3j2irj3iroj_U51u1o0x7rrDY2E 的文件在 .well-known/acme-challenge/ 文件夾中來驗證我們擁有該域名。請注意!我剛剛貼入的奇怪字符串將在每次進行此過程時都改變。

由於預設情況下這些文件夾和文件並不存在,你需要創建它們。

在這個文件中,你需要放入 Certbot 打印的內容:

TS\_oZ2-ji23jrio3j2irj3iroj\_U51u1o0x7rrDY2E.1DzOo\_voCOsrpddP\_2kpoek2opeko2pke-UAPb21sW1c

至於文件名 - 這個字符串每次運行 Certbot 時都是唯一的。

允許 Express 提供靜態文件

為了從 Express 提供該文件,你需要啟用靜態文件的提供。你可以創建一個 static 文件夾,並在其中添加 .well-known 子文件夾,然後像這樣配置 Express:

const express = require('express')
const app = express()

//...

app.use(express.static(\_\_dirname + '/static', { dotfiles: 'allow' }))

//...

dotfiles 選項是必需的,否則以 . 開頭的 .well-known 文件將無法被訪問。這是一項安全措施,因為點文件可以包含敏感信息,默認情況下最好保留它們。

確認域名

現在運行應用程式,並確保該文件可以從公共互聯網訪問。返回正在運行的 Certbot,按 ENTER 鍵繼續執行腳本。

獲取憑證

完成!如果一切順利,Certbot 已經創建了憑證和私鑰,並將它們放在你計算機上的某個文件夾(當然,它也會告訴你該文件夾的位置)。

現在,只需將路徑拷貝/粘貼到應用程式中,以開始使用它們來提供請求:

const fs = require('fs')
const https = require('https')
const app = express()

app.get('/', (req, res) => {
 res.send('Hello HTTPS!')
})

https
 .createServer(
 {
 key: fs.readFileSync('/etc/letsencrypt/path/to/key.pem'),
 cert: fs.readFileSync('/etc/letsencrypt/path/to/cert.pem'),
 ca: fs.readFileSync('/etc/letsencrypt/path/to/chain.pem'),
 },
 app
 )
 .listen(443, () => {
 console.log('Listening...')
 })

請注意,我讓此服務器在 443 端口上監聽,因此需要使用 root 權限運行。

此外,此服務器僅運行在 HTTPS 上,因為我使用了 https.createServer()。你也可以同時運行一個 HTTP 服務器,只需運行以下代碼:

http.createServer(app).listen(80, () => {
 console.log('Listening...')
})

https
 .createServer(
 {
 key: fs.readFileSync('/etc/letsencrypt/path/to/key.pem'),
 cert: fs.readFileSync('/etc/letsencrypt/path/to/cert.pem'),
 ca: fs.readFileSync('/etc/letsencrypt/path/to/chain.pem'),
 },
 app
 )
 .listen(443, () => {
 console.log('Listening...')
 })

設置續訂

SSL 憑證只有效期 90 天,所以你需要設置自動續訂的系統。

如何設置呢?使用定時任務。

定時任務是一種在指定時間間隔運行任務的方式。可以是每周、每分鐘、每月等等。

在我們的例子中,我們將按照 Certbot 的建議,每天運行續訂腳本兩次。

首先,找出你系統上 certbot 的絕對路徑。我使用 macOS 上的 type certbot 命令找到它,而在我這裡它的位置是 /usr/local/bin/certbot

以下是我們需要運行的腳本:

certbot renew

這是定時任務的項目:

0 */12 * * * root /usr/local/bin/certbot renew >/dev/null 2>&1

以上代表“每 12 小時運行一次,每天運行兩次:00:00 和 12:00”。

提示:我使用 https://crontab-generator.org/ 生成了這個行。

使用以下命令將新創建的腳本添加到系統的 crontab 中:

env EDITOR=pico crontab -e

這將打開 pico 編輯器(根據你的喜好,可以替換為其他編輯器)。只需輸入新的腳本,保存,即可安裝 cron 作業。

完成後,你可以使用以下命令查看活動的 cron 作業列表:

crontab -l