Cloudflare Workers 的開發體驗在無伺服器這個賽道幾乎沒有對手——一支 wrangler deploy 把 JavaScript 推上去,請求進來幾毫秒內冷啟、KV 跟 R2 binding 直接拿來用、Cron Trigger 排程內建。但這個體驗的代價是廠商鎖定到骨子裡:KV、R2、Durable Objects、Service Binding 全是 Cloudflare 的專有介面,搬離平台等同於整套程式碼重寫。
OpenWorkers 是 2026 年 1 月在 Hacker News 上冒出來的專案,用 Rust 直接綁 rusty_v8 重寫了一套相容於 Cloudflare Workers 程式設計模型的執行環境。和過去那些「Workers 替代品」最大的差別在於:它不是把 Node.js 或 Deno 套上 Workers 風格的 wrapper,而是真的下到 V8 isolate 這一層,把整套執行環境跟 binding 系統重新實作一次。對於想要 Workers 開發體驗但拒絕被綁在 Cloudflare 帳單上的團隊,這是 2026 年目前最值得追蹤的選項。
V8 isolate 為什麼跟容器化函式不是同一回事
把 OpenWorkers 跟「Lambda、Cloud Run、Knative 之類的容器化函式」放在一起比較會看不出差異——表面上都是「事件進來、跑一段程式碼、回應出去」。差別在隔離單位的層級。
Lambda 把每個函式打包成一個 container image,每次冷啟動要拉起一個 microVM(Firecracker),記憶體跟 CPU 都是獨立分配的。即使最快的冷啟也要幾十毫秒到幾百毫秒,常駐記憶體最少 128MB 起跳,閒置實例要錢。
V8 isolate 是另一種模型。一個作業系統 process 裡可以同時存在幾千個 isolate,每個 isolate 有獨立的 heap、獨立的 global 物件、彼此完全看不到對方的記憶體,但共用同一個 V8 引擎實例。冷啟動只是 instantiate 一個新的 isolate context,通常 5 毫秒以下完成;每個 isolate 的記憶體基線可以低到幾 MB。
這個架構在 Cloudflare 全球三百個 PoP 的規模下意義很大——每個 PoP 機房不必為了某個冷門 worker 預留一整顆 CPU。在自架單一機房的場景,意義會打折扣,但對於「同一臺機器要跑幾百個小型 JS 服務」的場景,isolate 的密度還是壓倒性贏過容器。
為什麼是 rusty_v8 而不是 vm2、deno-core
OpenWorkers 一開始選用過 vm2 跟 deno-core,後來都換掉。這段技術選型的演進值得細看,因為它反映了 JavaScript 沙箱這條路線的現實。
vm2 是 Node.js 生態裡早期最常被推薦的 sandbox 套件,2023 年因為 CVE-2023-29017 與後續一連串無法修補的 escape 漏洞,原作者直接宣告 vm2 不再維護、不應該被當作安全邊界使用。任何把 vm2 當沙箱跑使用者程式碼的服務,本質上都是裸奔。
deno-core 是 Deno runtime 的核心模組,把 V8 跟 Tokio 整合在一起。技術上沒問題,但它把整個 Deno 的 Web API(包含 Deno.* 命名空間下的檔案系統存取、子程序、網路 syscall)都帶進來。如果只想要一個乾淨的 JavaScript 執行環境、自己決定要暴露什麼 binding,deno-core 等於先把不需要的東西全塞進來再想辦法關掉。
rusty_v8 是 Deno 團隊維護的另一個套件——純粹是 V8 的 Rust 綁定,沒有任何 runtime 概念。要建立 isolate、要暴露 host function、要從 Rust 端 throw exception 進 JavaScript,全部都得自己寫。但好處也很直接:執行環境裡有什麼,全是 OpenWorkers 自己決定的,沒有藏起來的 syscall、沒有預設啟用的 Web API。
對於要實作 Cloudflare Workers 相容介面的場景,這個選擇近乎必要。Cloudflare 對 worker 能存取什麼定義得很嚴格——只有 fetch、KV、R2、Durable Objects、Service Binding 這些明確的 binding,沒有 process、沒有 fs、沒有任意 socket。要做出語意一致的相容層,從 rusty_v8 起手反而比從 deno-core 砍 API 來得乾淨。
binding 系統的相容深度
OpenWorkers 目前實作的 binding 涵蓋了 Cloudflare Workers 八成的常用情境:
- KV namespace:
env.MY_KV.get(key)這套介面直接相容,背後接 PostgreSQL 的 key-value table - R2 bucket:對應到任何 S3 相容的物件儲存,可以指向 MinIO、Garage、Backblaze B2 或 AWS S3
- Service Binding:worker 之間互相呼叫,語意跟 Cloudflare 的
env.OTHER_WORKER.fetch()一致 - 環境變數與 Secrets:透過儀表板或 API 設定,注入到
env物件 - Cron Trigger:支援 5 欄位跟 6 欄位 cron 語法,排程器是獨立元件
Durable Objects 跟 WebSocket Hibernation 還在 roadmap 上,這兩個是 Cloudflare Workers 真正難複製的部分——Durable Objects 要解決全球一致性、WebSocket Hibernation 牽涉到把長連線從 isolate 解綁。在 OpenWorkers 補上這兩個之前,依賴 Durable Objects 做狀態管理的程式碼遷移過去會卡關。
Workers AI 那條線完全沒有對應——本來就是綁定 Cloudflare 自家的推論基礎設施,要替代得自己接 Ollama 或 vLLM。但這在自架場景反而是好事,可以選用本地模型而不是被綁在某家服務的 token 計費。
部署架構與一份 docker-compose
OpenWorkers 把整套執行環境拆成幾個獨立服務:
- nginx:前端代理,處理 TLS termination 跟 routing
- dashboard:Web UI,管理 worker、binding、log
- api:控制平面 API,提供部署、設定、metrics
- runners:實際執行 isolate 的工作節點,可以水平擴展
- scheduler:cron trigger 的排程器
- logs:執行日誌收集與查詢
- postgate:PostgreSQL 連線池與 binding 後端
- NATS:服務間訊息通訊
聽起來很複雜,實際部署只需要一份 docker-compose.yml 跟一個 PostgreSQL 實例。官方倉庫把所有元件包成同一份 Compose,clone 下來改幾個環境變數就能跑:
1 | git clone https://github.com/openworkers/openworkers-infra |
最小化部署的資源需求是 2 vCPU、4GB RAM、20GB SSD。runner 數量根據預期負載調整,每個 runner 預設能撐 50 到 100 個併發 isolate,視 worker 的記憶體使用而定。
跑起來之後從 dashboard 用 wrangler 相容的 CLI 部署:
1 | npx @openworkers/cli login https://workers.example.com |
wrangler.toml 的格式基本沿用,只是 binding 的 namespace ID 改成 OpenWorkers 自己的識別碼。已經有 Cloudflare Workers 程式碼的團隊,遷移成本主要落在「重新建立 KV namespace、重新上傳 R2 bucket 內容」這塊,程式碼本身改動很少。
沙箱不是安全邊界,這件事要先講清楚
OpenWorkers 在 Hacker News 上被問到最多的問題就是:V8 isolate 算不算 security boundary?開發者的回應很誠實——「the sandboxing is more about resource isolation than security-grade multi-tenancy」,要跑真正不可信的程式碼,請在 isolate 外面再包一層 container 或 VM。
這個立場其實是對的。V8 本身雖然有 sandbox,但 V8 的 CVE 歷史證明 isolate 之間的隔離不是設計來抵擋對抗性攻擊的——Cloudflare 之所以敢拿 isolate 跑多租戶,是因為他們有完整的內部威脅模型、加上 isolate 之外的多層次防禦(網路隔離、行為偵測、shadow execution)。
對自架使用者來說這意味著兩種使用模式:
單租戶或受信任程式碼:自己團隊寫的 worker、內部服務、合作夥伴的程式碼,isolate 提供的資源隔離(CPU 100ms、記憶體 128MB)就夠了。
多租戶或不可信程式碼:把每個租戶的 runner 跑在獨立的 container 裡,或更激進一點放進獨立的 VM。OpenWorkers 的 runner 設計成可以水平擴展,多開幾個 runner 把不同租戶綁到不同 runner 是合理的做法。
對於只想替自家業務找 Workers 自架方案的團隊,第一種模式直接適用,不必過度焦慮。
自架邊緣這個說法本身要重新校準
社群討論裡有一派質疑:自架 Workers 失去了邊緣運算的意義,因為自家機房不可能有三百個 PoP。這個質疑技術上對,但搞錯了使用情境。
邊緣運算的核心好處有兩個:低延遲(地理上靠近使用者)、高吞吐(請求不需要回源)。Cloudflare Workers 之所以強,是因為這兩個好處同時有。自架到單一機房只能拿到第二個——請求不需要再回源到另一臺 origin server——對於 API gateway、邊緣鑑權、靜態內容前置處理這些場景,第二個好處的價值就夠了。
更具體的場景:把原本跑在後端的某些輕量邏輯(A/B 測試分流、IP 黑白名單、bot 偵測、redirect 規則)從 application server 拆出來放進 worker,application server 就能專注處理真正的業務邏輯。這套架構在自架單機房下完全成立。
如果用戶分佈全球、低延遲是硬需求,那 Cloudflare 那種 anycast 邊緣本來就無法自架——這時要的是 Workers 那套,不是 OpenWorkers。
該選 OpenWorkers 還是直接用 Cloudflare Workers
放下意識形態的話,這個決策其實有清楚的判斷點。
該選 OpenWorkers 的情境:
- 已經被 Cloudflare 帳單嚇到——AI 生成的程式碼產生意外的高請求量這件事在 2025 到 2026 年發生過好幾次
- 監管或合規要求資料不能離境,臺灣金融業、政府專案常見
- 想把 Workers 當作 microservice 平台用,部署在自家機房裡
- 已經有 Postgres 跟物件儲存的基礎設施,希望把 worker 接到既有資料層
該繼續用 Cloudflare Workers 的情境:
- 真的需要全球邊緣 PoP 的低延遲分佈
- 依賴 Durable Objects 做全球一致性狀態管理
- 流量規模還小,免費或 $5 方案就夠用,自架的維運成本不划算
- 重度使用 Workers AI、Vectorize、Hyperdrive 這些 Cloudflare 專屬服務
中間有一個值得考慮的混合模式:把對延遲敏感、對外公開的入口放在 Cloudflare Workers,把對成本敏感、邏輯較重的後端 worker 放在 OpenWorkers,前後透過 fetch 或 service binding 串起來。這樣既享受到全球邊緣的低延遲,又把運算密集的部分搬回自家機房控制成本。
把 Workers 那套搬回自家機房之後
無伺服器 JavaScript runtime 這條路線過去幾年被 Cloudflare、Vercel、Netlify、Deno Deploy 佔滿,「自架」幾乎不在這個賽道的選項裡。OpenWorkers 用 rusty_v8 直接從 V8 引擎這層重做,把 Cloudflare 那套開發體驗從「只能在他們的雲跑」拉到「可以在任何一臺 Linux 機器跑」,這在心智模型上是個明顯的改變。
要在自家機房或 VPS 上跑 OpenWorkers 平穩運轉,幾個基礎設施條件要先到位:穩定的 PostgreSQL(KV 跟 metadata 都靠它)、可靠的物件儲存(R2 binding 的替代)、有規模一點的話再加上獨立的 NATS 集群。CPU 要選單核心效能好的——V8 isolate 的 JIT 編譯對單核效能敏感,多核心數量遠不如時脈高來得有感。
NCSE Network 在臺灣的節點位於是方電訊機房,並提供採用 Intel Xeon Gold CPU 的 VPS 主機與 NVMe SSD 儲存;對於跑 OpenWorkers 這類重視單核效能與低延遲 I/O 的 JavaScript runtime,是合適的底層配置。搭配臺灣 IP Transit 的線路品質,自架邊緣運算服務的本地延遲體驗會比放在海外節點明顯好。前往 ncse.tw 了解規格與方案。