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

Auto-héberger OpenBot avec un bot IA par conteneur

Découvrez comment la gateway OpenBot contrôle et journalise chaque action, pourquoi chaque bot a son navigateur Chromium et combien de RAM prévoir sur votre VPS.

Résultat de l’auto-hébergement de collaborateurs IA OpenBot

Vous auto-hébergez les collaborateurs IA OpenBot en exécutant un serveur gateway et un conteneur par bot sur du matériel que vous contrôlez. Chaque conteneur de bot contient son propre navigateur Chromium et son propre volume de workspace, avec un profil de navigateur conservé entre les sessions. Chaque action effectuée par un bot sur un ordinateur, un fichier, un serveur MCP (model context protocol) ou un composant d’interface utilisateur passe par cette gateway. Celle-ci vérifie l’action par rapport à une policy avant son exécution, puis l’enregistre.

OpenBot est publié par CopilotKit sous licence MIT sur github.com/CopilotKit/openbot. La première release marquée, v0.0.1, a été publiée le 17 August 2026. Le projet se décrit comme étant en alpha et en développement actif. Considérez-le comme une conception sérieuse, mais encore marquée par des limites de début de projet.

L’intérêt de cette architecture est aussi ce qui la rend coûteuse. Un navigateur par agent représente le coût mémoire que la plupart des utilisateurs oublient de prévoir. Le dimensionnement passe donc avant l’installation.

Comment la passerelle décide de chaque action

Le serveur d’API sur le port 3001 est le seul chemin vers l’ordinateur d’un bot. Avant l’exécution d’une action dans le navigateur, la passerelle détermine la cible à partir d’un instantané de la page, évalue les règles de stratégie CEL (Common Expression Language) dans leur contexte, écrit une ligne d’audit contenant la décision, puis appelle le conteneur. Si l’exécution échoue ensuite, elle écrit une deuxième ligne. La documentation indique clairement la séparation : l’ordinateur ne décide pas de la stratégie, la passerelle du serveur constitue la limite d’action.

La stratégie applique un refus par défaut et les règles de refus sont évaluées avant les règles d’autorisation. Le comportement en cas d’échec compte davantage que la syntaxe des règles. Une stratégie absente n’autorise rien et une règle incorrecte bloque l’action, qu’il s’agisse d’une règle de refus ou d’une règle d’autorisation. Une erreur de stratégie entraîne donc un bot bloqué, et non un bot libre d’agir sur vos comptes.

La piste d’audit est stockée dans PostgreSQL et survit donc à un redémarrage. Les transferts de contrôle sont enregistrés sous computer.help_requested, computer.control_taken et computer.control_released. Vous pouvez ainsi voir un bot demander l’intervention d’un humain, puis voir l’humain lui rendre le contrôle. Les secrets sont enregistrés sous forme de nombres de caractères, jamais sous forme de valeurs. Les opérations sur les fichiers enregistrent le chemin et la taille, jamais le contenu. Pour appliquer la même limite de contrôle sans navigateur en arrière-plan, consultez faire passer les actions d’un agent IA par des validations.

Combien consomme un bot en RAM et sur le disque

Le projet publie des mesures pour un seul Bot sur arm64. Ce sont les seuls chiffres de dimensionnement fournis par OpenBot. Ils décrivent un bot sur une architecture donnée. Considérez-les donc comme un point de départ, et non comme un plan de capacité.

ChartOpenBot published resource figures, one Bot on arm64 (August 2026)
The data behind this chart
[
  {
    "label": "Measured, one Bot",
    "memory_gb": 0.55,
    "disk_gb": 5.3,
    "vcpu": 0.06
  },
  {
    "label": "Documented minimum",
    "memory_gb": 2,
    "disk_gb": 8,
    "vcpu": 1
  },
  {
    "label": "Documented recommended",
    "memory_gb": 4,
    "disk_gb": 10,
    "vcpu": 2
  }
]

