---
slug: celld-self-hosted-durable-objects-runtime
title: celld：把 Durable Objects 相容 runtime 放進自己的機器
status: published
excerpt: 理解自架 Durable Objects 相容 runtime、相容範圍、網路邊界與成本。
category: Infrastructure
tags: [deno, cloudflare, durable-objects]
author: Seer
author_role: Author
read_time: 8 min
cover: "/static/celld-self-hosted-durable-objects-runtime-cover.png"
closing_note: "先把邊界講清楚，工具才能變成可靠流程。"
published_at: "2026-08-20T00:00:00Z"
updated_at: "2026-08-20T00:00:00Z"
---

[celld](https://github.com/denoland/celld) 是 Deno Land 開源的 daemon。它在自己的 Linux 機器跑一部分 Cloudflare Workers 與 Durable Objects API，讓每個 named object 有一份 SQLite 狀態，並複寫到自己控制的 S3 相容 bucket 或 Google Cloud Storage。[1][2]

可以把它理解成「自架的 Durable Objects 相容層」。它不等於把整個 Cloudflare 平台搬回家。KV、R2、Cache API、Workers AI、Vectorize、Hyperdrive、Cron、Cloudflare 網域和 TLS 都不在目前範圍內。[3][4]

查核 `main` commit `ae8fac053d79f971bfcb996054bb43eb2f9b05da`，版本 `v0.2.1`，2026-08-14。GitHub 頁面當時約 4,000 stars、126 forks。這些是查核快照，不等於生產成熟度或相容性保證。Repo 採 Apache-2.0。[1][8]

本輪只讀 repo、官方相容性文件、限制與 Cloudflare 官方文件，沒有安裝 binary、建立 bucket、部署 Worker 或啟動任何 listener。

## 先看結論

- 想做協作文件、聊天室、遊戲房、單一使用者工作區、rate limiter、presence 或每個帳號一份 state，celld 的 object 模型很適合。[2][5]
- 想沿用 Workers + Durable Objects 的大部分程式心智模型，又想把執行地點、bucket、網路與帳單放回自己的基礎設施，celld 值得評估。[2][3]
- 想用 Cloudflare 的 CDN、KV、R2、D1、AI、TLS、流量吸收與全球邊緣調度，直接用 Cloudflare Durable Objects 比較合適。[3][5]
- celld 仍是 alpha，fleet 只有單一 application deployment，沒有管理式 ingress、central placement controller 或自動更新。[4]
- 對外流量要自己放 load balancer／ingress proxy。內部 peer port 只能留在私網或加密 overlay，bucket 憑證等同 fleet 管理權限。[2][4]

## Durable Objects 是什麼

Cloudflare Durable Object 是有固定全域名稱的特殊 Worker。每個 object 同時持有 compute 與 durable storage，因此多個 client 可以把請求送到同一個 object，由它協調同一份狀態。[5]

常見形狀如下：

```text
room:general       → 一個聊天室狀態與 WebSocket 連線集合
user:42            → 一個使用者的節流計數、偏好或同步隊列
doc:abc            → 一份協作文件的 operation 與 snapshot
auction:item-9     → 一場競標的順序、倒數時間與得標狀態
```

Durable Object 的重點不在「有一個資料庫」，而在「特定名字永遠指向同一個可協調的 stateful entity」。Cloudflare 文件說明，它有 globally unique name，儲存與 object 共置，提供 strongly consistent 的 state。[5]

這個模型避開了多人同時改一列資料時的 coordination 邏輯。聊天室可以依 room ID 分片，協作文件依 doc ID 分片，使用者狀態依 user ID 分片。每個 object 的衝突和故障半徑自然收在自己的 key 裡。

## celld 怎麼實作這個模型

celld 把 Durable Object 稱為 **cell**。每個 cell 是一個 SQLite database。node 內嵌 V8，執行 Wrangler bundle。所有 node 共用一個 bucket，裡面放 deployment、cell state 與小型 ownership record。[2]

```mermaid
flowchart TB
  U["使用者"] --> I["TLS / Load Balancer"]
  I --> L["celld public listener"]
  L --> W["Named cell Worker handler"]
  W --> S["本地 SQLite state"]
  S -->|非同步複寫| B["S3 / GCS bucket: deployments, history, ownership"]
  B -->|ownership 轉移時還原| W
```

ownership 使用 object storage 的 compare-and-swap。celld 的說法是每個 cell 同一時間只會由一個 node 擁有，不靠 member list、control plane 或 consensus service。cell 移動或重新啟動時，新 owner 從 bucket 還原 SQLite state 後繼續執行。[2]

fencing 的細節值得知道：ownership record 會帶 epoch，複寫資料也依 epoch 分隔；文件主張寫入要先 durable 落到 bucket，並重新讀取 ownership 後才 ack，藉此避免舊 owner 回來覆寫新資料。這是 repo 的設計宣稱，沒有在本輪做故障注入或一致性測試。[9]

### alpha 與網路安全邊界

celld 官方把目前版本列為 alpha，明說不適用 hostile multi-tenant workload。它也不終結 TLS；public listener 要放在外部 ingress／TLS proxy 後面。internal listener 是 peer 和 operator API，文件要求留在私網、WireGuard 或 Tailscale，不可暴露到 Internet。peer traffic 有 HMAC、body signature、時鐘上限與 replay 防護，這些不等於替你的 public ingress、bucket policy、tenant isolation 做完安全設計。[10]

這帶來幾個實際效果：

- state 依 object name 自動分片
- 閒置、沒有 node 持有的 cell 幾乎沒有執行成本
- node 是可替換的，bucket 才是 durable source of truth
- 一個 cell 的熱點不會直接鎖住其他 cell

v0.2.0 起，celld 把多個 resident cell 放在共享 isolate pool，並加入壓力下的 idle cell shedding、寫入複寫 compaction、graceful drain 與 public／internal listener 分離。這些都是 repo 的設計與測量敘述，本輪未自行壓測。[1][2]

## 能做什麼

| 類型 | object key | cell 裡面放什麼 | 為什麼適合 |
|---|---|---|---|
| 即時聊天室 | `room:<id>` | WebSocket、在線名單、最後訊息、rate limit | 同一個 room 的所有人會到同一份協調 state |
| 協作文件 | `doc:<id>` | operation log、snapshot、在線編輯者 | 文件邊界就是自然分片單位 |
| 遊戲房間 | `match:<id>` | 回合、玩家狀態、倒數 alarm | 需要有順序處理事件與定時觸發 |
| 每位使用者 agent | `agent:<user-id>` | agent session、排隊工作、權限範圍 | 將長期 session 與其他使用者隔離 |
| 防重複下單 | `order:<id>` | idempotency key、狀態機 | 把同一訂單的並發收在一個 entity |
| API 節流 | `token:<customer-id>` | token bucket、次數、reset alarm | 計數與判斷在同一處完成 |

Durable Object 也有 alarms 與 hibernatable WebSockets。celld 的相容面列出 SQLite storage、alarms、inbound hibernatable WebSockets、outbound WebSocket client、named-object address 和 stub RPC。[3]

## 怎麼接

### 1. 寫 Workers + Durable Objects 專案

celld 的部署工具讀 `wrangler.jsonc` 或 `wrangler.json`。它接受 `name`、`main`、`compatibility_date`、`compatibility_flags`、`durable_objects`、`migrations`、`assets`、`services`、`vars` 這些 config key。[3]

示意設定：

```jsonc
{
  "name": "collab-app",
  "main": "src/index.ts",
  "compatibility_date": "2026-08-20",
  "durable_objects": {
    "bindings": [{ "name": "ROOM", "class_name": "Room" }]
  },
  "migrations": [{ "tag": "v1", "new_sqlite_classes": ["Room"] }]
}
```

程式的概念仍是從 Worker 取得 namespace，再用 name 取 object ID：

```ts
export default {
  async fetch(request: Request, env: Env) {
    const room = new URL(request.url).pathname.split("/").at(-1)!;
    const id = env.ROOM.idFromName(room);
    return env.ROOM.get(id).fetch(request);
  },
};

export class Room extends DurableObject {
  async fetch(request: Request) {
    // 讀寫本 room 的 state，或升級 WebSocket
    return new Response("room ready");
  }
}
```

這段是 Workers／DO 的最小模型示意，沒有對 celld 實跑。實際 API 相容範圍要以 celld 的 compatibility table 為準。[3][5]

### 2. 準備 state bucket 和 node

celld 需要 S3-compatible bucket 或 Google Cloud Storage。沒有純 local filesystem mode。即使是本機開發，也需要有 conditional writes 的真 bucket 或相容 object store。[2][4]

它用標準 AWS credential chain，或 GCS 的 Application Default Credentials。憑證必須縮到最小 bucket 範圍。拿到 bucket 的憑證，等同拿到 fleet 管理權限。[2][4]

README 的模式是先部署，再讓一台或多台 node 指向同一個 bucket：

```bash
celld deploy . --bucket s3://my-cells-bucket

celld \
  --bucket s3://my-cells-bucket \
  --listen 0.0.0.0:8080 \
  --internal-listen 10.0.0.12:8081 \
  --advertise node-a.internal:8081
```

S3 相容服務要補 `--endpoint`。Google Cloud Storage 使用 `gs://` bucket，認證與 S3 不同。[2]

### 3. 網路要切 public 和 internal

v0.2.0 將資料平面和 control plane 拆開：

- public listener：只服務 Worker routes 和 `/__celld/health`
- internal listener：operator API、node-to-node peer traffic

internal port 不可公開。README 要求放私有網路或加密 overlay，例如 WireGuard、Tailscale，並由外部 ingress proxy 處理 public TLS。[2][4]

部署時至少做這幾件事：

- load balancer 只指向 public listener
- firewall 不開 internal listener 給網際網路
- bucket 權限只給 fleet 所需 prefix
- 把 `--advertise` 指到 node 之間真正可達的 private address
- 在更新或擴容前跑 `celld diagnose --bucket ...`

## 相容範圍與移植策略

celld 支援 module Worker、`fetch`、JS RPC、service bindings、DO bindings、`vars` 與 static assets。無法用的 binding 或 config 原則上應在 deploy 或 first use 報錯。[3]

幾個很重要的空洞：

| Cloudflare 功能 | celld 現況 | 遷移時怎麼處理 |
|---|---|---|
| Durable Objects | 核心支援 | 可先從 DO-only app 評估 |
| D1 | planned | 改用 cell SQLite 或外接資料庫 |
| KV | out of scope | 另接 Redis／Valkey 或保留 Cloudflare KV |
| R2 | out of scope | celld 自己使用 S3/GCS，應用 blob 改接同一類 object storage |
| Cache API | 無 | 交給 CDN／reverse proxy／外部 cache |
| Workers AI／Vectorize | 無 | 外接模型或向量服務 |
| Cron Trigger | 無 | 用 DO alarm、外部 scheduler 或系統排程 |
| TLS、custom domains | 無 | Caddy、Nginx、Traefik 或雲端 LB |
| `wrangler.toml` | 不接受 | 轉成 `wrangler.jsonc` |

適合的遷移順序是：先抽一個 DO-only 功能，例如 room presence 或 user rate limit，讓它只依賴 Worker + DO + SQLite。確認壓力、失敗轉移、WebSocket 與 bucket 成本後，再決定是否擴大。

## 費用：Cloudflare 跟自架怎麼比

兩條路的帳單模型不同。

### Cloudflare Durable Objects

Cloudflare Durable Objects 有 compute 和 storage 兩種計費。Workers Paid 最低每月 5 美元，DO Paid 含 100 萬 requests、40 萬 GB-s duration、SQLite 250 億 row reads、5,000 萬 row writes 與 5 GB-month storage，超量再按使用計費。[6][7]

| DO Paid 項目 | 包含量 | 超量價格 |
|---|---:|---:|
| Requests | 100 萬／月 | US$0.15／百萬 |
| Duration | 40 萬 GB-s／月 | US$12.50／百萬 GB-s |
| SQLite rows read | 250 億／月 | US$0.001／百萬 rows |
| SQLite rows written | 5,000 萬／月 | US$1.00／百萬 rows |
| SQLite storage | 5 GB-month | US$0.20／GB-month |

WebSocket 要特別注意 duration。傳統 `accept()` 會讓 object 在連線期間持續產生 duration；使用 WebSocket Hibernation 才能讓 idle state 不算 duration。Cloudflare 官方的 100 個 objects、各 50 條 socket、每日 8 小時活躍的範例，總估算為每月 US$419.30。採 hibernation 的類似模型能顯著下降。[6]

### celld 自架

celld 自身採 Apache-2.0，沒有服務使用費。帳單轉成你選的：

- VM 或裸機的 CPU／記憶體／磁碟
- S3、R2、MinIO 或 GCS 的 storage 與 operation
- load balancer、TLS proxy、private network／overlay
- logging、metrics、on-call、備份與升級的工程成本

celld 用 S3-compatible bucket 當 replicated state 和 ownership authority。它不等同於 R2 binding，但 R2 可作 S3-compatible bucket 端點，這是 README 提到的部署方式。[2][3]

因此自架比較適合已有固定機器、私網與 object storage 的團隊，或資料／合規要求必須離開 managed edge 的情境。若目標是最快開始、全球就近啟動、CDN 與平台服務一起用，Cloudflare 的管理式 DO 通常省下更多操作成本。

## 目前限制與風險

- alpha，單一 fleet 只跑一個 application deployment，沒有 multi-tenant scheduler 或 account service。[4]
- 沒有 central placement controller。新 node 加入不會主動重平衡，正常流量才會讓 unowned／released cell 找到可用 node。[4]
- TLS 不在 peer protocol 內，必須由 ingress proxy 或私網／overlay 處理。[4]
- peer 跨 node WebSocket reconnect 的測試覆蓋較薄。對 latency 敏感的 cell，應盡量讓 ingress 對到 owner node。[4]
- Windows 不支援，Intel Mac 沒有 prebuilt binary。[4]
- 有些 API 還是 partial，且個別 Node／Cloudflare API 可能提供 inert stub 或缺口。production 前要以 compatibility table 逐項測自己的依賴。[3]
- 不要直接把 internal listener、operator API 或 bucket credentials 曝露到 public internet。[2][4]

## 結語

celld 的價值在於把「一個 key 對一個可協調、可持久化 stateful entity」這個 Durable Objects 模型帶到自己控制的機器與 bucket。它很適合切出聊天房、文件、遊戲局、每位使用者 agent session 或節流器等 entity 型工作負載。

它目前仍是功能邊界清楚的 alpha runtime。拿它替代 Cloudflare 前，先盤點你依賴的是 Durable Objects 本身，還是 Cloudflare 的整套邊緣平台服務。前者能開始做相容性與故障轉移驗證，後者大多還需要保留 managed platform 或自行補上基礎設施。

## Sources

[1] https://github.com/denoland/celld — denoland/celld repository
[2] https://raw.githubusercontent.com/denoland/celld/ae8fac053d79f971bfcb996054bb43eb2f9b05da/README.md — celld README v0.2.1 commit ae8fac0
[3] https://celld.dev/docs/cloudflare-compat — celld Cloudflare compatibility
[4] https://celld.dev/docs/limitations — celld limitations
[5] https://developers.cloudflare.com/durable-objects — Cloudflare Durable Objects overview
[6] https://developers.cloudflare.com/durable-objects/platform/pricing — Cloudflare Durable Objects pricing
[7] https://developers.cloudflare.com/workers/platform/pricing — Cloudflare Workers pricing
[8] https://raw.githubusercontent.com/denoland/celld/ae8fac053d79f971bfcb996054bb43eb2f9b05da/LICENSE — celld Apache-2.0 license
[9] https://raw.githubusercontent.com/denoland/celld/ae8fac053d79f971bfcb996054bb43eb2f9b05da/docs/fencing.md — celld fencing design
[10] https://raw.githubusercontent.com/denoland/celld/ae8fac053d79f971bfcb996054bb43eb2f9b05da/docs/security.md — celld security boundary
