SSD Nodes Learn 🎉 VPS dès $5.50/mois
Guides Matt ConnorPar Matt Connor

Auto-héberger Dormice pour les sandbox d’agents

Installez Dormice sur un VPS Linux, exécutez du code non fiable dans un sandbox compatible E2B, vérifiez l’isolation et dimensionnez votre hôte.

Ce qu’est Dormice et ce qu’il n’est pas

Dormice est un agent sandbox auto-hébergé : un daemon sur un VPS Linux dont vous êtes propriétaire. Votre code d’agent l’appelle via HTTP pour exécuter du code non fiable dans un conteneur isolé. Votre programme demande un sandbox par son nom, récupère le même sandbox quel que soit son état, y exécute une commande, puis lit la sortie. Le sandbox est une ressource gérée par programme, pas une machine à laquelle vous vous connectez.

Cette approche est différente du fait de donner un ordinateur complet à un agent. Une VM éphémère pour un agent de codage est une machine à laquelle vous vous connectez en SSH, que vous laissez l’agent détériorer, puis que vous supprimez. Dormice se situe un niveau en dessous : c’est l’API d’exécution appelée par votre programme lorsqu’il dispose déjà du code et a besoin d’un environnement sûr pour l’exécuter. Utilisez la VM éphémère lorsqu’une machine complète constitue l’unité de travail. Utilisez Dormice lorsqu’un seul appel exec constitue l’unité de travail et que vous voulez en effectuer cent par jour sans déployer cent VM.

Le projet se présente comme compatible avec E2B. E2B est un service de sandbox hébergé dont la bibliothèque cliente est déjà importée par de nombreux frameworks d’agents. Dormice expose le même protocole sous ses propres préfixes d’URL. Une application écrite avec le package e2b officiel continue donc de fonctionner lorsque vous la dirigez vers votre propre serveur. Le code de l’application ne change pas. Seuls deux URL et un préfixe de clé API changent.

Ce que signifie en pratique « le SQLite des agent sandboxes »

SQLite est une base de données que vous intégrez à votre application, au lieu d’exploiter un service séparé. Dormice reprend directement cette comparaison. Un daemon, un fichier SQLite pour le ledger et un port TCP. Pas de Kubernetes, pas de base de données séparée, pas de scheduler. Le daemon verrouille le fichier à côté de son ledger et refuse de démarrer lorsque le ledger et la machine détectée ne peuvent pas appartenir au même ensemble. Un split brain ne peut donc pas se produire silencieusement. La conception cible une seule machine. Si vous avez besoin d’un fleet réparti sur plusieurs hôtes, le README vous recommande clairement de choisir une autre solution. Vous devez en tenir compte.

La seconde partie concerne les coûts. Un sandbox hébergé est facturé pour chaque seconde d’existence. Les hosted sandboxes sont donc conçus pour être jetables. Dormice s’exécute sur du matériel que vous payez déjà. Ses sandboxes sont donc permanents et coûtent moins cher plus ils restent inactifs. Un sandbox descend d’un état au suivant : actif, puis frozen, puis stopped, puis archived. Chaque acquire le fait remonter depuis l’état atteint.

Le freezing est le point important à comprendre. C’est lui qui rend abordable la conservation permanente du sandbox de chaque agent. Ces chiffres sont publiés par le projet. Ils ont été mesurés sur son matériel, pas sur le vôtre.

ChartOne idle sandbox before and after freezing, figures published by the project
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
  }
]

Un sandbox idle qui utilise 1024 MiB de mémoire tombe à 5 MiB de mémoire resident une fois frozen, puis revient à l’état actif en environ 50 ms. Les processus sont suspendus puis repris sur place. Un agent long-lived conserve donc l’état de son shell et son travail en cours pendant le freeze. Reproduisez ce comportement sur votre propre hôte avant de dimensionner votre capacité en fonction de ces chiffres.

Prérequis de l’hôte avant l’installation

L’hôte doit exécuter Ubuntu ou Debian sur x86_64, et l’installateur nécessite les privilèges root. Le daemon conserve ces privilèges à l’exécution, car il effectue des loop mounts et écrit dans les cgroups.

Les sandbox s’exécutent dans Docker avec gVisor, un container runtime qui place un kernel en espace utilisateur entre le conteneur et le kernel de l’hôte. gVisor fournit le runtime runsc utilisé par chaque sandbox. Le daemon fonctionne avec Node 22 ou une version ultérieure. L’installateur fournit sa propre copie, donc la version de Node installée sur le système reste inchangée.

