如何使用流行的免費解決方案 Let’s Encrypt 設置 HTTPS
如果你在自己的 VPS 上運行 Node.js 應用程式,你需要一個獲取 SSL 憑證的解決方案。
使用 Let’s Encrypt 和 Certbot 是當今的標準做法,它們是由 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