La mémoire maximale mesurée est de 0.55 Go pour un Bot. Le minimum documenté est de 2 Go et la recommandation est de 4 Go. L’écart entre la mesure et le minimum laisse à Chromium la possibilité d’augmenter sa consommation sous charge. La mémoire utilisée par un navigateur dépend des pages ouvertes, et non de la consommation du processus au repos. La consommation CPU au repos est presque nulle : 0.06 cœur au maximum de la plage mesurée. Le CPU n’est donc pas le principal poste de consommation. Le disque l’est. L’image seule occupe 5.3 Go, contre un volume recommandé de 10 Go. Elle est aussi volumineuse parce qu’elle inclut les binaires Firefox et WebKit de Playwright en plus de Chromium.

Ces chiffres ne permettent pas de savoir combien coûteront plusieurs bots ensemble. Le projet ne publie aucune mesure pour ce cas. Faites vos propres mesures. Démarrez un bot, donnez-lui une tâche réelle avec une page ouverte, puis surveillez le conteneur pendant son exécution.

docker stats --no-stream
free -m

Relevez la colonne MEM USAGE pour le conteneur du bot afin d’obtenir la consommation par bot. Ajoutez ensuite la gateway et PostgreSQL, puis multipliez la consommation par bot par le nombre de bots que vous prévoyez d’exécuter simultanément. Un bot inactif conserve tout de même un processus de navigateur. Le multiplicateur s’applique donc aux bots existants, et pas uniquement aux bots actifs. Le calcul est le même que celui utilisé pour dimensionner la RAM et le CPU d’un VPS pour un agent de code. La partie consacrée au navigateur est détaillée dans exécuter un navigateur headless pour des agents sur un VPS.

Un détail concernant Chromium est important pour les petites configurations. OpenBot lance Chromium avec --disable-dev-shm-usage. Le navigateur écrit donc dans /tmp au lieu de /dev/shm. Cela évite le crash qui se produit sur les hôtes disposant d’un /dev/shm de petite taille. En contrepartie, la charge est reportée sur le système de fichiers root. C’est une raison supplémentaire pour laquelle le disque recommandé est plus grand que l’image.

Comment auto-héberger OpenBot sur un VPS ?

Vous avez besoin de Docker, de Bun 1.3 ou d’une version plus récente, d’un projet Intelligence CopilotKit et d’une clé d’API de modèle. La documentation de développement attend également lsof, python3 et curl sur le serveur. Clonez une release marquée plutôt que main, car main sur un projet alpha change sans préavis.

git clone --branch v0.0.1 https://github.com/CopilotKit/openbot.git
cd openbot
cp .env.example .env

Provisionnez le projet Intelligence. Ces trois commandes écrivent la clé d’exécution et le token de licence dans votre fichier d’environnement.

npx --yes copilotkit@latest login
npx --yes copilotkit@latest project select
npx --yes copilotkit@latest license --write

Générez la clé qui chiffre les identifiants stockés et placez la sortie dans .env sous la forme KEY_ENCRYPTION_KEY. Ajoutez votre OPENAI_API_KEY dans le même fichier, ou définissez BOT_PROVIDER sur anthropic ou google avec la clé correspondante.

openssl rand -base64 32

Installez et démarrez ensuite les services.

bun install
bash scripts/start.sh

scripts/start.sh démarre les services Docker, exécute les migrations de la base de données, démarre le serveur et l’application, puis vérifie leur état. À la fin, l’application répond sur le port 3010 et l’API sur le port 3001. Le script signale les conflits de ports et laisse en place un service correspondant déjà démarré. Vous pouvez donc l’exécuter deux fois sans risque.

Vérifiez le fonctionnement depuis le serveur lui-même avant d’exposer quoi que ce soit.

curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3010
ss -ltnp | grep -E ':(3010|3001|4100|4500|5432)'

Un 200 renvoyé par la première commande signifie que l’application répond. La deuxième commande indique à quelles adresses ces ports sont liés. C’est cette information qui compte sur un VPS. Une ligne contenant 127.0.0.1:3001 indique que le service est accessible uniquement depuis le serveur. Une ligne contenant 0.0.0.0:3001 signifie que toute personne pouvant joindre le serveur peut y accéder.

L’image de conteneur unique

La documentation de déploiement fournit également une image unique qui contient l’application, l’API et Chromium, accessible sur le port 3001.