Un swap doit être disponible et vm.swappiness doit avoir la valeur 100. Il ne s’agit pas d’un conseil d’optimisation, mais d’une exigence fonctionnelle. Le gel fonctionne en déplaçant la mémoire d’une sandbox inactive vers le swap. gVisor conserve la mémoire des sandbox sous forme de mémoire partagée, et le kernel n’échange pas la mémoire partagée avec la valeur par défaut de swappiness. Le projet a mesuré 0 octet récupéré avec la valeur par défaut, contre 99.5 pour cent avec la valeur 100. Vérifiez la valeur réellement utilisée par le kernel, car certaines images cloud fournissent vm.swappiness = 0 dans un fichier que vous ne penserez jamais à consulter.

sysctl vm.swappiness
swapon --show

sysctl vm.swappiness doit afficher vm.swappiness = 100, et swapon --show doit lister un swapfile. Si swappiness affiche 0, chaque gel est sans effet et vous continuez à utiliser toute la mémoire nécessaire pour chaque sandbox inactive.

Installer Dormice sur Ubuntu

L’installation documentée consiste à envoyer un pipe vers bash :

curl -fsSL https://raw.githubusercontent.com/BitMiracle-AI/Dormice/main/deploy/install.sh | bash

Récupérez ce script et lisez-le avant de l’exécuter. Il s’exécute en tant que root et modifie votre hôte : il installe Docker s’il est absent, télécharge gVisor et Caddy avec vérification des sommes de contrôle, crée un fichier swap, écrit des unités systemd et ajoute des règles de pare-feu.

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 définit la taille du fichier swap et utilise par défaut la valeur 16, ce qui représente beaucoup d’espace disque sur un petit VPS. --mirror cn redirige les téléchargements vers des miroirs accessibles depuis la Chine continentale. Réexécuter l’installateur met le code à niveau et corrige les divergences de configuration. Il ne renouvelle jamais votre API token.

Le code est installé dans /opt/dormice, la configuration dans /etc/dormice/env, les données de la sandbox dans /var/lib/dormice, et les commandes dormice et dor dans /usr/local/bin. L’installateur génère l’API token pendant l’installation et l’écrit dans /etc/dormice/env avec le mode 600.

Aucune version marquée n’est disponible pour l’installation. Au 4 août 2026, le dépôt ne contient aucun tag git ni aucune release GitHub. L’installateur clone donc main, et vous obtenez ce qui a été ajouté ce matin-là. Pour figer une version, vous devez donc noter le commit réellement installé.

git -C /opt/dormice rev-parse HEAD

Conservez ce hash avec vos notes de déploiement. Si une mise à niveau casse quelque chose, ce commit est votre seul moyen de revenir en arrière, car aucun numéro de version n’est disponible.

L’installateur termine en exécutant dor doctor. Il s’agit d’un contrôle de l’hôte en lecture seule qui démarre de vrais conteneurs gVisor pour vérifier que le runtime fonctionne, au lieu de se fier à une liste de paquets. Exécutez-le de nouveau chaque fois que le daemon se comporte de manière anormale.

sudo dor doctor
systemctl is-active dormice

systemctl is-active dormice doit afficher active. S’il affiche failed, journalctl -u dormice -n 50 contient la cause. Un démarrage en échec est généralement lié à la prérequis swap ou gVisor, et non au daemon lui-même.

L’installateur installe également Caddy sur la machine. Vérifiez donc les ports en écoute avant de considérer la configuration du pare-feu comme terminée.

sudo ss -lntp

Le daemon écoute sur 127.0.0.1:3676 et aucun paramètre ne permet de modifier ce comportement, volontairement. Y accéder depuis votre ordinateur portable est une action explicite. La solution la plus simple consiste à utiliser un tunnel SSH.

ssh -L 3676:127.0.0.1:3676 root@your-server

Une fois le tunnel ouvert, http://127.0.0.1:3676/console sur votre ordinateur portable correspond à la console web. Connectez-vous une fois avec le token. Celui-ci devient alors un cookie de session httpOnly, et le token lui-même n’est jamais stocké à un emplacement lisible par la page. La page Connect affiche des extraits client prêts à être copiés-collés, déjà configurés pour pointer vers votre propre endpoint.

Créer un sandbox et y exécuter du code

Une opération crée un sandbox : acquire. Elle est idempotente : la même clé renvoie toujours le même sandbox, en le créant, en le réveillant, en le démarrant ou en le restaurant si nécessaire. Tous les autres verbes renvoient 404 pour une clé jamais utilisée. Le CLI dor ne possède pas de verbe acquire. Votre premier sandbox doit donc être créé depuis la console ou avec une bibliothèque cliente.

