How to Self-Host Dormice Agent Sandboxes on VPS
Learn how Dormice runs E2B-compatible agent sandboxes on your Linux VPS, plus install steps, code execution, isolation checks, and host sizing.
Wetin Dormice be, and wetin e no be
Dormice na self-hosted agent sandbox: na one daemon for Linux VPS wey you own, and your agent code dey call am over HTTP to run untrusted code inside isolated container. Your program go ask for sandbox by name, get the same sandbox back no matter the state wey e dey, run command inside am, then read the output. The sandbox na programmatic resource, no be machine wey you go log into.
This one different from giving agent whole computer. A throwaway VM for coding agent na box wey you go SSH into, allow agent spoil am, then delete am. Dormice dey one level down: na execution API wey your program dey call when e already get code and need safe place to run am. Use throwaway VM when whole machine na the unit of work. Use Dormice when one exec call na the unit of work, and you want run hundred of dem every day without hundred VMs.
The project call itself E2B compatible. E2B na hosted sandbox service wey client library for plenty agent frameworks already dey import. Dormice dey serve the same protocol under its own URL prefixes, so application wey dem write against official e2b package go continue run when you point am to your own box. Application code no change. Na two URLs and one API key prefix go change.
Wetin “the SQLite of agent sandboxes” mean for real
SQLite na database wey you embed instead of service wey you dey operate, and Dormice borrow that comparison directly. One daemon, one SQLite file for the ledger, one TCP port. No Kubernetes, no separate database, no scheduler. The daemon take lock beside its ledger and no go start when the ledger and the machine wey e find no fit belong together, so split brain no fit happen quietly. One machine na the design. If you need fleet across many hosts, the README tell you plainly make you pick another thing, and you suppose listen.
The second part of the idea concern cost. Hosted sandbox dey charge for every second wey e exist, so hosted sandboxes dey disposable by design. Dormice dey run for hardware wey you already dey pay for, so its sandboxes permanent and dem dey cheaper the longer dem remain still. Sandbox dey cool down one rung at a time: active, then frozen, then stopped, then archived. Any acquire go bring am back from whichever rung e reach.
Freezing na the part wey worth understanding, because na wetin make keeping every agent's sandbox forever affordable. These figures na the project own published figures, measured for its hardware and no be for your own.
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
}
]Idle sandbox wey dey hold 1024 MiB memory drop to 5 MiB resident memory once e freeze, and e come back for about 50 ms. Processes suspend and resume for the same place, so long-lived agent keep its shell state and its half-finished work across the freeze. Reproduce am for your own host before you plan capacity around am.
Things wey host need before you install
Host na Ubuntu or Debian for x86_64, and installer need root. Daemon dey keep root while e dey run because e dey do loop mounts and write cgroups.
Sandboxes dey run under Docker with gVisor (na container runtime wey put userspace kernel between container and host kernel). E dey provide the runsc runtime wey every sandbox dey use. Node 22 or newer dey run the daemon, and installer bring its own copy, so your system Node remain untouched.
Swap must dey available, and vm.swappiness must be 100. This no be tuning advice; na functional requirement. Freezing dey work by pushing idle sandbox memory go swap. gVisor dey hold sandbox memory as shared memory, and kernel no go swap shared memory when default swappiness dey active. Project measure 0 bytes reclaimed for the default value and 99.5 percent reclaimed at 100. Check the value wey kernel dey really use, because some cloud images dey put vm.swappiness = 0 for file wey you no go ever think to read.
sysctl vm.swappiness
swapon --showsysctl vm.swappiness suppose print vm.swappiness = 100, and swapon --show suppose list one swapfile. If swappiness print 0, every freeze na no-op wey go leave you dey pay full memory for every idle sandbox.
Install Dormice for Ubuntu
The documented install na one pipe go bash:
curl -fsSL https://raw.githubusercontent.com/BitMiracle-AI/Dormice/main/deploy/install.sh | bashFetch am read am before you run am. This script dey run as root and e dey rearrange your host: e installs Docker if e no dey, downloads gVisor and Caddy with checksum verification, creates swapfile, writes systemd units, and adds firewall rules.
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 dey set swapfile size and e default to 16, wey mean plenty disk space for small VPS. --mirror cn switches the downloads go mirrors wey mainland China fit reach. If you run the installer again, e upgrades the code and repairs drift, but e no ever rotate your API token.
Code dey for /opt/dormice, configuration dey for /etc/dormice/env, sandbox data dey for /var/lib/dormice, while the dormice and dor commands dey for /usr/local/bin. The installer generates the API token during install and writes am to /etc/dormice/env with mode 600.
No tagged release dey wey you fit install against. As of 4 August 2026, the repository no get git tags and no GitHub releases, so the installer clones main and you go get anything wey enter that morning. So, to pin a version, write down the commit wey you actually install.
git -C /opt/dormice rev-parse HEADSave that hash with your deploy notes. If upgrade spoil something, na that commit be your only way back, because no version number dey wey you fit request.
The installer ends by running dor doctor. Na read-only host check be this; e boots real gVisor containers to prove say the runtime dey work instead of trusting package list. Run am again any time the daemon dey misbehave.
sudo dor doctor
systemctl is-active dormicesystemctl is-active dormice suppose print active. If e print failed, journalctl -u dormice -n 50 get the reason, and failed start usually come from swap or gVisor prerequisite, no be the daemon itself.
The installer still puts Caddy for the box, so check wetin dey listen before you decide say the firewall work don finish.
sudo ss -lntpThe daemon binds 127.0.0.1:3676 and e no get setting to change that, by design. To reach am from your laptop na deliberate action, and the cheap option na SSH tunnel.
ssh -L 3676:127.0.0.1:3676 root@your-serverWhen the tunnel open, http://127.0.0.1:3676/console for your laptop na the web console. Sign in with the token once, and e go become an httpOnly session cookie, so the page no fit read or store the token itself. The Connect page there prints client snippets wey you fit copy and paste, and dem don already point to your own endpoint.
Create sandbox and execute code inside am
One operation dey create sandbox: acquire. E dey idempotent, so the same key always return the same sandbox. E go create am, wake am, start am, or restore am as needed. Every other verb go answer 404 for key wey e never see before. The dor CLI no get acquire verb, so your first sandbox go come from the console or client library.
The console route na the fastest. Open /console through the tunnel and create sandbox wey dem name my-agent. The CLI go then work on am.
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 dey list each sandbox with im lifecycle state. Na so you fit monitor one as e move from active go frozen. dor sandbox exec dey print Python 3.12 version, because the stock image na Ubuntu 24.04 with Python 3.12, Node 24, git, and ripgrep already installed. If authentication error show instead, e mean say the token line wey you copy include the variable name.
Files dey move with dor sandbox push my-agent ./script.py, and e go land for /home/user/script.py. dor sandbox pull my-agent notes.txt go bring one file back. The native file verbs get 16 MiB limit for each file, but the E2B file surface dey stream files and allow sandbox disk quota to be the only limit.
Destroying na the only verb wey dey lose data. E also show the project age well: the main README and the bundled agent skill both document dor sandbox destroy <key>, while the CLI package README document dor sandbox release <key>. Run dor sandbox --help for your own build and trust that result instead.
Point your existing E2B code go your own box
Na this reason to care. The official e2b package from npm, as e be, dey talk to Dormice. Run this from your laptop while the SSH tunnel dey open, so nothing new go listen on the server.
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.tsA healthy run dey print exit code 0 and 42. The API key na your Dormice token with an e2b_ prefix for front, because na this format the compatibility layer expect.
The compatibility no be stub. The project end-to-end suite dey test streaming stdout and stderr, background commands, interactive PTY, signed upload and download URLs, directory watching, and port proxy through the official package against real Docker and gVisor daemon. Before you migrate any real workload, note these few differences:
- Template builds no dey implemented. Template na docker image wey you build by yourself and register with
dor template add, thenSandbox.create('name')go resolve am. If you use name wey no dey registered, e go return 404 instead of pretending. - Sandboxes wey you create through the E2B surface get real deadlines, because E2B semantics require am. Sandboxes wey you create through the native API no dey get deadline.
- Frozen sandbox keep its processes and resume dem from where dem stop, so pause and resume for here no be the stop and cold start wey you fit don dey used to.
Wetin sandbox dey stop, and wetin e no dey stop
gVisor dey intercept system calls from the container for userspace and service dem by itself, so code wey sandbox dey run no dey talk directly to your host kernel. Inside the sandbox, everything dey run as unprivileged user, uid 1000. This combination dey handle normal case: generated script wey run rm -rf /, fill disk, or fork until something die go damage na im own sandbox and stop there.
Na wetin e no dey stop be this. Na you get responsibility for each one.
- Sandbox get working outbound network. Generated code fit download anything e like and post anything e find. Installer network hardening cover two specific things: e drop container traffic to cloud metadata service for 169.254.0.0/16, wey be where cloud dey give instance credentials to anything wey fit reach am, and e turn off container-to-container traffic with
"icc": falsefor Dockerdaemon.json. Nothing else dey blocked. Readsudo iptables -S DOCKER-USERand add your own DROP rules for private ranges wey sandbox no get business to reach. - Docker dey insert im own rules before your firewall, so published container port fit answer from internet while ufw dey insist say e close. Read how Docker dey publish ports past ufw and the ufw firewall basics for VPS before you expose anything for this host.
- gVisor na userspace kernel, no be hypervisor. Na deliberate trade-off be that, because freezing require sandboxes to be processes, and requirement for KVM go stop the thing from installing anywhere. If your threat model require hardware virtualisation, use Firecracker-class isolation and accept the operational cost wey come with am.
- API token na the complete security boundary for client side. Anything wey hold
DORMICE_API_TOKENfit create, read, and destroy every sandbox for the machine. Give agent process im own least privilege user for VPS and treat the token the same way you dey treat SSH key. The habits from running Claude Code safely for VPS apply directly.
The daemon itself dey run as root for your host. gVisor dey protect host from code inside sandbox, and nothing dey protect host from daemon or from anybody wey hold im token. So machine wey dey run Dormice suppose be machine wey dey do only that. If your agent also dey reach tools through MCP (model context protocol), keep those MCP servers for separate VPS for the same reason.
Sandbox wey 4 GB and 8 GB fit hold?
Two things dey use memory: host baseline by itself, and working set of every sandbox wey dey awake. Keep about 1 GB for Ubuntu, Docker and daemon, then divide wetin remain by wetin one of your sandboxes really dey use. Sandbox wey dey run Python script wey dey read small number of files fit dey around 200 to 300 MiB. One wey dey run compiler or complete test suite fit pass one 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
}
]4 GB VPS fit keep about 6 sandboxes awake at once if each one dey use 512 MiB, or 3 if each one dey use complete gibibyte. 8 GB VPS increase am to 14 and 7. These na limits for concurrent work, and na calculation dem be, no be benchmark, so monitor free -m while your own load dey run.
Swap dey limit frozen sandboxes instead of RAM, and na the main reason for this design. Frozen sandbox wey dey hold one gibibyte go keep roughly that amount for swap and almost nothing for resident memory, so installer's default 16 GB swapfile fit park about 16 of dem. After that, dem need reach stopped rung, where na disk only dem dey cost. Disk na the real long-term limit here: every sandbox dey keep its filesystem, and few dozen agents wey each carry node_modules directory go fill small volume long before memory become important.
Freeze, stop, archive: lifecycle settings
Default setting na freeze after 10 minutes wey nobody use am, stop after 3 days, and archive after 7 days when archiving don configure. If you set stopAfterSeconds to null, you get resident agent: e fit freeze when idle, but e no go ever do cold start.
Archiving optional, and daemon no dey hide am. Set the four DORMICE_S3_* variables, and the stopped sandbox disk go pack with tar and zstd, send am go any S3-compatible bucket, then free the local disk. That bucket fit be MinIO bucket wey you host by yourself for another machine wey belong to you. If you leave the variables unset, sandboxes go remain stopped forever, and policy wey request archive go reject am instead of quietly ignoring am. Restore status dey visible, no be silent: the next acquire go answer immediately with restoring status and progress value, then e go change to ready when the disk don return.
You suppose depend on am yet?
Straight answer: no be for anything wey you no fit rebuild. The first commit for the repository get date 8 July 2026. As of 4 August 2026, e get 446 stars, 37 forks, Apache-2.0 licence, and no tagged release at all. The README status line itself talk say nothing there ready for production.
This combination get one particular kind risk. The code dey change under you because the installer dey track main. The interface still dey settle. Na exactly why the delete verb get two different names for two files inside the same repository. And project wey only four weeks old fit simply stop, because no licence clause force anybody to continue.
The E2B compatibility na wetin make the risk manageable. Your application dey talk to protocol wey get hosted implementation behind am. So if Dormice stop work, you change two URLs and continue. Write your agent against the E2B surface instead of the native API, and you keep that exit option. The native @dormice/sdk package never reach npm yet too. To use am, you need build am from the repository. This na another reason to start with the compatible path.
Run am where you fit afford lose am. Rebuild the host from a script. Keep the token out of every prompt and every commit. Pull anything wey worth keeping out of the sandboxes according to your own backup schedule.
FAQ
Dormice ready for production?
No, and project sef talk am clearly. The status line for README talk say nothing for there ready for production yet. As of 4 August 2026, repository don old about four weeks, e get no git tags and no releases, so no version number dey wey you fit pin. Installer clones main branch, so every run go give you the newest commit. Record git -C /opt/dormice rev-parse HEAD after every install, and keep anything valuable outside the sandboxes.
How Dormice different from giving my agent disposable VM?
Disposable VM na machine wey get SSH. You create am for one session, then delete am afterwards. Dormice na execution API: your program calls acquire, then exec, and e gets stdout plus exit code back. No shell session dey for middle. VM fit human or agent wey want use whole computer for some time. Dormice fit application wey dey run generated code many times every day and no want carry machine-level setup and teardown for every run.
Official E2B SDK really dey work without code changes?
Yes, but you need configuration changes. Point apiUrl and sandboxUrl to /e2b/api and /e2b/envd for your daemon, then pass your Dormice token with e2b_ prefix as the API key. Command execution, PTY sessions, file transfer, signed URLs and port proxy all dey covered by the project's end-to-end suite through the official package. Template building na the main gap: e2b template build never implemented, so template na docker image wey you build and register with dor template add.
How many sandboxes fit run for 4 GB VPS?
About 6 fit dey awake at the same time if each sandbox uses 512 MiB. If each one uses full gibibyte, na about 3. This calculation reserve roughly 1 GB for operating system, Docker and daemon. Frozen sandboxes depend on swap instead. Installer default 16 GB swapfile fit hold around 16 sandboxes wey each hold one gibibyte. Measure your own with free -m under real load, because sandbox wey dey run test suite fit use several times the memory wey sandbox wey dey run small script use.
Why Dormice need vm.swappiness set to 100?
To freeze sandbox mean say system go push the sandbox idle memory go swap. gVisor dey hold sandbox memory as shared memory. Linux kernel no go swap shared memory when swappiness dey the default value. So for default value, freeze no go reclaim anything, and sandbox go continue to use full memory. Project measure 0 bytes reclaimed at default value and 99.5 percent reclaimed at 100. Check the effective value with sysctl vm.swappiness instead of reading config files, because some cloud images dey ship with value of 0.