docker build -t openbot .
docker run -p 127.0.0.1:3001:3001 --env-file .env \
  -e EMBEDDED_POSTGRES=on -v openbot-data:/var/lib/postgresql/data openbot

EMBEDDED_POSTGRES=on exécute PostgreSQL dans le conteneur et applique les migrations au démarrage. Le volume nommé conserve l’historique d’audit lors d’un nouveau déploiement. Sans ce volume, chaque reconstruction supprime cet historique. Si vous configurez DATABASE_URL pour utiliser une base de données managée, l’extension vector doit y être activée. Les services managés tels que RDS, Cloud SQL et Azure Database prennent en charge cette extension, mais aucun ne l’active pour vous. Une migration vers une base de données managée vierge échoue donc, car le type de colonne vector n’existe pas encore.

Exécutez les migrations comme étape de release lorsque la base de données est externe.

docker run --rm --env-file .env openbot \
  sh -c "cd /app/server && bun x drizzle-kit migrate --config=drizzle.config.ts"

Cette image n’expose volontairement pas le port du navigateur. Elle n’inclut pas non plus le superviseur, car celui-ci a besoin du socket Docker, que les plateformes serverless ne fournissent pas. Sans superviseur, tous les bots partagent un même navigateur et donc un même ensemble d’identifiants de connexion. L’isolation qui justifiait l’exécution de conteneurs distincts pour chaque bot disparaît alors. Si vous avez besoin d’identifiants distincts pour chaque bot, exécutez la stack Compose avec COMPUTER_SUPERVISOR_URL et SUPERVISOR_TOKEN définis, sur un hôte où vous acceptez ce compromis. Un processus capable de communiquer avec le socket Docker peut démarrer un conteneur privilégié. En pratique, il dispose donc des privilèges root sur l’hôte. C’est une bonne raison de conserver OpenBot sur une machine dédiée, dans le même esprit que l’attribution d’une VM jetable aux agents de codage.

Pourquoi OPENBOT_SINGLE_USER est un réglage pour un ordinateur portable

.env.example est fourni avec OPENBOT_SINGLE_USER=true. Ce réglage considère chaque requête comme provenant d’un administrateur et désactive entièrement l’authentification. Sur un ordinateur portable, c’est pratique, car vous êtes le seul client pouvant atteindre le port. Sur un VPS, cela signifie que la première personne qui atteint le port 3010 devient administrateur d’un système qui stocke des identifiants chiffrés et contrôle un navigateur déjà connecté à vos comptes.

Il existe deux façons correctes de l’exécuter. Conservez OPENBOT_SINGLE_USER=true, liez chaque port à 127.0.0.1 et accédez à l’application uniquement via un tunnel SSH ou une interface réseau privée.

ssh -N -L 3010:127.0.0.1:3010 -L 3001:127.0.0.1:3001 you@your-vps

L’application est alors accessible à l’adresse http://localhost:3010 dans votre propre navigateur. Elle est ainsi considérée comme un contexte sécurisé. Les cookies d’authentification et les fonctionnalités du navigateur nécessaires à l’écran en direct fonctionnent donc correctement. L’autre solution consiste à désactiver le mode mono-utilisateur et à configurer un véritable fournisseur d’identité. Google, Microsoft Entra, Okta, SAML et OIDC sont pris en charge. Tous les fournisseurs nécessitent également BETTER_AUTH_SECRET avec au moins 32 caractères, BETTER_AUTH_URL défini sur l’URL de base publique de l’API pour les rappels OAuth, INITIAL_ADMIN_EMAILS et TRUSTED_ORIGINS. Les identifiants du fournisseur doivent être complets, car un fournisseur partiellement configuré empêche le démarrage au lieu de revenir à un accès ouvert.

Si l’application est accessible via un nom public, placez TLS (transport layer security) devant elle. Une page servie en http:// simple ailleurs que sur localhost n’est pas un contexte sécurisé. Les cookies marqués Secure ne sont donc pas enregistrés et l’authentification échoue d’une manière qui ressemble à un bug dans OpenBot.

Protéger les ports internes par le pare-feu

