部署於邊緣網絡 · 300+ 節點

內容管理,
天生去中心化
為邊緣而設。

0xCMS 是完全運行於 Cloudflare Workers 的邊緣原生內容管理系統。OAuth 2.1 登入、可發佈到任何目標 — 資料庫、R2 靜態 JSON、IPFS — 內建版本內容及私有媒體庫。零伺服器,零冷啟動。

0ms
冷啟動
發佈目標
頁面版本
0xcms — wrangler@edge

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,沒有需要看守的資料庫。私有資料預設分離,並為管理員及插件清楚列明信任邊界。

🔐

OAuth 2.1 + PKCE

支援 Eventuai、GitHub、Google、Microsoft 及 Apple。雙 JWT 使用 15 分鐘 access token 及可輪換的 7 日 refresh session;撤銷會即時阻止 refresh,而已簽發的 access token 會按時到期。

⛓️

Pluggable 發佈目標

發佈時會把同一份 snapshot 透過 adapter 分發出去:已發佈 D1、R2 bucket 內的靜態 JSON,或任何插件 Worker — 可 pin 到 IPFS、觸發 webhook、餵入搜尋索引。每個目標的錯誤都會在編輯器顯示。

🧬

所有內容都有版本

每次儲存都會建立新的頁面版本。任何頁面都可回復到歷史任一時間點 — 你的內容帳本只會追加,不會覆寫。

🛰️

即時頁面同步

每個頁面由 Durable Object 協調多人同時編輯,團隊成員不會互相覆蓋工作。

🗄️

私有媒體庫

上載檔案會落在私有 R2 bucket,不會公開。Worker 會在 /media/* 控制每次讀取,並透過 /media-preview/* 即時縮圖。

🧩

Worker 插件

以 HTTPS 註冊獨立 Worker,加入 lifecycle hooks、自訂內容類型、欄位與 blocks、後台頁面及發佈目標。毋須 runtime install 或重新部署 CMS;在後台貼上 URL,每個插件都有自己的 secret。

查看完整功能清單

19 個分類 · 直接讀自原始碼

預設已加固: CSP nonce 速率限制 跨來源修改保護 Canonical host 強制檢查 以能力為本的權限控制

// 02 — 架構

像鏈上一樣清晰的 發佈流程

草稿保持私有。一次發佈會建立 snapshot,並透過 adapter 分發到已發佈資料庫、靜態 JSON bucket,或你綁定的任何插件 Worker。讀者永遠不會碰到後台資料。

DB · 私有
users · sessions
draft_pages · page_versions
tags · trash · media_files
— 發佈 ⟶ 取消發佈
d1 · PUBLISHED_DB
live_pages · live_page_tags
r2 · static JSON
pages/<uuid>.json · index.json
plugin · 你的 Worker
IPFS · webhook · 搜尋索引
— 讀取 ⟶ 邊緣快取
🌐 公開網站
Liquid 模板
由 300+
邊緣節點提供

PUBLISH_TARGETS = "d1,r2" · 插件以 publishTarget: true · 每個目標的錯誤都會回報,絕不靜默失敗

Hono + TypeScript
路由及 runtime
Tailwind + VanillaJS
零框架後台 UI
LiquidJS + Emmet
模板及內容編寫

// 03 — 開始使用

建立你的 專屬 instance

由 clone 到邊緣部署只需九步。你只需要一個 Cloudflare 帳戶和 wrangler

01

Clone repo 及安裝依賴

LionRockJS/worker-cms, 取得原始碼,然後安裝。

$ git clone https://github.com/LionRockJS/worker-cms.git
$ cd worker-cms
$ npm install
02

建立 D1 資料庫

兩個隔離資料庫:cms 存放私有後台資料,cms-published 只存 live content。把輸出的 database_id 複製到 wrangler.toml

$ npx wrangler d1 create cms
$ npx wrangler d1 create cms-published
03

執行 migrations

正式環境加上 --remote。本機可用 npm run db:migrate 一次套用兩個資料庫。

$ npx wrangler d1 migrations apply cms
$ npx wrangler d1 migrations apply cms-published
04

建立私有 R2 媒體庫

Bucket 保持私有;Worker 會在 /media/<key> 提供物件。MEDIA_BUCKET binding 已在 wrangler.toml 內設定。

$ npx wrangler r2 bucket create worker-cms-media
05

設定 secrets

⚠️ 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。

06

啟用 OAuth provider

wrangler.toml 選好 gateway,然後到每個 provider 註冊 OAuth app,取得 client IDclient secret。所有 provider 都會導回同一 callback,也就是你的 OAUTH_REDIRECT_URI

# 正式環境 — 必須與 wrangler.toml 完全一致
https://<your-domain>/auth/callback
# 本機開發(.dev.vars)
http://localhost:8787/auth/callback

GitHub — scopes: read:user, user:email

  1. 前往 github.com/settings/developersOAuth AppsNew OAuth App. (如為 org-owned app,請到該 org 的 Settings → Developer settings。)
  2. Homepage URL 設為你的 domain,並把 Authorization callback URL 設為 https://<your-domain>/auth/callback
  3. Register application,複製 Client ID
  4. Generate a new client secret 並即時複製 — GitHub 只會顯示一次。

Google — scopes: openid, email, profile

  1. 打開 console.cloud.google.com/apis/credentials 並選擇(或建立)project。
  2. 先設定 OAuth consent screen — 選 External,填入 app 名稱及支援電郵。App 未公開前,請在 Test users 加入你的電郵。
  3. 前往 CredentialsCreate CredentialsOAuth client ID → application type Web application.
  4. Authorized redirect URIs 加入 https://<your-domain>/auth/callback(開發用 localhost URI 也一併加入)。
  5. Create,然後複製 Client IDClient 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。

07

本機執行

$ npm run dev
# → http://localhost:8787
08

部署到邊緣 🚀

$ npm run deploy
09

登入,然後授予自己 admin 權限

你的帳戶會在首次登入後才建立。當 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]'"
++

Optional: fan out to more 發佈目標

發佈預設使用 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-manageRegister 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。

// 準備好就開始

不用盲信。
親自驗證。

Live instance 此刻已在邊緣運行。

開啟 0xCMS ↗

cms.eventuai.com