部署到 Node.js

本頁內容

EmDash 執行於 Node.js 22.16 或更高版本。本指南對單台伺服器使用 SQLite 和本機儲存。當多個執行個體需要同一個資料庫時,使用 PostgreSQL 或 libSQL;當媒體必須獨立於伺服器磁碟存活時,使用 S3 相容儲存。

先決條件

  • Node.js v22.16.0 或更高
  • Node.js 主機提供商或 VPS

設定站點

為 Node.js 部署設定 EmDash:

import { defineConfig } from "astro/config";
import node from "@astrojs/node";
import emdash, { local, s3 } from "emdash/astro";
import { sqlite } from "emdash/db";

export default defineConfig({
	output: "server",
	adapter: node({ mode: "standalone" }),
	integrations: [
		emdash({
			database: sqlite({ url: "file:./data/emdash.db" }),
			storage: local({
				directory: "./data/uploads",
				baseUrl: "/_emdash/api/media/file",
			}),
		}),
	],
});

建置並執行

  1. 建置專案:

    npm run build
  2. 啟動伺服器:

    node ./dist/server/entry.mjs

    在啟動伺服器之前,透過主機提供商的行程環境設定 EMDASH_ENCRYPTION_KEY 和其他執行時期憑證。獨立 Node 入口不會自動載入 .env。對於使用產生的 .env 檔案的本機執行,請用 node --env-file=.env ./dist/server/entry.mjs 啟動。

伺服器預設執行於 http://localhost:4321。在預設的 auto 遷移模式下,第一次請求會套用待處理的核心遷移。全新資料庫還會收到內嵌的 seed。Manage core database migrations 說明如何在恢復生產流量之前進行遷移。

排程任務

內建排程器僅在 Node.js 行程執行時執行。它處理排程發佈、外掛任務和一般維護。

在生產中至少持續執行一個 Node.js 行程。當每個行程都停止或休眠時,排程任務會暫停。

外掛沙箱

市集外掛和列在 sandboxed: [] 下的外掛需要沙箱執行器。在 Node.js 上,執行器是 @emdash-cms/sandbox-workerd,它在 workerd 子行程中執行外掛。Plugin Sandbox 涵蓋安裝、workerd 行程如何執行及其故障模式。

選擇生產資料服務

當資料庫保留在持久磁碟區上、媒體遷移到 S3 相容儲存時,使用以下模式:

import emdash, { s3 } from "emdash/astro";

export default defineConfig({
	integrations: [
			emdash({
				database: sqlite({ url: `file:${process.env.DATABASE_PATH}` }),
				storage: s3(),
		}),
	],
});

Docker

新增 .dockerignore 以保持建置內容較小:

node_modules
dist
.git

建立 Dockerfile:

FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:22-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./

RUN mkdir -p data

ENV HOST=0.0.0.0
ENV PORT=4321

EXPOSE 4321
CMD ["node", "./dist/server/entry.mjs"]

seed 檔案在建置時讀取並內嵌到套件中,因此無需複製到執行時期映像。遷移在部署後的第一次請求時執行;僅當資料庫沒有集合且設定尚未完成時才套用 seed——現有資料永遠不會被覆寫。

建置映像並執行容器:

docker build -t my-emdash-site .
docker run -p 4321:4321 -v emdash-data:/app/data my-emdash-site

Docker Compose 檔案用命名磁碟區管理同一容器:

services:
  emdash:
    build: .
    ports:
      - "4321:4321"
    volumes:
      - emdash-data:/app/data
    restart: unless-stopped

volumes:
  emdash-data:

在背景啟動堆疊:

docker compose up -d

執行時期環境

伺服器啟動時從行程環境讀取資料庫和儲存憑證。以下變數支援上述設定:

外掛設定加密

EMDASH_ENCRYPTION_KEY 加密宣告為密鑰的外掛設定。格式錯誤的值會產生面向操作員的啟動訊息,在修復該值之前,外掛密鑰設定操作會失敗。

產生有效值並將結果新增到伺服器行程環境:

npx emdash secrets generate  # add the result to your environment

該值由操作員提供,不儲存在資料庫中。將其保存在密鑰管理器和單獨的復原備份中。輪換期間,先提供新金鑰,並在逗號後保留較舊金鑰,直到每個外掛密鑰都再次儲存。EmDash 目前不報告哪些金鑰 ID 仍在使用,因此請追蹤每個重新儲存的憑證,並在移除舊金鑰之前驗證其整合。在沒有被引用金鑰的情況下復原資料庫會使相應設定不可讀。

選用:穩定值覆寫

EmDash 自動產生預覽 HMAC 密鑰和留言者 IP 雜湊 鹽,並在首次使用時持久化到資料庫。下面的環境變數 將它們固定為你控制的值——當單獨的行程需要與主站點 共用密鑰時很有用。

變數描述
EMDASH_PREVIEW_SECRET自動產生的預覽 HMAC 密鑰的覆寫。
EMDASH_IP_SALT自動產生的留言者 IP 雜湊鹽的覆寫。
EMDASH_AUTH_SECRET選用。若設定,用作 IP 鹽來源(除非也設定了 EMDASH_IP_SALT,後者優先),使已依賴它的安裝保持留言者 IP 雜湊穩定。新部署請保持未設定。

有關金鑰格式、每個受支援的密鑰以及輪換或遺失的影響,請參見 Secrets and key management。

資料庫與儲存

變數描述範例
DATABASE_PATHSQLite 資料庫路徑/data/emdash.db
HOST伺服器主機0.0.0.0
PORT伺服器連接埠4321
S3_ENDPOINTS3 端點 URLhttps://xxx.r2.cloudflarestorage.com
S3_BUCKETS3 儲存桶名稱my-media-bucket
S3_ACCESS_KEY_IDS3 存取金鑰AKIA...
S3_SECRET_ACCESS_KEYS3 秘密金鑰...
S3_REGIONS3 區域auto
S3_PUBLIC_URL媒體的公開 URLhttps://cdn.example.com

持久儲存

SQLite 需要持久磁碟儲存。確保你的託管平台提供:

  • 已掛載的磁碟區或持久磁碟
  • 對資料庫目錄的寫入存取
  • 資料庫檔案的備份機制

同時備份 SQLite 檔案和上傳目錄。在復原期間取代其中任一者之前,先停止行程。參見 Backups。

健康檢查

為負載平衡器新增健康檢查端點:

export const GET = () => {
  return new Response("OK", { status: 200 });
};

此端點證明 Node.js 行程可以提供 Astro 路由。它不證明資料庫、儲存後端、遷移狀態或外掛沙箱是健康的。在向新版本傳送流量之前,請單獨驗證這些依賴。

傳送流量前驗證

啟動新建置後,驗證生產請求使用的相同執行時期服務:

  1. 請求 /health 和一個公開內容頁。兩者都必須回傳成功回應。
  2. 從已建置的專案執行 npx emdash migrate --check。它必須報告所設定資料庫沒有待處理或未知遷移。
  3. 登入 /_emdash/admin,建立或編輯一次性草稿並發佈。確認公開頁面顯示變更。
  4. 上傳一次性媒體檔案並開啟回傳的 URL。驗證後刪除該檔案。
  5. 若站點使用沙箱外掛,呼叫一個外掛路由或 hook,並確認伺服器日誌沒有 sandbox-unavailable 或 workerd 啟動錯誤。

在每個適用檢查通過之前,將新執行個體保持在負載平衡器之外。