La note de sécurité d’OpenBot indique que les endpoints des services internes sont protégés par des tokens, qu’ils doivent rester privés et qu’ils ne doivent pas servir à contourner la gateway. Les tokens constituent la deuxième protection. La première consiste à rendre le port totalement inaccessible.

L’agent-computer écoute sur le port 4100 et nécessite COMPUTER_TOKEN. Les endpoints du bot écoutent sur les ports 4200 et 4201. Le supervisor écoute sur le port 4500 de l’hôte et sur le port 4300 dans son conteneur. PostgreSQL écoute sur le port 5432. Aucun de ces ports ne doit être exposé sur une interface publique. Dans un déploiement mono-utilisateur, cela s’applique également à l’application et à l’API.

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw enable
sudo ufw status verbose

Un piège se présente ici pour ceux qui pensent que le pare-feu suffit. La publication d’un port de conteneur avec -p 3001:3001 amène Docker à installer une règle DNAT. Le trafic est alors traité dans le chemin FORWARD et ne passe jamais par la chaîne INPUT, à laquelle s’applique le refus par défaut d’ufw. Le port reste ouvert alors que ufw status affiche toujours Status: active. Liez le port publié à la loopback directement dans le mapping, par exemple avec -p 127.0.0.1:3001:3001, ou définissez l’adresse de l’hôte dans votre fichier compose. Vérifiez avec ss -ltnp, et non avec ufw status.

OpenBot n’est pas une stack hors ligne

Établissez ce point avant de planifier le déploiement. OpenBot dépend d’un projet CopilotKit Intelligence, qui conserve les threads persistants et la mémoire des conversations en dehors de votre serveur. Au démarrage, le serveur valide INTELLIGENCE_API_URL, INTELLIGENCE_GATEWAY_WS_URL, INTELLIGENCE_API_KEY et COPILOTKIT_LICENSE_TOKEN ; les quatre doivent être présents ensemble, sinon le démarrage échoue. Un forfait gratuit est disponible depuis August 2026, et Intelligence peut lui-même être auto-hébergé. Un déploiement entièrement local est donc possible, mais il demande davantage de travail que ne l’indique le quickstart.

Le modèle constitue la deuxième dépendance externe. Aucun modèle n’est fourni avec OpenBot. BOT_PROVIDER accepte openai, anthropic ou google, et OPENAI_BASE_URL fait pointer le chemin OpenAI vers n’importe quel endpoint compatible. C’est là que s’insère l’exécution d’Ollama sur un VPS pour auto-héberger un LLM si vous voulez conserver les tokens sur votre propre matériel. Le contrôle du navigateur sollicite fortement le modèle. Testez donc un modèle local sur une tâche réelle avant de l’adopter.

Exécuter une seule réplique pour le moment

La passerelle met en cache les instantanés des pages dans la mémoire du processus serveur. Avec deux répliques, un instantané créé par un processus est invisible pour l’autre. Les actions échouent donc par intermittence avec des erreurs element-not-found qui semblent aléatoires. La documentation de déploiement est explicite : exécutez une seule réplique et définissez à 1 le nombre maximal d’instances de votre plateforme. Cette limite pourra être supprimée lorsque la mise en cache des instantanés sera déplacée vers la base de données. D’ici là, vous devez faire évoluer OpenBot en augmentant les ressources de la machine, et non en ajoutant des machines. L’isolation entre les bots repose toujours sur les conteneurs propres à chaque bot, comme les sandboxes d’agents auto-hébergées isolent les erreurs d’un agent de celles des autres.

Modes de défaillance et symptômes observés

Le démarrage s’arrête immédiatement après le renseignement de .env. Le serveur valide la configuration avant de fournir le moindre service. Un bloc Intelligence incomplet, l’absence de KEY_ENCRYPTION_KEY ou un fournisseur OAuth avec un client ID sans secret interrompent tous le démarrage au lieu de dégrader silencieusement le fonctionnement. Lisez la première erreur, corrigez ce champ, puis redémarrez.

Les migrations échouent sur une base de données managée. L’extension vector n’est pas activée par défaut. La migration utilise donc un type de colonne que PostgreSQL ne connaît pas. Connectez-vous en tant que superuser, exécutez CREATE EXTENSION vector;, puis relancez l’étape de migration.