La console est la méthode la plus rapide. Ouvrez /console via le tunnel et créez un sandbox nommé my-agent. Le CLI peut ensuite l'utiliser.

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 liste chaque sandbox avec son état de cycle de vie. Vous pouvez ainsi surveiller le passage de l'état actif à l'état gelé. dor sandbox exec affiche une version de Python 3.12, car l'image standard est Ubuntu 24.04 avec Python 3.12, Node 24, git et ripgrep déjà installés. Une erreur d'authentification signifie généralement que la ligne contenant le token incluait le nom de la variable.

Les fichiers sont transférés avec dor sandbox push my-agent ./script.py, qui les place dans /home/user/script.py, et dor sandbox pull my-agent notes.txt permet d'en récupérer un. Les verbes natifs de gestion des fichiers limitent chaque fichier à 16 MiB. L'interface de fichiers E2B effectue un streaming et fait du quota disque du sandbox la seule limite.

La destruction est le seul verbe qui supprime les données. Elle illustre aussi l'ancienneté du projet : le README principal et la compétence agent fournie avec le projet documentent dor sandbox destroy <key>, tandis que le README du package CLI documente dor sandbox release <key>. Exécutez plutôt dor sandbox --help sur votre propre build et fiez-vous à son résultat.

Pointez votre code E2B existant vers votre propre serveur

C’est la raison principale de vous y intéresser. Le package officiel e2b installé depuis npm, sans modification, communique avec Dormice. Exécutez ceci depuis votre ordinateur portable avec le tunnel SSH ouvert. Aucun nouveau service n’écoute ainsi sur le serveur.

npm init -y
npm i e2b tsx
import { 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

Une exécution correcte affiche le code de sortie 0 et 42. La clé API est votre token Dormice précédé du préfixe e2b_. C’est le format attendu par la couche de compatibilité.

La compatibilité ne se limite pas à un stub. La suite de tests de bout en bout du projet utilise le package officiel avec un daemon Docker et gVisor réel pour tester la sortie standard et la sortie d’erreur en streaming, les commandes en arrière-plan, un PTY interactif, les URL d’upload et de download signées, la surveillance de répertoires et un proxy de port. Quelques différences doivent être prises en compte avant toute migration réelle :

  • La création de templates n’est pas implémentée. Un template est une image Docker que vous construisez vous-même et enregistrez avec dor template add. Sandbox.create('name') la résout ensuite. Un nom non enregistré renvoie une erreur 404 au lieu d’être accepté comme s’il existait.
  • Les sandboxes créés via l’interface E2B ont de vraies échéances, car la sémantique E2B l’exige. Aucune échéance n’est imposée aux sandboxes créés via l’API native.
  • Une sandbox gelée conserve ses processus et les reprend là où ils en étaient. Ici, la mise en pause et la reprise ne correspondent donc pas à l’arrêt puis au redémarrage à froid auxquels vous êtes peut-être habitué.

Ce que le sandbox bloque et ce qu’il ne bloque pas

gVisor intercepte les appels système du conteneur en espace utilisateur et les traite lui-même. Le code exécuté dans le sandbox ne communique donc pas directement avec le kernel de l’hôte. Dans le sandbox, tout s’exécute avec un utilisateur non privilégié, uid 1000. Cette combinaison couvre le cas courant : un script généré qui exécute rm -rf /, remplit le disque ou crée des processus jusqu’à provoquer une panne endommage son propre sandbox, puis s’arrête là.

Voici ce que le sandbox ne bloque pas. Ces points relèvent de votre responsabilité.

  • Un sandbox dispose d’un accès réseau sortant fonctionnel. Le code généré peut télécharger ce qu’il veut et envoyer tout ce qu’il trouve. Le renforcement réseau de l’installateur couvre deux points précis : il bloque le trafic des conteneurs vers le service de métadonnées cloud sur 169.254.0.0/16, qui permet au cloud de fournir les identifiants de l’instance à tout ce qui peut l’atteindre, et il désactive le trafic entre conteneurs avec "icc": false dans daemon.json de Docker. Rien d’autre n’est bloqué. Consultez sudo iptables -S DOCKER-USER et ajoutez vos propres règles DROP pour les plages privées qu’un sandbox ne doit pas pouvoir atteindre.
  • Docker insère ses propres règles avant celles de votre firewall. Un port publié par un conteneur peut donc répondre depuis Internet alors que ufw indique qu’il est fermé. Consultez la publication des ports Docker qui contourne ufw et les bases du firewall ufw pour un VPS avant d’exposer quoi que ce soit sur cet hôte.
  • gVisor est un kernel en espace utilisateur, pas un hyperviseur. C’est un compromis délibéré : le gel d’un sandbox exige que celui-ci soit un processus, et imposer KVM empêcherait l’installation partout. Si votre modèle de menace exige une virtualisation matérielle, utilisez une isolation de type Firecracker et acceptez le coût opérationnel associé.
  • Le token d’API constitue toute la frontière de sécurité côté client. Tout détenteur de DORMICE_API_TOKEN peut créer, lire et détruire chaque sandbox de la machine. Donnez au processus agent son propre utilisateur avec le moins de privilèges sur le VPS et traitez le token comme une clé SSH. Les pratiques de l’exécution sûre de Claude Code sur un VPS s’appliquent directement.

Le daemon lui-même s’exécute en tant que root sur votre hôte. gVisor protège l’hôte contre le code exécuté dans un sandbox, mais rien ne protège l’hôte contre le daemon ou contre toute personne qui détient son token. La machine qui exécute Dormice doit donc être dédiée à cette seule tâche. Si votre agent accède également à des outils via MCP (model context protocol), gardez ces serveurs MCP sur un VPS distinct pour la même raison.

Combien de sandbox tiennent dans 4 GB et 8 GB ?

Deux éléments consomment de la mémoire : la consommation de base de l’hôte et le working set de chaque sandbox actuellement actif. Réservez environ 1 GB pour Ubuntu, Docker et le daemon, puis divisez la mémoire restante par la consommation réelle d’un sandbox. Un sandbox qui exécute un script Python lisant quelques fichiers utilise environ 200 à 300 MiB. Un sandbox qui exécute un compilateur ou une suite de tests complète peut dépasser 1 gibibyte.

ChartConcurrent sandboxes by host RAM, arithmetic after a 1 GB host reserve
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
  }
]

