DormiceをVPSにセルフホストする方法
DormiceでE2B互換のエージェントサンドボックスを自分のLinux VPSに構築します。インストール、コード実行、分離の確認、必要なホストサイズまで解説します。
Dormice とは何か、何ではないか
Dormice はセルフホスト型のエージェントサンドボックスです。所有する Linux VPS 上で 1 つのデーモンを動かし、エージェントのコードから HTTP 経由で呼び出して、信頼できないコードを分離されたコンテナ内で実行します。プログラムは名前でサンドボックスを要求し、サンドボックスがどの状態であっても同じものを取得し、その中でコマンドを実行して出力を読み取ります。サンドボックスはプログラムから操作するリソースであり、ログインするマシンではありません。
これは、エージェントにコンピューター全体を与える構成とは異なります。コーディングエージェント用の 使い捨て VM は、SSH でログインし、エージェントに壊させてから削除するボックスです。Dormice は 1 段階下に位置します。すでにコードがあり、安全に実行する場所が必要なときに、プログラムから呼び出す実行 API です。マシン全体を作業単位にする場合は使い捨て VM を使用します。1 回の exec 呼び出しを作業単位にし、1 日に 100 回実行するために 100 台の VM を用意したくない場合は Dormice を使用します。
このプロジェクトは E2B 互換をうたっています。E2B はホスト型のサンドボックスサービスで、多くのエージェントフレームワークがそのクライアントライブラリをすでに import しています。Dormice は独自の URL プレフィックスで同じプロトコルを提供するため、公式の e2b パッケージを使用するアプリケーションでも、接続先を自分のサーバーに変更すれば動作を継続できます。アプリケーションコードは変更しません。変更するのは 2 つの URL と 1 つの API キープレフィックスだけです。
エージェント用サンドボックスの「SQLite」とは実際に何を意味するか
SQLite は運用するサービスではなく、組み込んで使うデータベースです。Dormice はこの比較をそのまま取り入れています。デーモンは 1 つ、台帳用の SQLite ファイルは 1 つ、TCP ポートは 1 つです。Kubernetes、別個のデータベース、スケジューラーは必要ありません。デーモンは台帳の隣にロックを取得し、台帳と検出したマシンが同じ組み合わせに属し得ない場合は起動を拒否します。そのため、スプリットブレインが気付かないまま発生することはありません。設計上、マシンは 1 台です。複数のホストにまたがるフリートが必要な場合は、README に別のものを選ぶよう明記されています。その指示に従ってください。
この考え方の後半は、コストに関するものです。ホスト型サンドボックスは存在する 1 秒ごとに課金されるため、設計上は使い捨てです。Dormice はすでに料金を支払っているハードウェア上で動作するため、サンドボックスは永続的に保持でき、停止したままの期間が長いほど安価になります。サンドボックスは、active、frozen、stopped、archived の順に 1 段階ずつ休止します。どの段階に到達していても、acquire すれば再び起動します。
すべてのエージェントのサンドボックスを永続的に保持しながらコストを抑えられる理由は、凍結の仕組みにあります。以下はプロジェクトが公開している独自の測定値です。プロジェクトのハードウェアで測定した値であり、お使いの環境での値ではありません。
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 のメモリを使用してアイドル状態にあるサンドボックスは、凍結すると常駐メモリが 5 MiB まで減少し、約 50 ms で復帰します。プロセスはその場で一時停止・再開されるため、長時間動作するエージェントは、凍結をまたいでもシェルの状態と途中までの作業を保持できます。この値を基に容量を計画する前に、自分のホストで再現性を確認してください。
インストール前にホストで必要な条件
ホストは x86_64 上の Ubuntu または Debian で、インストーラーの実行には root が必要です。デーモンはループマウントを実行し、cgroup に書き込むため、実行時も root のまま動作します。
サンドボックスは、gVisor(コンテナとホストのカーネルの間にユーザー空間カーネルを配置するコンテナランタイム)を使用して Docker 上で実行します。これにより、各サンドボックスが使用する runsc ランタイムが提供されます。デーモンの実行には Node 22 以降が必要です。インストーラーが独自の Node を同梱するため、システムの Node は変更されません。
Swap が存在し、vm.swappiness は 100 でなければなりません。これはチューニングの推奨値ではなく、機能要件です。アイドル状態のサンドボックスのメモリを Swap に追い出すことでフリーズが機能します。gVisor はサンドボックスのメモリを共有メモリとして保持するため、デフォルトの swappiness ではカーネルが共有メモリを Swap に移動しません。プロジェクトの測定では、デフォルト値で解放されたメモリは 0 bytes でしたが、100 では 99.5 percent が解放されました。クラウドイメージによっては、読もうとは思わないファイルに vm.swappiness = 0 が設定されているため、カーネルが実際に使用している値を確認してください。
sysctl vm.swappiness
swapon --showsysctl vm.swappiness は vm.swappiness = 100 と表示され、swapon --show は swapfile を一覧表示するはずです。swappiness が 0 と表示される場合、すべてのフリーズ処理は何もせず、アイドル状態の各サンドボックスに必要なメモリを全量使い続けます。
Ubuntu に Dormice をインストールする
公式に記載されているインストール方法は、bash へ 1 本のパイプで渡す方法です。
curl -fsSL https://raw.githubusercontent.com/BitMiracle-AI/Dormice/main/deploy/install.sh | bash実行する前に取得して内容を確認してください。このスクリプトは root として実行され、ホストの構成を変更します。Docker がなければインストールし、チェックサム検証付きで 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 トークンがローテーションされることはありません。
コードは /opt/dormice、設定は /etc/dormice/env、サンドボックスデータは /var/lib/dormice に配置されます。dormice と dor のコマンドは /usr/local/bin に配置されます。インストーラーはインストール中に API トークンを生成し、モード 600 で /etc/dormice/env に書き込みます。
インストール対象にできるタグ付きリリースはありません。2026 年 8 月 4 日時点で、リポジトリには git tag も GitHub release もありません。そのため、インストーラーは main を clone し、その日の朝に追加されたコードがインストールされます。したがって、バージョンを固定するには、実際にインストールした commit を記録する必要があります。
git -C /opt/dormice rev-parse HEADその hash をデプロイメモに保存してください。アップグレードで問題が発生した場合、その commit が唯一の復旧手段になります。指定できるバージョン番号がないためです。
インストーラーは最後に dor doctor を実行します。これは読み取り専用のホストチェックであり、実際の gVisor コンテナを起動してランタイムが動作することを確認します。パッケージ一覧だけを信頼するチェックではありません。daemon の動作に問題がある場合は、再度実行してください。
sudo dor doctor
systemctl is-active dormicesystemctl is-active dormice は active を出力するはずです。failed が出力された場合、原因は journalctl -u dormice -n 50 に記録されています。起動失敗の原因は、通常 daemon 自体ではなく、swap または gVisor の前提条件です。
インストーラーはホストに Caddy も配置します。そのため、ファイアウォールの設定が完了したと判断する前に、待ち受け中のポートを確認してください。
sudo ss -lntpdaemon は 127.0.0.1:3676 に bind し、この設定を変更する項目はありません。これは意図された設計です。ノート PC から接続するには明示的な操作が必要で、手軽な方法は SSH トンネルです。
ssh -L 3676:127.0.0.1:3676 root@your-serverトンネルを開くと、ノート PC 上の http://127.0.0.1:3676/console が Web コンソールになります。トークンで 1 回サインインすると、httpOnly のセッション cookie が発行されます。そのため、トークン自体がページから読み取れる場所に保存されることはありません。そこにある Connect ページには、自分のエンドポイントを指定済みのクライアント用スニペットが表示され、コピーして貼り付けて使えます。
サンドボックスを作成してコードを実行する
サンドボックスを作成する操作は acquire です。これは冪等性があるため、同じキーを指定すると常に同じサンドボックスが返されます。必要に応じて、サンドボックスの作成、休止状態からの復帰、起動、復元が行われます。それ以外の動詞は、これまでに認識したことのないキーに対して 404 を返します。dor CLI には acquire 動詞がないため、最初のサンドボックスはコンソールまたはクライアントライブラリから作成します。
コンソールを使う方法が最も簡単です。トンネル経由で /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 があらかじめインストールされているためです。認証エラーが表示される場合は、コピーしたトークンの行に変数名まで含まれている可能性があります。
ファイルの転送には dor sandbox push my-agent ./script.py を使用します。ファイルは /home/user/script.py に保存され、dor sandbox pull my-agent notes.txt で取り出せます。ネイティブのファイル操作では 1 ファイルあたり 16 MiB に制限されます。一方、E2B のファイル操作はストリーミングに対応しているため、制限はサンドボックスのディスククォータだけです。
データを失うのは destroy 操作だけです。これはプロジェクトの経過年数を示す例でもあります。メインの README と同梱された agent skill では dor sandbox destroy <key> と記載されていますが、CLI パッケージの README では dor sandbox release <key> と記載されています。自分のビルドで dor sandbox --help を実行し、その結果を正しい情報として扱ってください。
既存の E2B コードを自分のサーバーに向ける
これが導入する理由です。npm の公式 e2b パッケージは変更せずに使用でき、Dormice と通信します。SSH トンネルを開いた状態で、ノート PC から次を実行してください。サーバー上で新たに待ち受けるサービスはありません。
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正常に実行されると、終了コード 0 と 42 が出力されます。API key には Dormice token の先頭に e2b_ prefix を付けます。これは互換レイヤーが想定する形式です。
この互換性はスタブではありません。ストリーミング形式の stdout と stderr、バックグラウンドコマンド、対話型 PTY、署名付きの upload URL と download URL、ディレクトリ監視、port proxy はすべて、プロジェクトの end-to-end suite によって、公式パッケージ経由で実際の Docker および gVisor daemon に対して検証されています。実際の移行を始める前に、次の差異を確認してください。
- Template build は実装されていません。template は自分で build して
dor template addに登録する docker image であり、Sandbox.create('name')がその image を解決します。未登録の名前に対しては、見つかったように扱わず 404 を返します。 - E2B surface 経由で作成した sandbox には、E2B の semantics で必要とされるため、実際の deadline が設定されます。native API 経由で作成した sandbox に deadline が設定されることはありません。
- freeze した sandbox はプロセスを保持し、処理の途中から再開します。そのため、ここでの pause と resume は、一般的な stop と cold start とは異なります。
サンドボックスが防ぐものと、防がないもの
gVisor はコンテナのシステムコールをユーザー空間で横取りして、自身で処理します。そのため、サンドボックス内のコードがホストのカーネルと直接通信することはありません。サンドボックス内では、すべてが非特権ユーザーの uid 1000 として実行されます。この組み合わせにより、通常のケースには対応できます。生成されたスクリプトが rm -rf / を実行したり、ディスクを満杯にしたり、何かが停止するまで fork を繰り返したりしても、影響は自身のサンドボックス内にとどまり、そこで停止します。
一方、防げないものもあります。以下はすべて、利用者側で対処する必要があります。
- サンドボックスでは外向きのネットワーク通信が利用できます。生成されたコードは任意のデータをダウンロードし、取得した情報を任意の宛先へ送信できます。インストーラーのネットワーク強化策が対象とするのは、次の2点だけです。まず、コンテナからクラウドのメタデータサービス 169.254.0.0/16 への通信を遮断します。このサービスは、到達可能な対象へクラウドがインスタンス認証情報を渡す場所です。次に、Docker の
daemon.jsonで"icc": falseを使用し、コンテナ間通信を無効にします。それ以外は何も遮断されません。sudo iptables -S DOCKER-USERを読み、サンドボックスから到達させるべきでないプライベート範囲に対する独自の DROP ルールを追加してください。 - Docker はファイアウォールより前に独自のルールを挿入します。そのため、ufw がポートを閉じていると示していても、公開したコンテナポートがインターネットから応答する場合があります。このホストで何かを公開する前に、Docker が ufw を越えてポートを公開する仕組み と VPS 向け ufw ファイアウォールの基本 を読んでください。
- gVisor はハイパーバイザーではなく、ユーザー空間のカーネルです。これは意図的なトレードオフです。フリーズ機能にはサンドボックスをプロセスとして実行する必要があり、KVM を必須にすると、どこにでもインストールできなくなるためです。脅威モデルでハードウェア仮想化が必要な場合は、Firecracker クラスの分離を使用し、それに伴う運用コストを受け入れてください。
- API トークンが、クライアント側におけるセキュリティ境界のすべてです。
DORMICE_API_TOKENを保持するものは、マシン上のすべてのサンドボックスを作成、読み取り、破棄できます。エージェントプロセスには専用の VPS 上の最小権限ユーザーを割り当て、トークンは SSH key と同じように扱ってください。VPS 上で Claude Code を安全に実行する方法の運用習慣をそのまま適用できます。
デーモン自体は、ホスト上で root として実行されます。gVisor はサンドボックス内のコードからホストを保護しますが、デーモンやそのトークンを保持する者からホストを保護するものはありません。そのため、Dormice を実行するマシンは、Dormice 専用にしてください。エージェントが MCP(model context protocol)経由でもツールにアクセスする場合は、同じ理由から、MCP サーバーを別の VPS に配置してください。
4 GB と 8 GB にはいくつのサンドボックスを収容できますか?
メモリを消費するのは、ホスト自体のベースライン使用量と、現在起動している各サンドボックスのワーキングセットです。Ubuntu、Docker、デーモン用に約 1 GB を確保し、残りをサンドボックス 1 個が実際に使用する容量で割ります。数個のファイルを読み取る Python スクリプトを実行するサンドボックスは、約 200~300 MiB です。コンパイラや完全なテストスイートを実行するサンドボックスでは、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
}
]各サンドボックスが 512 MiB を使用する場合、4 GB の VPS では約 6 個を同時に起動できます。各サンドボックスが 1 gibibyte をすべて使用する場合は 3 個です。8 GB の VPS では、それぞれ 14 個と 7 個になります。これらは同時実行できる作業量の上限であり、ベンチマークの結果ではなく算術上の値です。そのため、実際の負荷を実行しながら free -m を監視してください。
凍結状態のサンドボックスは RAM ではなく swap によって制限されます。これがこの設計の目的です。1 gibibyte を保持していた凍結状態のサンドボックスは、swap にほぼ同じ容量を保持し、RAM 上にはほとんど常駐しません。そのため、インストーラーのデフォルトである 16 GB の swapfile には、約 16 個を退避できます。それを超えると停止状態へ移行する必要があり、その状態ではディスク容量だけを消費します。ここで長期的な本当の制限になるのはディスクです。各サンドボックスはファイルシステムを保持するため、node_modules ディレクトリを持つエージェントが数十個あると、メモリが問題になるよりはるか前に小容量のボリュームが一杯になります。
停止・凍結・アーカイブ:ライフサイクル設定
デフォルトでは、10 分間アイドル状態が続くと凍結し、3 日後に停止し、アーカイブを設定している場合は 7 日後にアーカイブします。stopAfterSeconds を null に設定すると、常駐エージェントとして動作します。アイドル時に凍結することはありますが、コールドスタートは発生しません。
アーカイブは任意であり、daemon はその状態を正確に扱います。4 つの DORMICE_S3_* 変数を設定すると、停止した sandbox のディスクが tar と zstd でパックされ、S3 互換バケットに転送された後、ローカルから解放されます。そのバケットには、別のマシンで自分がホストする MinIO バケットも使用できます。変数を設定しない場合、sandbox は停止状態のまま保持されます。アーカイブを要求するポリシーは、無視されずに拒否されます。復元の進行状況も明示されます。次回の acquire は restoring 状態と進捗値を直ちに返し、ディスクが復元されると ready に切り替わります。
まだ依存してよい段階ですか?
率直に言うと、再構築できない用途ではまだ使うべきではありません。リポジトリの最初のコミットは 8 July 2026 です。4 August 2026 時点で、446 stars、37 forks、Apache-2.0 ライセンスで、タグ付きのリリースはありません。README 自身のステータス欄にも、本番環境で利用できる状態ではないと記載されています。
この組み合わせには、特有のリスクがあります。インストーラーが main を追跡するため、コードの内容が予告なく変わります。インターフェースもまだ固まっていません。同じリポジトリ内の 2 つのファイルで、delete 操作の名前が異なるのはそのためです。また、開始から 4 週間のプロジェクトは、単純に開発が止まる可能性があります。開発を継続する義務を誰かに課すライセンス条項もないためです。
このリスクを許容しやすくするのが、E2B 互換性です。アプリケーションは、その背後にホスト型の実装があるプロトコルと通信します。そのため、Dormice の開発が停滞しても、2 つの URL を変更すれば運用を継続できます。エージェントはネイティブ API ではなく E2B のインターフェースに対して実装してください。そうすれば、この移行経路を維持できます。ネイティブの @dormice/sdk パッケージは npm にもまだ公開されていません。利用するにはリポジトリからビルドする必要があるため、最初は互換性のある経路を使うもう 1 つの理由になります。
失っても問題ない環境で実行してください。スクリプトからホストを再構築できるようにし、トークンをすべてのプロンプトとコミットから除外してください。保持する価値のあるデータは、独自に定めたバックアップスケジュールでサンドボックスの外へ取り出してください。
FAQ
Dormice は本番環境で利用できる状態ですか?
いいえ。プロジェクト自身もそのように説明しています。README のステータス行には、現時点では本番利用できるものはないと記載されています。2026 年 8 月 4 日時点で、リポジトリは作成から約 4 週間で、git tag も release もありません。そのため、固定すべきバージョン番号がありません。インストーラーは main ブランチを clone するため、実行するたびに最新の commit が取得されます。インストールのたびに git -C /opt/dormice rev-parse HEAD を記録し、重要なデータは sandbox の外部に保管してください。
エージェントに使い捨ての VM を与える場合と、Dormice はどう違いますか?
使い捨ての VM は、セッション用に作成し、終了後に削除する SSH 接続可能なマシンです。Dormice は実行 API です。プログラムが acquire を呼び出し、続いて exec を呼び出すと、途中に shell session を挟まずに stdout と終了コードを取得できます。VM は、人間や一定時間にわたってコンピューター全体を使いたいエージェントに適しています。Dormice は、毎日何度も生成コードを実行し、実行のたびにマシン単位のセットアップと破棄を行いたくないアプリケーションに適しています。
公式の E2B SDK は本当にコードを変更せずに動作しますか?
はい。設定の変更は必要です。apiUrl と sandboxUrl を daemon 上の /e2b/api と /e2b/envd に設定し、Dormice token には e2b_ prefix を付けて API key として渡します。コマンド実行、PTY session、ファイル転送、署名付き URL、port proxy はすべて、公式 package を経由して実行するプロジェクトの end-to-end suite でカバーされています。template の構築には明確な制限があります。e2b template build は実装されていないため、template は自分で build し、dor template add で登録する docker image になります。
4 GB の VPS では、いくつの sandbox を実行できますか?
各 sandbox が 512 MiB を使用する場合、同時に起動状態にできる数は約 6 です。各 sandbox が 1 gibibyte 全体を使用する場合は 3 です。これは、オペレーティングシステム、Docker、daemon 用に約 1 GB を確保した後の値です。停止状態の sandbox は swap によって制限されます。そのため、インストーラーのデフォルトである 16 GB の swapfile では、1 つあたり 1 gibibyte を使用していた sandbox を約 16 個退避できます。実際の負荷をかけた状態で free -m を使用し、自分の環境で測定してください。test suite を実行する sandbox は、小さな script を実行する sandbox の数倍のリソースを使用するためです。
Dormice で vm.swappiness を 100 に設定する必要があるのはなぜですか?
sandbox を停止状態にするとは、アイドル状態のメモリを swap に移動することです。gVisor は sandbox のメモリを shared memory として保持します。Linux kernel は、デフォルトの swappiness では shared memory を swap に移動しません。そのため、デフォルト値では freeze してもメモリを回収できず、sandbox は通常どおり全メモリを消費し続けます。プロジェクトの測定では、デフォルト値で回収できたメモリは 0 bytes でしたが、100 では 99.5 percent を回収できました。設定ファイルを読むのではなく、sysctl vm.swappiness で有効な値を確認してください。一部の cloud image では値が 0 に設定されているためです。