L’application se charge, mais la session de connexion n’est jamais conservée. Vous utilisez http:// en clair sur une adresse publique. Il ne s’agit pas d’un contexte sécurisé, et le cookie Secure est donc rejeté. Placez TLS devant l’application ou utilisez le tunnel SSH afin que le navigateur voie localhost.

Des bots partagent des identifiants que vous pensiez distincts. Le supervisor n’est pas en cours d’exécution. Il n’y a donc pas d’ordinateur dédié par bot, et tous les bots utilisent le navigateur partagé. Vérifiez que COMPUTER_SUPERVISOR_URL est défini et que le supervisor peut accéder au socket Docker.

Un bot s’arrête et demande de l’aide. C’est le fonctionnement prévu. La piste d’audit enregistre computer.help_requested, vous prenez le contrôle sur l’écran en direct et la prise en main est enregistrée des deux côtés.

FAQ

OPENBOT_SINGLE_USER peut-il rester activé pour un déploiement sur un VPS ?

Uniquement si la gateway est inaccessible depuis Internet. OPENBOT_SINGLE_USER=true accepte chaque requête comme provenant d’un administrateur, sans authentification. Toute personne capable d’ouvrir le port contrôle donc le déploiement, les identifiants qu’il contient et le navigateur dans lequel une session est ouverte. Cette configuration convient si tous les ports sont liés à 127.0.0.1 et si vous accédez à l’application via un tunnel SSH ou une interface réseau privée. Sur une interface publique, désactivez-la et configurez Google, Microsoft Entra, Okta ou OIDC avec BETTER_AUTH_SECRET, BETTER_AUTH_URL, INITIAL_ADMIN_EMAILS et TRUSTED_ORIGINS.

De combien de RAM un bot OpenBot a-t-il besoin ?

Les chiffres publiés par le projet pour un seul bot sur arm64 indiquent un pic de mémoire de 0.55 Go, avec 2 Go comme minimum documenté et 4 Go recommandés. Aucun chiffre n’est publié pour plusieurs bots exécutés simultanément, car chacun utilise sa propre instance de Chromium. Exécutez un bot sur une tâche réelle, consultez la mémoire de son conteneur dans docker stats, ajoutez la gateway et la base de données, puis multipliez le résultat par le nombre de bots que vous prévoyez d’exécuter simultanément.

Ai-je besoin d’un compte CopilotKit pour auto-héberger OpenBot ?

Oui. OpenBot dépend d’un projet CopilotKit Intelligence pour conserver les threads et la mémoire. Le serveur refuse de démarrer si l’URL de l’API Intelligence, l’URL WebSocket de la gateway, la clé API et le token de licence ne sont pas tous définis. Une formule gratuite est disponible en août 2026. Intelligence peut aussi être auto-hébergé, ce qui permet de supprimer cette dépendance hébergée au prix d’un travail supplémentaire. Vous devez également fournir votre propre clé API de modèle, car aucun modèle n’est inclus avec OpenBot.

Pourquoi chaque bot possède-t-il son propre navigateur au lieu d’en partager un ?

Parce qu’un profil de navigateur constitue une identité. Un navigateur partagé implique des cookies et des sessions partagés. Ainsi, si un bot est connecté à un compte, tous les bots le sont. Les conteneurs distincts par bot donnent à chaque collaborateur son propre profil et ses propres connexions. Cette isolation augmente la consommation mémoire, car une instance de Chromium par bot représente le principal poste de consommation dans le dimensionnement.

Quels ports OpenBot doivent être ouverts sur le pare-feu ?

Aucun des ports internes. L’agent-computer sur 4100, les endpoints des bots sur 4200 et 4201, le supervisor sur 4500 et PostgreSQL sur 5432 doivent tous rester privés. Le projet les protège avec des tokens et demande qu’ils restent inaccessibles dans tous les cas. Publiez uniquement ce qu’un utilisateur doit pouvoir ouvrir. Gardez à l’esprit qu’un port de conteneur publié avec -p 3001:3001 reste accessible malgré une règle ufw en refus par défaut, car la règle DNAT de Docker place ce trafic dans le chemin FORWARD plutôt que dans INPUT.