在 Raspberry Pi 上自行託管 Node.js 網站

對許多開發者而言,自行託管的吸引力不僅在於成本,更在於掌控。雖然 Vercel 或 Netlify 等平台提供無縫部署,但有時特定的技術需求——例如需要舊版動態函式庫或偏好完整環境所有權——會使自建伺服器成為更好的選擇。

使用 Raspberry Pi 作為網頁伺服器是學習網路、伺服器管理與部署流程細節的絕佳方式。本指南概述了在 Raspberry Pi 上託管基於 Node.js 的網站(例如使用 Astro 或 Svelte 建置的網站)的精簡流程。

架構概覽:從路由器到瀏覽器

要讓網站從家庭網路對全世界可存取,必須在本地私有 IP 與公開 IP 之間建立橋樑。

1. 端口轉發與反向代理

第一步是設定路由器,將進入的流量轉發至 Raspberry Pi 的特定內部 IP 位址。由於路由器介面差異甚大,此步驟需參考您所使用硬體的說明文件。

當流量抵達 Pi 後,您需要一種方式來處理請求與管理 SSL 憑證。Caddy 是高度推薦的工具,因為它會自動處理 HTTPS。以下是一個 Astro 網站的典型 Caddyfile 設定範例:

m4rt.nl {
    root * /home/mart/Documents/m4rt.nl
    file_server
    reverse_proxy localhost:4321
}

在此設定中,Caddy 直接提供靜態檔案,並將請求代理至執行於 4321 埠的 Node.js 程序。

2. DNS 設定

設定伺服器後,您必須將網域指向家庭網路。這可透過在 DNS 服務提供商的設定中新增 A Record,將您的網域(例如 yoursite.com)映射至 ISP 提供的公共 IP 位址。

管理應用程式生命週期

每次變更時手動執行建置腳本效率低下。要打造可投入生產的環境,您需要一個程序管理器與部署管線。

使用 PM2 進行程序管理

部署 Node.js 應用時,不能僅在終端機會話中執行啟動指令,因為會話關閉後程序會終止。PM2 是一個生產環境的程序管理器,可讓應用在背景持續運行,並在崩潰時自動重新啟動。

執行 npm run build 後,您可以使用以下指令啟動入口點: pm2 run entry.mjs

使用 GitHub Actions 自動化部署

為了模擬現代雲平台的「push-to-deploy」體驗,您可以使用 GitHub Actions 實作 CI/CD 管線。透過建立工作流程檔案(例如 .github/workflows/update_server.yml),每當您將程式碼推送至儲存庫時,即可透過 SSH 觸發遠端更新。

使用 appleboy/ssh-action,工作流程可安全地以主機 IP 與密碼的祕密資訊連接至 Pi,然後執行本機 shell 腳本來處理更新。

更新腳本

一個健全的更新腳本應能處理多個專案,並確保拉取最新程式碼後進行建置。此類腳本的範例邏輯包括:

  1. 迭代基礎資料夾中的目錄。
  2. 檢查是否存在 .git 資料夾,以執行 git pull
  3. 透過 package.json 辨識 Node.js 專案,並以特定埠執行建置指令。
  4. 重新啟動所有 PM2 程序以套用變更。

安全性考量與替代方案

雖然端口轉發是讓網站快速上線的方式,但它會將家庭網路的埠暴露於公共互聯網,可能帶來安全風險。

正如社群成員在相關討論中指出的,對家庭防火牆打洞可能存在風險。更安全的替代方案是使用 Cloudflare Tunnel。Tunnel 會在您的伺服器與 Cloudflare 網路之間建立安全的僅向外連線,無需在路由器上開放埠,且可隱藏家庭的公共 IP 位址。

結合 Raspberry Pi 與 Caddy、PM2、GitHub Actions 等工具,開發者即可在客廳打造全自動、專業等級的託管環境。

Sources