如何自架 Dormice agent sandbox
Dormice 可在自有 Linux VPS 執行 E2B 相容的 agent sandbox。本文示範安裝、在隔離 container 執行程式碼、檢查隔離效果,並估算主機所需資源。
Dormice 是什麼,以及它不是什麼
Dormice 是自架的 agent sandbox:在你擁有的 Linux VPS 上執行一個 daemon,讓 agent 程式透過 HTTP 呼叫,在隔離的 container 內執行不受信任的程式碼。你的程式依名稱要求 sandbox,無論 sandbox 原本處於什麼狀態,都會取得同一個 sandbox,接著在其中執行命令並讀取輸出。sandbox 是由程式操作的資源,不是供你登入的機器。
這與把整台電腦交給 agent 的方式不同。供 coding agent 使用的一次性 VM 是一台可透過 SSH 登入的主機;你讓 agent 任意修改,完成後再刪除。Dormice 再往下一層:當程式已經有程式碼,且需要安全的執行位置時,Dormice 是程式呼叫的執行 API。當整台機器是工作單位時,使用一次性 VM。當單一 exec 呼叫是工作單位,且你每天想執行 100 次而不建立 100 台 VM 時,使用 Dormice。
此專案將自身定位為 E2B 相容。E2B 是代管的 sandbox 服務,許多 agent framework 已經匯入其 client library。Dormice 使用自有的 URL prefix 提供相同的 protocol,因此,對官方 e2b package 開發的應用程式,只要將目標指向你自己的主機,就能繼續執行。應用程式程式碼不需要變更。只需變更 2 個 URL 和 1 個 API key prefix。
實務上「agent sandbox 的 SQLite」代表什麼
SQLite 是嵌入應用程式的資料庫,不是需要自行營運的服務;Dormice 直接借用了這個比較。一個 daemon、一個用於 ledger 的 SQLite 檔案,以及一個 TCP port。不需要 Kubernetes、獨立資料庫或 scheduler。daemon 會在 ledger 旁建立 lock;如果 ledger 與它找到的機器不可能屬於同一組,就拒絕啟動,因此不會悄悄發生 split brain。這套設計以單一機器為前提。如果需要跨多台主機的 fleet,README 會明確要求你選擇其他方案,你應該遵循這項建議。
這個概念的另一半與成本有關。託管 sandbox 只要存在就會按秒計費,因此託管 sandbox 天生是拋棄式的。Dormice 執行於你已經支付成本的硬體上,因此其 sandbox 可以永久保留,閒置時間越長,平均成本越低。sandbox 會逐級冷卻:active、接著是 frozen,再來是 stopped,最後是 archived。任何 acquire 都會從 sandbox 所處的階段將它喚回。
值得理解的是 freezing,因為它讓永久保留每個 agent 的 sandbox 變得負擔得起。以下是專案自行發布的數據,測試環境是專案使用的硬體,不是你的硬體。
The data behind this chart
[
{
"label": "Active, holding 1 GiB",
"resident_memory_mib": 1024,
"wake_ms": 0
},
{
"label": "Frozen",
"resident_memory_mib": 5,
"wake_ms": 50
}
]一個使用 1024 MiB 記憶體的 idle sandbox,在 frozen 後常駐記憶體會降至 5 MiB,並在約 50 ms 內恢復。程序會在原處暫停並繼續執行,因此長時間執行的 agent 在 freezing 前後仍能保留 shell 狀態與尚未完成的工作。在根據這些數據規劃容量前,請先在自己的主機上重現測試結果。
安裝前主機需要具備的條件
主機必須是 x86_64 架構的 Ubuntu 或 Debian,且安裝程式需要 root 權限。daemon 在執行期間仍會使用 root,因為它需要執行 loop mount 並寫入 cgroups。
Sandbox 會在搭配 gVisor 的 Docker 中執行。gVisor 是一種在 container 與主機 kernel 之間加入 userspace kernel 的 container runtime,提供每個 sandbox 使用的 runsc runtime。daemon 需要 Node 22 或更新版本才能執行。安裝程式會自備 Node,因此不會變更系統上的 Node。
系統必須存在 swap,且 vm.swappiness 必須是 100。這不是調校建議,而是功能需求。Freeze 的運作方式,是將閒置 sandbox 的記憶體移出至 swap。gVisor 會以 shared memory 保存 sandbox 記憶體,而 kernel 在預設的 swappiness 下不會將 shared memory swap out。專案測得預設值只能回收 0 bytes,設為 100 時則可回收 99.5 percent。請確認 kernel 實際使用的值,因為某些 cloud image 會在你不可能主動查看的檔案中設定 vm.swappiness = 0。
sysctl vm.swappiness
swapon --showsysctl vm.swappiness 應輸出 vm.swappiness = 100,而 swapon --show 應列出一個 swapfile。如果 swappiness 輸出為 0,每次 freeze 都不會產生任何作用,導致每個閒置 sandbox 都持續占用完整記憶體。
在 Ubuntu 上安裝 Dormice
文件中的安裝方式是將一個管線傳給 bash:
curl -fsSL https://raw.githubusercontent.com/BitMiracle-AI/Dormice/main/deploy/install.sh | bash執行前,請先下載並閱讀這個腳本。此腳本會以 root 身分執行,並重新調整主機環境:如果尚未安裝 Docker,便會安裝 Docker;接著下載並驗證 checksum 的 gVisor 與 Caddy、建立 swapfile、寫入 systemd unit,並加入防火牆規則。
curl -fsSL https://raw.githubusercontent.com/BitMiracle-AI/Dormice/main/deploy/install.sh -o dormice-install.sh
less dormice-install.sh
sudo bash dormice-install.sh --swap-gb 8--swap-gb 用來設定 swapfile 大小,預設值為 16。對小型 VPS 而言,這會占用過多磁碟空間。--mirror cn 會將下載來源切換為中國大陸可連線的鏡像站。重新執行安裝程式會升級程式碼並修復偏移,但不會輪換你的 API token。
程式碼會放在 /opt/dormice,設定檔放在 /etc/dormice/env,sandbox 資料放在 /var/lib/dormice,而 dormice 與 dor 指令會放在 /usr/local/bin。安裝程式會在安裝期間產生 API token,並以 mode 600 寫入 /etc/dormice/env。
目前沒有可供安裝時指定的標記版本。截至 4 August 2026,該 repository 沒有 git tag,也沒有 GitHub release,因此安裝程式會 clone main,你取得的是當天早上最新加入的內容。因此,若要固定版本,必須記錄實際安裝的 commit。
git -C /opt/dormice rev-parse HEAD請將該 hash 與部署備註一併保存。升級導致問題時,這個 commit 是唯一的復原依據,因為沒有可供指定的版本號。
安裝程式最後會執行 dor doctor。這是唯讀的主機檢查工具,會啟動實際的 gVisor container,以確認 runtime 能正常運作,而不是只依賴套件清單。daemon 行為異常時,請再次執行這項檢查。
sudo dor doctor
systemctl is-active dormicesystemctl is-active dormice 應輸出 active。如果輸出 failed,原因會記錄在 journalctl -u dormice -n 50;啟動失敗通常是 swap 或 gVisor 先決條件造成的,而不是 daemon 本身的問題。
安裝程式也會在主機上安裝 Caddy,因此在確認防火牆設定完成前,請先檢查目前有哪些服務正在監聽。
sudo ss -lntpdaemon 會繫結至 127.0.0.1:3676,而且依設計沒有可變更此設定的選項。從筆記型電腦連線到它需要刻意建立存取路徑,最簡單的方法是使用 SSH tunnel。
ssh -L 3676:127.0.0.1:3676 root@your-server建立 tunnel 後,筆記型電腦上的 http://127.0.0.1:3676/console 就是 Web console。登入時使用一次 token,之後會轉換為 httpOnly session cookie,因此頁面無法讀取 token 本身。該頁面的 Connect 頁面會顯示已指向你自己 endpoint、可直接複製貼上的 client 片段。
建立沙盒並在其中執行程式碼
有一個操作會建立沙盒:acquire。此操作具備冪等性,因此相同的 key 一律會傳回相同的沙盒,並視需要建立、喚醒、啟動或還原該沙盒。對於從未見過的 key,其他所有動詞都會回應 404。dor CLI 沒有 acquire 動詞,因此第一個沙盒必須透過主控台或用戶端程式庫建立。
使用主控台最快。透過 tunnel 開啟 /console,並建立名為 my-agent 的沙盒。之後即可使用 CLI 操作該沙盒。
sudo grep DORMICE_API_TOKEN /etc/dormice/env
export DORMICE_ENDPOINT=http://127.0.0.1:3676
export DORMICE_API_TOKEN=paste-the-value-here
dor sandbox ls
dor sandbox exec my-agent 'python3 --version'dor sandbox ls 會列出每個沙盒及其生命週期狀態,可用來監控沙盒從 active 變為 frozen。dor sandbox exec 會輸出 Python 3.12 版本,因為預設映像檔是 Ubuntu 24.04,且已安裝 Python 3.12、Node 24、git 和 ripgrep。若改為出現驗證錯誤,表示你複製的 token 行包含了變數名稱。
使用 dor sandbox push my-agent ./script.py 傳送檔案;檔案會放在 /home/user/script.py。使用 dor sandbox pull my-agent notes.txt 可將檔案取回。原生檔案動詞對單一檔案的大小上限為 16 MiB;E2B 檔案介面則會以串流方式傳輸,唯一限制是沙盒的磁碟配額。
只有 destroy 動詞會遺失資料,這也充分反映了此專案目前的發展階段:主要 README 與隨附的 agent skill 都記載 dor sandbox destroy <key>,而 CLI 套件的 README 則記載 dor sandbox release <key>。請在自己的建置上執行 dor sandbox --help,並以該結果為準。
讓現有的 E2B 程式碼指向自己的伺服器
這就是值得使用的原因。npm 提供的官方 e2b package 未經修改即可與 Dormice 通訊。保持 SSH tunnel 開啟,從筆記型電腦執行以下指令,因此伺服器上不會有新的服務監聽。
npm init -y
npm i e2b tsximport { Sandbox } from 'e2b';
const sbx = await Sandbox.create({
apiKey: `e2b_${process.env.DORMICE_API_TOKEN}`,
apiUrl: 'http://127.0.0.1:3676/e2b/api',
sandboxUrl: 'http://127.0.0.1:3676/e2b/envd',
});
const result = await sbx.commands.run('python3 -c "print(6 * 7)"');
console.log(result.exitCode, result.stdout);
await sbx.kill();DORMICE_API_TOKEN=paste-the-value-here npx tsx index.ts正常執行時會輸出 exit code 0 和 42。API key 是 Dormice token,前面加上 e2b_ prefix。這是相容層要求的格式。
這項相容性不是 stub。專案的 end-to-end 測試套件會透過官方 package,針對實際的 Docker 和 gVisor daemon,測試串流 stdout 與 stderr、背景指令、互動式 PTY、簽署的上傳與下載 URL、目錄監看,以及 port proxy。在遷移任何實際工作負載前,請先注意以下幾項差異:
- 不支援 template build。Template 是自行建置並使用
dor template add註冊的 docker image,Sandbox.create('name')會解析該 image。未註冊的名稱會回傳 404,不會假裝成功。 - 透過 E2B 介面建立的 sandbox 會套用實際的 deadline,因為 E2B 語意要求如此。透過原生 API 建立的 sandbox 永遠不會套用 deadline。
- 凍結的 sandbox 會保留其 process,並從中斷處繼續執行。因此,此處的 pause 和 resume 並不是你可能熟悉的 stop 和 cold start。
沙箱能阻擋什麼,以及不能阻擋什麼
gVisor 會在 userspace 攔截容器的 system call,並自行處理,因此沙箱內的程式碼不會直接與主機 kernel 通訊。在沙箱內,所有程式都以非特權使用者 uid 1000 執行。這種組合足以處理一般情況:產生的 script 若執行 rm -rf /、填滿磁碟,或持續 fork 直到程序崩潰,只會破壞自己的沙箱,影響不會超出該沙箱。
以下是它無法阻擋的事項。這些都需要由你負責。
- 沙箱具備對外連出的 network。產生的程式碼可以任意下載內容,也可以傳送它找到的任何資料。安裝程式的 network hardening 只處理兩件特定事項:封鎖容器流量前往 cloud metadata service 的 169.254.0.0/16;cloud 會在該網段將 instance credentials 提供給任何能連線的對象。它也會在 Docker 的
daemon.json中使用"icc": false關閉容器之間的流量。其他流量一律不會封鎖。請閱讀sudo iptables -S DOCKER-USER,並為沙箱不應連線的 private ranges 加入自己的 DROP rules。 - Docker 會將自己的 rules 插入 firewall 之前,因此即使 ufw 表示某個 published container port 已關閉,該埠仍可能從 internet 回應。對此主機開放任何服務前,請先閱讀 Docker 如何繞過 ufw 發布埠 及 VPS 的 ufw firewall 基礎。
- gVisor 是 userspace kernel,不是 hypervisor。這是刻意的取捨,因為 freeze 功能要求沙箱以 processes 執行,而要求 KVM 會使該元件無法在各種環境中安裝。若你的 threat model 要求 hardware virtualisation,請使用 Firecracker-class isolation,並接受其帶來的 operational cost。
- API token 是 client 端的完整 security boundary。任何持有
DORMICE_API_TOKEN的對象,都能在該機器上建立、讀取及刪除所有沙箱。請為 agent process 指定專用的 VPS 最小權限使用者,並以管理 SSH key 的方式管理該 token。在 VPS 上安全執行 Claude Code 的做法同樣適用。
daemon 本身會以 root 身分在主機上執行。gVisor 能保護主機,避免沙箱內的程式碼影響主機;但無法保護主機免受 daemon 或 token 持有者的影響。因此,執行 Dormice 的機器應只執行這項工作。如果你的 agent 也透過 MCP(model context protocol)使用 tools,基於相同理由,請將這些 MCP servers 放在獨立 VPS 上。
4 GB 和 8 GB 能容納多少個 sandbox?
會耗用記憶體的因素有兩個:主機本身的基線用量,以及目前處於喚醒狀態的每個 sandbox 工作集。先為 Ubuntu、Docker 和 daemon 保留約 1 GB,再將剩餘記憶體除以單一 sandbox 的實際用量。執行會讀取幾個檔案之 Python script 的 sandbox,通常約使用 200 到 300 MiB。執行 compiler 或完整 test suite 的 sandbox,可能超過 1 gibibyte。
The data behind this chart
[
{
"host": "4 GB VPS",
"active_at_512_mib": 6,
"active_at_1_gib": 3,
"frozen_on_16gb_swap": 16
},
{
"host": "8 GB VPS",
"active_at_512_mib": 14,
"active_at_1_gib": 7,
"frozen_on_16gb_swap": 16
}
]如果每個 sandbox 使用 512 MiB,4 GB VPS 一次約可讓 6 個 sandbox 保持喚醒;如果每個使用完整 1 gibibyte,則約可讓 3 個保持喚醒。8 GB VPS 對應為 14 個和 7 個。這些數字是同時執行工作的上限,屬於算術估算而非基準測試,因此請在實際負載執行時監控 free -m。
凍結的 sandbox 受 swap 限制,而不是 RAM,這正是此設計的目的。若凍結前的 sandbox 使用 1 gibibyte,凍結後大約會在 swap 中保留相同容量,幾乎不占用常駐記憶體,因此安裝程式預設的 16 GB swapfile 約可暫存 16 個 sandbox。超過此數量後,這些 sandbox 必須進入 stopped 階段,此時只占用磁碟空間。長期而言,真正的限制是磁碟:每個 sandbox 都會保留自己的檔案系統,而幾十個各自包含 node_modules 目錄的 agent,會在記憶體成為問題前就填滿小容量磁碟區。
凍結、停止、封存:生命週期控制項
預設值為閒置 10 分鐘後凍結、3 天後停止;設定封存功能後,則會在 7 天後封存。將 stopAfterSeconds 設為 null 可提供常駐 agent:閒置時仍可能凍結,但不會進行 cold start。
封存是選用功能,daemon 會明確反映設定狀態。設定 4 個 DORMICE_S3_* 變數後,已停止 sandbox 的磁碟會使用 tar 和 zstd 打包,傳送至任何相容 S3 的 bucket,並釋放本機空間。該 bucket 可以是您在另一台自有機器上自行託管的 MinIO bucket。若未設定這些變數,sandbox 會永遠停留在 stopped 狀態;若政策要求封存,系統會拒絕該要求,不會默默忽略。還原狀態也會明確顯示,不會在背景靜默進行:下一次 acquire 會立即回傳 restoring 狀態與進度值,磁碟還原完成後則切換為 ready。
目前是否適合依賴?
直接說結論:凡是無法重建的工作,都不適合依賴它。該 repository 的第一個 commit 日期為 8 July 2026。截至 4 August 2026,該專案有 446 顆 stars、37 個 forks,採用 Apache-2.0 授權,且完全沒有 tagged release。README 自己的狀態行也表示,目前沒有任何內容已準備好用於 production。
這些條件組合出特定的風險。由於 installer 會追蹤 main,程式碼可能在你使用期間變動。介面仍在調整,這正是為什麼同一個 repository 的兩個檔案中,delete verb 會使用兩個不同名稱。此外,成立僅四週的專案可能直接停止,因為授權條款沒有要求任何人持續維護。
E2B 相容性讓這項風險仍可控。你的應用程式會與一個背後有 hosted implementation 的 protocol 通訊,因此如果 Dormice 停止開發,只需修改兩個 URL 即可繼續運作。讓 agent 使用 E2B surface,而不是 native API,便能保留這條退出路徑。原生 @dormice/sdk package 目前也尚未發布到 npm;若要使用它,必須從 repository 建置。這也是一開始採用相容路徑的另一個理由。
請在可以承受遺失的環境中執行它。使用 script 重建 host,勿將 token 放入任何 prompt 或 commit,並依照你自己的 backup schedule,將任何需要保留的內容移出 sandbox。
FAQ
Dormice 已準備好用於正式環境嗎?
還沒有,專案本身也明確如此說明。README 的狀態列指出,目前其中任何內容都尚未準備好用於正式環境。截至 4 August 2026,該 repository 約建立 4 weeks,沒有 git tags,也沒有 releases,因此沒有可固定使用的版本號。安裝程式會 clone main branch,表示每次執行都會取得最新 commit。每次安裝後記錄 git -C /opt/dormice rev-parse HEAD,並將任何重要資料保存在 sandboxes 外部。
Dormice 與提供給 agent 的一次性 VM 有何不同?
一次性 VM 是一台具備 SSH 的機器,供你建立後使用一個工作階段,完成後再刪除。Dormice 是 execution API:程式呼叫 acquire,再呼叫 exec,取得 stdout 與 exit code,中間不需要 shell session。VM 適合需要暫時使用整台電腦的人員或 agent。Dormice 適合每天多次執行產生程式碼的應用程式,且不希望每次執行都處理一整台機器的設定與清理。
官方 E2B SDK 真的不需修改程式碼就能運作嗎?
可以,但需要修改設定。將 apiUrl 與 sandboxUrl 指向 daemon 上的 /e2b/api 與 /e2b/envd,並在 API key 中以 e2b_ prefix 傳入 Dormice token。Command execution、PTY sessions、file transfer、signed URLs 與 port proxy 都已由專案透過官方 package 執行的 end-to-end suite 涵蓋。Template building 是主要缺口:e2b template build 尚未實作,因此 template 是由你建置並使用 dor template add 註冊的 docker image。
4 GB VPS 可以容納多少個 sandboxes?
如果每個 sandbox 使用 512 MiB,在同一時間約可保持 6 個啟用;如果每個使用完整 1 GiB,則約可保持 3 個。這是假設預留約 1 GB 給作業系統、Docker 與 daemon。Frozen sandboxes 則受 swap 限制,因此安裝程式預設建立的 16 GB swapfile,約可容納 16 個各自曾使用 1 GiB 的 sandboxes。請在實際負載下使用 free -m 測量自己的環境,因為執行 test suite 的 sandbox 所需資源,可能是執行小型 script 的 sandbox 的數倍。
為什麼 Dormice 需要將 vm.swappiness 設為 100?
凍結 sandbox 表示將其閒置記憶體移出至 swap。gVisor 將 sandbox 記憶體保存在 shared memory 中,而 Linux kernel 在預設的 swappiness 下不會置換 shared memory。因此,在預設值下,凍結操作無法回收任何記憶體,sandbox 仍會持續占用完整記憶體。專案測得預設值回收 0 bytes,而設為 100 時可回收 99.5 percent。請使用 sysctl vm.swappiness 檢查 effective value,不要直接讀取設定檔,因為部分 cloud images 會將值設為 0。