Un VPS de 4 GB peut garder environ 6 sandbox actifs en même temps si chacun utilise 512 MiB, ou 3 si chacun utilise 1 gibibyte complet. Avec 8 GB, ces valeurs passent à 14 et 7. Ce sont des plafonds pour les tâches concurrentes, calculés arithmétiquement et non mesurés par benchmark. Surveillez donc free -m pendant l’exécution de votre propre charge.

Les sandbox gelés sont limités par le swap plutôt que par la RAM, ce qui constitue l’objectif de cette conception. Un sandbox gelé qui utilisait 1 gibibyte conserve environ cette quantité dans le swap et presque rien en mémoire résidente. Le fichier de swap de 16 GB créé par défaut par l’installateur peut donc en stocker environ 16. Au-delà, ils doivent passer à l’état arrêté, où ils ne consomment que de l’espace disque. Le disque constitue la vraie limite à long terme : chaque sandbox conserve son filesystem, et quelques dizaines d’agents contenant chacun un répertoire node_modules rempliront un petit volume bien avant que la mémoire ne devienne un problème.

Geler, arrêter, archiver : les paramètres du cycle de vie

Par défaut, le sandbox est gelé après 10 minutes d’inactivité, arrêté après 3 jours, puis archivé après 7 jours si l’archivage est configuré. Définir stopAfterSeconds sur null fournit un agent résident : il peut être gelé lorsqu’il est inactif, mais il ne redémarre jamais à froid.

L’archivage est facultatif, et le daemon l’indique clairement. Définissez les quatre variables DORMICE_S3_*. Le disque d’un sandbox arrêté est alors empaqueté avec tar et zstd, envoyé vers n’importe quel bucket compatible S3, puis libéré localement. Ce bucket peut être un bucket MinIO que vous hébergez vous-même sur une autre de vos machines. Si vous laissez les variables non définies, les sandbox restent indéfiniment à l’état arrêté, et une policy demandant l’archivage est refusée au lieu d’être ignorée silencieusement. Les restaurations sont visibles : l’acquisition suivante répond immédiatement avec un état de restauration et une valeur de progression, puis passe à l’état prêt lorsque le disque est de nouveau disponible.

Faut-il déjà en dépendre ?

Réponse directe : pas pour quoi que ce soit que vous ne pouvez pas reconstruire. Le premier commit du dépôt date du 8 juillet 2026. Au 4 août 2026, le projet affiche 446 stars, 37 forks, une licence Apache-2.0 et aucune release taguée. La ligne d’état du README indique elle-même que rien n’est prêt pour la production.

