上一章節我們用 DNS 和 Nginx,讓別人能透過網址連到我們的 Node.js Container。不過網址前面還是 http://,如果之後要傳登入帳密,總不能就這樣送出去啊
今天會把瀏覽器到 Nginx 這段改成 HTTPS,讓傳輸內容加密,也讓瀏覽器能檢查網站的憑證。憑證有到期日,所以除了申請,還要把自動續期一起處理好
接著我們一起展開這項旅程勒 :D
假設你打開 api.example.com,瀏覽器要確認對方拿出的憑證,能不能代表這個網域名稱
負責簽發憑證的機構叫做 CA(Certificate Authority,憑證機構)。這次會用到三個角色:
圖中左邊走 HTTPS 443,到了 Nginx 才解密,再透過同一台 EC2 的 127.0.0.1:8080 交給 Container。後面這一小段還是 HTTP
今天申請的是網站憑證,跟 Node.js 連到 RDS 的那段 TLS 是分開的,不用拿這張憑證去改資料庫設定哦
Let's Encrypt 不會只聽我們說「這個網域是我的」,就直接發憑證。它得先確認我們能控制這個名稱
這次使用 HTTP-01 驗證:Certbot 先替 Nginx 準備一段驗證內容,Let's Encrypt 再從外面連進網域的 80 port,到 /.well-known/acme-challenge/ 底下讀取它。確認內容正確,才會簽發憑證
所以 DNS 要指對主機,80 也要能從外部連進來。只有在 EC2 裡測 localhost 成功,還不夠哩(也附上 Let's Encrypt 驗證方式)
這個驗證證明的是網域控制權,不是在替網站內容背書。詐騙網站也可能有 HTTPS XD
延續前篇的 Ubuntu 24.04、主機上的 Nginx,以及已經能使用的網域。下面的 api.example.com 都要換成自己的名稱;如果你用的是前篇的 nip.io 名稱,就繼續用那一個
如果前篇結束後把 EC2 停機了,先啟動同一台主機,確認 Nginx 和 Container 已經運作,再從自己電腦、還沒 SSH 的終端機檢查:
dig +short api.example.com A
curl -i http://api.example.com/health
第一行會查到 EC2 的 EIP,第二行會回 200 和 {"status":"ok"}。Windows PowerShell 的第一行改成 Resolve-DnsName api.example.com -Type A,後面的 curl 都使用 curl.exe
如果另外有 AAAA 紀錄,也就是 IPv6 的 DNS 紀錄,它也得指向可用的入口;沒有使用 IPv6,就移除這個名稱底下指錯的 AAAA 紀錄,避免驗證走錯地方
接著回到 AWS 的東京區,進入 EC2 → Instances → 選自己的主機 → Security,點開主機實際掛載的 Web SG,再到 Inbound rules → Edit inbound rules:
| Type | Port | Source |
|---|---|---|
| HTTP | 80 | 0.0.0.0/0 |
| HTTPS | 443 | 0.0.0.0/0 |
80 沿用前篇,新增 443 後儲存。SSH 22 仍只允許自己的 IP,Container 的 8080 繼續留在本機,不用對外開
接下來換到 SSH 登入 EC2 的 ubuntu 視窗。先備份前篇的網站設定,再檢查 Nginx 語法:
sudo cp /etc/nginx/sites-available/demo-api /etc/nginx/sites-available/demo-api.before-https
sudo nginx -t
看到 syntax is ok 與 test is successful 再往下做。備份放在 sites-available 就好,不用連到 sites-enabled
這次依 Certbot 官方流程,使用 snap 安裝。snap 是 Ubuntu 上的套件安裝工具,我們先確認主機有它:
snap --version
如果顯示找不到指令,先執行 sudo apt update,再執行 sudo apt install -y snapd。下面以還沒裝過 Certbot 的主機為例
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/local/bin/certbot
certbot --version
第二行讓我們可以直接輸入 certbot。如果它提示檔案已存在,先用 ls -l /usr/local/bin/certbot 確認
接著申請憑證,記得換掉網域:
sudo certbot --nginx -d api.example.com --redirect
--nginx 讓 Certbot 幫忙設定 Nginx,-d 是憑證使用的網域,--redirect是把原本的 HTTP 轉到 HTTPS。依照畫面填寫自己的 Email
成功後,在 EC2 看一下同一份設定:
sudo cat /etc/nginx/sites-available/demo-api
sudo nginx -t
相關資訊如下,Certbot 會填入實際的憑證路徑~
| 設定 | 用途 |
|---|---|
listen 443 ssl |
接收 HTTPS 請求 |
ssl_certificate |
指向憑證檔案,通常以 fullchain.pem 結尾 |
ssl_certificate_key |
指向私鑰檔案,通常以 privkey.pem 結尾 |
proxy_pass http://127.0.0.1:8080 |
沿用前篇,轉給本機的 Container |
return 301 ... |
請使用者改走 HTTPS |
換回自己電腦的終端機:
curl -I http://api.example.com/health
curl -i https://api.example.com/health
第一行應看到 301,以及 Location: https://自己的網域/health。Location 就是它請你改去的新網址,/health 也要保留下來
第二行應回 200 和 {"status":"ok"}。這裡不要加 -k,因為它會跳過我們正要確認的憑證驗證
再用瀏覽器開 https://自己的網域/health,就能直接看到 JSON 沒有憑證警告。也可以從網址列的網站資訊,查看憑證的網域名稱與到期日
如果卡住,可以先這樣查查看:
| 看到什麼 | 先查哪裡 |
|---|---|
| HTTP 能連,HTTPS 卻逾時 | Web SG 的 443、Nginx 是否監聽 443;有啟用主機防火牆的話,也要放行 |
| 憑證名稱不符 | 開啟的網址是否跟申請的網域相同,有沒有還在用 IP |
| HTTPS 回 502 | Nginx 已接到請求,往下查 Container 和 127.0.0.1:8080 |
先回到 EC2 的 ubuntu 視窗,查看目前憑證:
sudo certbot certificates
Domains 是這張憑證適用的網域,Expiry Date 是到期日。接著試跑一次續期:
sudo certbot renew --dry-run
--dry-run 會使用測試環境,檢查續期流程能不能走完,不會換掉目前正式使用的憑證。輸出應該就會顯示模擬續期成功
手動試跑成功後,還要確認主機之後會自己執行續期。snap 版會建立續期排程,我們用下面兩行看看它有沒有啟用:
systemctl is-active snap.certbot.renew.timer
systemctl list-timers --all snap.certbot.renew.timer
第一行會回 active。第二行看 NEXT,也就是下次預定執行的時間。這個 timer 會定期檢查,憑證需要續期時才更新,並透過 Nginx 外掛重新載入憑證
如果 timer 存在卻是 inactive,執行 sudo snap start --enable certbot.renew,再重跑上面兩行。如果顯示找不到這個 timer,先確認是否真的使用本文的 snap 版本,不要當成已經完成
之後 DNS 改掉、或是 80 被封,或主機關機,續期還是有可能失敗。所以 80 要保留,同時提供 HTTP 轉址與這次使用的 HTTP-01 驗證
也留意一下,Let's Encrypt 已停止寄送到期提醒,不能等 Email 才想起來查看憑證勒,也附上官方(官方說明)
當你走到這裡,使用者就能經過 HTTPS → Nginx → Node.js Container,有沒有滿滿的成就感呢 XD
希望本篇你會喜歡,我們下篇見勒 :D