0xCMS 是完全運行於 Cloudflare Workers 的邊緣原生內容管理系統。OAuth 2.1 登入、可發佈到任何目標 — 資料庫、R2 靜態 JSON、IPFS — 內建版本內容及私有媒體庫。零伺服器,零冷啟動。
❯ npm run deploy
已編譯 Tailwind 後台 UI ✓
已上載 0xcms(2.41 秒)
D1 綁定: DB · PUBLISHED_DB
R2 私有庫: MEDIA_BUCKET [private]
發佈目標: d1 · r2 · plugin:ipfs
Durable Object: PageSyncDO [realtime]
✔ 已部署到 https://cms.eventuai.com
❯
// 01 — 簡介
一個認真出版系統需要的所有能力,都編進單一 Worker。沒有 origin server,沒有需要看守的資料庫。私有資料預設分離,並為管理員及插件清楚列明信任邊界。
支援 Eventuai、GitHub、Google、Microsoft 及 Apple。雙 JWT 使用 15 分鐘 access token 及可輪換的 7 日 refresh session;撤銷會即時阻止 refresh,而已簽發的 access token 會按時到期。
發佈時會把同一份 snapshot 透過 adapter 分發出去:已發佈 D1、R2 bucket 內的靜態 JSON,或任何插件 Worker — 可 pin 到 IPFS、觸發 webhook、餵入搜尋索引。每個目標的錯誤都會在編輯器顯示。
每次儲存都會建立新的頁面版本。任何頁面都可回復到歷史任一時間點 — 你的內容帳本只會追加,不會覆寫。
每個頁面由 Durable Object 協調多人同時編輯,團隊成員不會互相覆蓋工作。
上載檔案會落在私有 R2 bucket,不會公開。Worker 會在 /media/* 控制每次讀取,並透過 /media-preview/* 即時縮圖。
以 HTTPS 註冊獨立 Worker,加入 lifecycle hooks、自訂內容類型、欄位與 blocks、後台頁面及發佈目標。毋須 runtime install 或重新部署 CMS;在後台貼上 URL,每個插件都有自己的 secret。
19 個分類 · 直接讀自原始碼
// 02 — 架構
草稿保持私有。一次發佈會建立 snapshot,並透過 adapter 分發到已發佈資料庫、靜態 JSON bucket,或你綁定的任何插件 Worker。讀者永遠不會碰到後台資料。
PUBLISH_TARGETS = "d1,r2" · 插件以 publishTarget: true · 每個目標的錯誤都會回報,絕不靜默失敗
// 03 — 開始使用
由 clone 到邊緣部署只需九步。你只需要一個 Cloudflare 帳戶和 wrangler。
由 LionRockJS/worker-cms, 取得原始碼,然後安裝。
$ git clone https://github.com/LionRockJS/worker-cms.git
$ cd worker-cms
$ npm install
兩個隔離資料庫:cms 存放私有後台資料,cms-published 只存 live content。把輸出的 database_id 複製到 wrangler.toml。
$ npx wrangler d1 create cms
$ npx wrangler d1 create cms-published
正式環境加上 --remote。本機可用 npm run db:migrate 一次套用兩個資料庫。
$ npx wrangler d1 migrations apply cms
$ npx wrangler d1 migrations apply cms-published
Bucket 保持私有;Worker 會在 /media/<key> 提供物件。MEDIA_BUCKET binding 已在 wrangler.toml 內設定。
$ npx wrangler r2 bucket create worker-cms-media
⚠️ JWT secret 必須 至少 32 字元 — 若 key 太弱,Worker 在正式環境會拒絕服務。本機開發請建立 .dev.vars。
# 隨機 32-byte 簽署 key
$ openssl rand -hex 32 | npx wrangler secret put JWT_SECRET
Plugin secret 是 逐個插件 管理:註冊時 CMS 會建立專屬 secret,因此每個插件都可獨立輪換或撤銷。新安裝毋須設定 CMS 全域 PLUGIN_SECRET;它只保留作 legacy row 的 outbound fallback,而 /__cms inbound API 絕不接受它代替專屬 secret。
在 wrangler.toml 選好 gateway,然後到每個 provider 註冊 OAuth app,取得 client ID 及 client secret。所有 provider 都會導回同一 callback,也就是你的 OAUTH_REDIRECT_URI:
# 正式環境 — 必須與 wrangler.toml 完全一致
https://<your-domain>/auth/callback
# 本機開發(.dev.vars)
http://localhost:8787/auth/callback
https://<your-domain>/auth/callback。Client ID。https://<your-domain>/auth/callback(開發用 localhost URI 也一併加入)。Client ID 及 Client secret。列出已註冊的 gateway,並把各自的 client ID 放入 wrangler.toml。同時把 CANONICAL_ORIGIN 設為你的 domain — Worker 會強制使用 canonical host,否則導向預設 origin:
[vars]
ENABLED_PROVIDERS = "eventuai,github,google"
GITHUB_CLIENT_ID = "<github-client-id>"
GOOGLE_CLIENT_ID = "<google-client-id>"
OAUTH_REDIRECT_URI = "https://<your-domain>/auth/callback"
CANONICAL_ORIGIN = "https://<your-domain>"
然後把對應的 client secrets 以加密 secrets 上傳(切勿 commit)。逐條指令執行,並在提示時貼上值:
$ npx wrangler secret put GITHUB_CLIENT_SECRET
$ npx wrangler secret put GOOGLE_CLIENT_SECRET
只應在 Wrangler 的互動提示輸入 secret,或從受保護檔案讀入;不要直接把 secret 放進 shell command、wrangler.toml 或 source control。Account、database、route 及 OAuth client ID 是識別碼,不是 bearer secret。
$ npm run dev
# → http://localhost:8787
$ npm run deploy
你的帳戶會在首次登入後才建立。當 app 在本機或邊緣運行時,打開 /auth/login 並透過任一 provider 登入一次以建立 user row,然後提升權限。Roles 以逗號分隔。
# 正式 DB — 在已部署網站登入後執行
$ npx wrangler d1 execute cms --remote \
--command "UPDATE users SET role='admin' WHERE email='[email protected]'"
在 localhost:8787 測試?移除 --remote 以操作本機 DB,然後登出再登入,讓新角色寫入 token。
$ npx wrangler d1 execute cms \
--command "UPDATE users SET role='admin' WHERE email='[email protected]'"
發佈預設使用 d1 目標。加入 r2 可把靜態 JSON snapshot 放入 bucket:
$ npx wrangler r2 bucket create worker-cms-published
# wrangler.toml — 綁定 bucket,然後啟用目標
[[r2_buckets]]
binding = "PUBLISH_BUCKET"
bucket_name = "worker-cms-published"
[vars]
PUBLISH_TARGETS = "d1,r2"
For everything else, 發佈目標 are plugin Workers. Two are ready to deploy —
plugin-publish-ipfs
(透過 Pinata 把頁面 pin 到 IPFS)及
plugin-publish-webhook
(以 HMAC 簽署 webhook,供搜尋索引、重建、部署 hook 使用)— 或自己編寫:任何 manifest 宣告 publishTarget: true 的 Worker 都可以。
# 1 · 部署插件 Worker 並記下 URL
$ git clone https://github.com/zeroxcms/plugin-publish-ipfs && cd plugin-publish-ipfs
$ npm install && npx wrangler deploy
然後在 CMS 後台打開 /admin/plugins-manage → Register plugin,貼上 Worker URL。不用重新部署 CMS,亦不用 service binding — manifest(含 publishTarget: true)會透過 HTTPS 自動發現。CMS 會為該插件建立 專屬 secret;到 Plugins → Edit 複製到插件 Worker,然後重新部署:
# 2 · 貼上 Admin → Plugins → Edit 顯示的逐插件 secret
$ npx wrangler secret put PLUGIN_SECRET
$ npx wrangler deploy
插件屬受信任的應用程式碼。代理的插件頁面及明確核准的 JavaScript 會在 CMS origin 執行;請先審閱插件 source、只批出所需 page-type scope,並在插件受損時輪換其專屬 secret。