Cette combinaison crée un risque bien précis. Le code peut changer sous vos pieds, car l’installateur suit main. L’interface est encore en cours de stabilisation. C’est exactement pour cela que le verbe de suppression porte deux noms différents dans deux fichiers du même dépôt. De plus, un projet vieux de quatre semaines peut simplement s’arrêter, car aucune clause de licence n’oblige ses auteurs à poursuivre son développement.

La compatibilité E2B rend ce risque acceptable. Votre application utilise un protocole qui dispose d’une implémentation hébergée. Si Dormice s’arrête, vous pouvez modifier deux URL et continuer à fonctionner. Développez votre agent contre l’interface E2B plutôt que contre l’API native afin de conserver cette solution de repli. Le package natif @dormice/sdk n’est pas encore disponible sur npm. Son utilisation nécessite donc de le compiler depuis le dépôt, ce qui constitue une deuxième raison de commencer par la voie compatible.

Exécutez-le dans un environnement dont vous pouvez accepter la perte. Reconstruisez l’hôte à partir d’un script, ne placez le token dans aucun prompt ni commit, et récupérez les éléments importants depuis les sandboxes selon votre propre calendrier de sauvegarde.

FAQ

Dormice est-il prêt pour la production ?

Non, et le projet le précise lui-même. La ligne d’état du README indique que rien n’est encore prêt pour la production. Au 4 août 2026, le dépôt a environ quatre semaines, ne contient aucun tag git et aucune release. Il n’existe donc aucun numéro de version à verrouiller. L’installateur clone la branche main, ce qui signifie que chaque exécution récupère le commit le plus récent. Enregistrez git -C /opt/dormice rev-parse HEAD après chaque installation et conservez toutes les données importantes en dehors des sandboxes.

En quoi Dormice diffère-t-il d’une VM éphémère fournie à votre agent ?

Une VM éphémère est une machine avec SSH que vous créez pour une session, puis que vous supprimez. Dormice est une API d’exécution : votre programme appelle acquire, puis exec, et récupère stdout ainsi qu’un code de sortie, sans session shell intermédiaire. La VM convient à un humain ou à un agent qui a besoin d’un ordinateur complet pendant un certain temps. Dormice convient à une application qui exécute du code généré plusieurs fois par jour et ne veut pas recréer et supprimer une machine entière à chaque exécution.

Le SDK E2B officiel fonctionne-t-il réellement sans modifier le code ?

Oui, avec des changements de configuration. Configurez apiUrl et sandboxUrl pour utiliser /e2b/api et /e2b/envd sur votre daemon, puis transmettez votre token Dormice comme clé d’API avec le préfixe e2b_. L’exécution de commandes, les sessions PTY, le transfert de fichiers, les URL signées et le port proxy sont tous couverts par la suite de tests end-to-end du projet exécutée via le package officiel. La création de templates constitue la principale lacune : e2b template build n’est pas implémenté. Un template est donc une image Docker que vous construisez et enregistrez avec dor template add.

Combien de sandboxes peuvent fonctionner sur un VPS de 4 GB ?

Environ 6 peuvent être actives simultanément si chaque sandbox utilise 512 MiB, ou 3 si chacune utilise un gibioctet complet, après avoir réservé environ 1 GB pour le système d’exploitation, Docker et le daemon. Les sandboxes gelées sont plutôt limitées par le swap. Le swapfile de 16 GB créé par défaut par l’installateur permet donc de conserver environ 16 sandboxes ayant chacune utilisé un gibioctet. Mesurez votre propre charge avec free -m, car une sandbox qui exécute une suite de tests utilise plusieurs fois plus de mémoire qu’une sandbox qui exécute un petit script.

Pourquoi Dormice doit-il avoir vm.swappiness réglé sur 100 ?

Geler une sandbox consiste à déplacer sa mémoire inactive vers le swap. gVisor conserve la mémoire de la sandbox sous forme de mémoire partagée, et le noyau Linux ne permute pas la mémoire partagée avec la valeur par défaut de swappiness. Avec cette valeur, le gel ne récupère donc aucune mémoire et la sandbox continue de consommer toute sa mémoire. Le projet a mesuré 0 octet récupéré avec la valeur par défaut, contre 99.5 pour cent avec la valeur 100. Vérifiez la valeur effective avec sysctl vm.swappiness au lieu de lire les fichiers de configuration, car certaines images cloud fournissent une valeur de 0.