SSD Nodes Learn 🎉 VPS desde $5.50/mes
Guías Matt ConnorPor Matt Connor

Aloja OpenBot en tu VPS con un contenedor por bot

Ejecuta OpenBot con un gateway y un contenedor por compañero de IA. Cada bot mantiene Chromium y su perfil; calcula el consumo de RAM antes de instalarlo.

Lo que obtiene al alojar sus propios compañeros de trabajo de IA de OpenBot

Puede alojar sus propios compañeros de trabajo de IA de OpenBot ejecutando un servidor gateway y un contenedor por bot en hardware bajo su control. Cada contenedor de bot incluye su propio navegador Chromium y su propio volumen de espacio de trabajo, con un perfil del navegador que persiste entre sesiones. Cada acción que un bot realiza en un equipo, un archivo, un servidor MCP (model context protocol) o un componente de UI pasa por ese gateway. El gateway comprueba la acción según una política antes de ejecutarla y la registra después.

CopilotKit publica OpenBot con licencia MIT en github.com/CopilotKit/openbot. La primera versión etiquetada, v0.0.1, se publicó el 17 August 2026, y el proyecto se describe como alpha y en desarrollo activo. Trátelo como un diseño sólido que todavía presenta limitaciones iniciales.

La parte interesante de esta arquitectura también es la más costosa. Un navegador por agente es el coste de memoria que la mayoría de las personas olvida planificar. Por eso, aquí el dimensionamiento se realiza antes de la instalación.

Cómo decide el gateway cada acción

El servidor de API en el puerto 3001 es la única vía de acceso al equipo de un bot. Antes de ejecutar una acción del navegador, el gateway resuelve el destino a partir de una instantánea de la página, evalúa las reglas de política de CEL (Common Expression Language) según el contexto, escribe una fila de auditoría con la decisión y sólo después llama al contenedor. Si la ejecución falla después de eso, escribe una segunda fila. La documentación establece claramente este límite: el equipo no decide la política; el gateway del servidor es el límite de las acciones.

La política aplica denegación predeterminada y las reglas de denegación se evalúan antes que las reglas de autorización. La dirección del fallo importa más que la sintaxis de las reglas. Una política ausente no permite nada, y una regla incorrecta falla bloqueando tanto si es una regla de denegación como si es una regla de autorización. Por tanto, un error en la política deja el bot bloqueado en lugar de permitirle actuar sin restricciones sobre sus cuentas.

El registro de auditoría se almacena en PostgreSQL, por lo que sobrevive a un reinicio. Las transferencias de control se registran como computer.help_requested, computer.control_taken y computer.control_released. Así puede ver cuándo un bot solicita intervención humana y cuándo la persona devuelve el control. Los secretos se registran como recuentos de caracteres, nunca como valores. Las operaciones de archivos registran la ruta y el tamaño, nunca el contenido. Si quiere el mismo límite de control sin un navegador detrás, controlar las acciones de agentes de IA mediante aprobaciones cubre ese caso más específico.

Qué coste tienen un bot en RAM y disco

El proyecto publica cifras medidas para un solo Bot en arm64. Son las únicas cifras de dimensionamiento que ofrece OpenBot y describen un bot en una arquitectura concreta. Tómalas como punto de partida, no como un plan de capacidad.

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 memoria máxima medida fue de 0.55 GB para un Bot. El mínimo documentado es de 2 GB y la recomendación es de 4 GB. La diferencia entre la medición y el mínimo deja margen para que Chromium crezca bajo carga, porque el uso de memoria de un navegador depende de las páginas abiertas y no del proceso en reposo. El uso de CPU en reposo es prácticamente nulo: 0.06 de un núcleo en el extremo superior del intervalo medido. Por tanto, la CPU no es el recurso principal que estás dimensionando. El disco sí lo es. La imagen ocupa por sí sola 5.3 GB, frente a un volumen recomendado de 10 GB. Ocupa tanto porque incluye los binarios de Firefox y WebKit de Playwright junto a Chromium.

Estas cifras no indican cuánto cuestan varios bots juntos, y el proyecto no publica ninguna cifra para ese caso. Haz tus propias mediciones. Inicia un bot, asígnale una tarea real con una página abierta y monitoriza el contenedor mientras trabaja.

docker stats --no-stream
free -m

Toma la columna MEM USAGE del contenedor del bot como cifra por bot. Añade el gateway y PostgreSQL y, después, multiplica la cifra por bot por el número de bots que esperas tener al mismo tiempo. Un bot inactivo sigue manteniendo un proceso del navegador, por lo que el multiplicador se aplica a los bots existentes, no sólo a los que están trabajando. El cálculo es el mismo que se utiliza para dimensionar la RAM y la CPU de un VPS para un agente de programación, y la parte relacionada con el navegador se explica en ejecutar un navegador sin interfaz para agentes en un VPS.

Un detalle de Chromium afecta a los planes pequeños. OpenBot inicia Chromium con --disable-dev-shm-usage, por lo que el navegador escribe en /tmp en lugar de /dev/shm. Así se evita el fallo que se produce en hosts con un /dev/shm pequeño y se traslada la presión al sistema de archivos raíz. Es otra razón por la que el disco recomendado es mayor que la imagen.

¿Cómo se aloja OpenBot en un VPS?

Necesita Docker, Bun 1.3 o una versión posterior, un proyecto de CopilotKit Intelligence y una clave de API del modelo. La documentación de desarrollo también espera lsof, python3 y curl en el servidor. Clone una versión etiquetada en lugar de main, porque main en un proyecto alfa cambia sin previo aviso.

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

Prepare el proyecto de Intelligence. Estos tres comandos escriben la clave de ejecución y el token de licencia en el archivo de entorno.

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

Genere la clave que cifra las credenciales almacenadas y coloque la salida en .env como KEY_ENCRYPTION_KEY. Añada su OPENAI_API_KEY en el mismo archivo, o establezca BOT_PROVIDER en anthropic o google con la clave correspondiente.

openssl rand -base64 32

A continuación, instale e inicie el servicio.

bun install
bash scripts/start.sh

scripts/start.sh inicia los servicios de Docker, ejecuta las migraciones de la base de datos, inicia el servidor y la aplicación, y comprueba su estado. Cuando termina, la aplicación responde en el puerto 3010 y la API en el puerto 3001. El script informa de los conflictos de puertos y deja sin cambios un servicio coincidente que ya esté en ejecución, por lo que es seguro ejecutarlo dos veces.

Compruébelo desde el propio servidor antes de exponer ningún servicio.

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 del primer comando significa que la aplicación está atendiendo solicitudes. El segundo comando muestra en qué direcciones están enlazados esos puertos, y ese es el dato importante en un VPS. Una línea que indique 127.0.0.1:3001 sólo es accesible desde el servidor. Una línea que indique 0.0.0.0:3001 significa que cualquiera que pueda enrutar tráfico hacia el servidor puede acceder a él.

La imagen de contenedor única

La documentación de despliegue también proporciona una sola imagen que contiene la aplicación, la API y Chromium, y que se sirve en el puerto 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 ejecuta PostgreSQL dentro del contenedor y aplica las migraciones al iniciar. El volumen con nombre conserva el historial de auditoría entre redespliegues. Sin él, cada reconstrucción elimina ese historial. Si configura DATABASE_URL para usar una base de datos administrada, debe habilitar en ella la extensión vector. Servicios administrados como RDS, Cloud SQL y Azure Database admiten la extensión, pero ninguno la habilita automáticamente. Por eso, una migración contra una base de datos administrada nueva falla porque el tipo de columna vector todavía no existe.

Ejecute las migraciones como un paso de publicación cuando la base de datos sea externa.

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

Esa imagen deja deliberadamente sin publicar el puerto del navegador. También omite el supervisor porque este necesita el socket de Docker, que las plataformas serverless no ofrecen. Sin el supervisor, todos los bots comparten un navegador y, por tanto, el mismo conjunto de credenciales. Esto elimina el aislamiento que justificaba ejecutar un contenedor por bot. Si necesita credenciales separadas para cada bot, ejecute el stack de Compose con COMPUTER_SUPERVISOR_URL y SUPERVISOR_TOKEN definidos, en un host donde acepte este compromiso. Un proceso que pueda comunicarse con el socket de Docker puede iniciar un contenedor con privilegios. En la práctica, tiene acceso root al host. Esta es una buena razón para mantener OpenBot en una máquina independiente, del mismo modo que proporcionar a los agentes de programación una VM desechable.

Por qué OPENBOT_SINGLE_USER es una configuración para portátiles

.env.example se distribuye con OPENBOT_SINGLE_USER=true. Esa configuración acepta todas las solicitudes como si procedieran de un único administrador y omite por completo el inicio de sesión. En un portátil es práctico, porque el único cliente que puede acceder al puerto eres tú. En un VPS significa que la primera persona que acceda al puerto 3010 se convierte en administradora de un sistema que almacena credenciales cifradas y controla un navegador que ya tiene iniciada la sesión en tus cuentas.

Hay dos formas seguras de ejecutarlo. Mantén OPENBOT_SINGLE_USER=true, enlaza todos los puertos con 127.0.0.1 y accede a la aplicación sólo mediante un túnel SSH o una interfaz de red privada.

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

La aplicación estará disponible en http://localhost:3010 desde tu propio navegador. El navegador lo considera un contexto seguro, por lo que funcionan tanto las cookies de inicio de sesión como las funciones del navegador que necesita la pantalla interactiva. La otra opción es desactivar el modo de usuario único y configurar un proveedor de identidad real. Se admiten Google, Microsoft Entra, Okta, SAML y OIDC. Cualquier proveedor también necesita BETTER_AUTH_SECRET con 32 caracteres o más, BETTER_AUTH_URL configurado con la URL base pública de la API para las devoluciones de OAuth, INITIAL_ADMIN_EMAILS y TRUSTED_ORIGINS. Las credenciales del proveedor deben estar completas, porque un proveedor configurado a medias impide el arranque en lugar de volver al acceso abierto.

Si se puede acceder a la aplicación mediante un nombre público, coloca TLS (transport layer security) delante de ella. Una página servida mediante http:// desde cualquier ubicación que no sea localhost no es un contexto seguro. Por eso no se almacenan las cookies marcadas con Secure y el inicio de sesión falla de una forma que parece un error de OpenBot.

Cierre los puertos de las capas inferiores

La propia nota de seguridad de OpenBot indica que los endpoints de servicio de las capas inferiores están protegidos mediante tokens, que deben mantenerse privados y que no deben utilizarse para omitir el gateway. Los tokens son la segunda protección. La primera consiste en que el puerto no sea accesible en absoluto.

El agent-computer escucha en 4100 y requiere COMPUTER_TOKEN. Los endpoints del bot escuchan en 4200 y 4201. El supervisor escucha en 4500 en el host y en 4300 dentro de su contenedor. PostgreSQL escucha en 5432. Ninguno de esos servicios debe estar en una interfaz pública. En una implementación para un solo usuario, tampoco deben estarlo la aplicación ni la API.

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

Aquí hay una trampa que afecta a quienes suponen que el firewall es suficiente. Publicar un puerto de contenedor con -p 3001:3001 hace que Docker instale una regla DNAT. Por tanto, el tráfico se procesa en la ruta FORWARD y nunca pasa por la cadena INPUT, que es la que controla la denegación predeterminada de ufw. El puerto permanece abierto aunque ufw status siga mostrando Status: active. Enlaza el puerto publicado a loopback directamente en la asignación, como -p 127.0.0.1:3001:3001, o establece la dirección del host en el archivo compose. Compruébalo con ss -ltnp, no con ufw status.

OpenBot no es una pila sin conexión

Establezca esto antes de planificar el despliegue. OpenBot depende de un proyecto de CopilotKit Intelligence, que almacena los hilos persistentes y la memoria de las conversaciones fuera de su servidor. El servidor valida INTELLIGENCE_API_URL, INTELLIGENCE_GATEWAY_WS_URL, INTELLIGENCE_API_KEY y COPILOTKIT_LICENSE_TOKEN durante el arranque. Los cuatro deben estar presentes al mismo tiempo o el arranque falla. Desde August 2026 hay un plan gratuito. Intelligence también se puede alojar por cuenta propia, por lo que es posible realizar un despliegue completamente local, aunque requiere más trabajo del que muestra la guía de inicio rápido.

El modelo es la segunda dependencia externa. El paquete no incluye ningún modelo. BOT_PROVIDER acepta openai, anthropic o google. OPENAI_BASE_URL dirige la ruta de OpenAI a cualquier endpoint compatible. Ahí encaja ejecutar Ollama en un VPS para alojar un LLM por cuenta propia si quiere que los tokens permanezcan en su propio hardware. El control del navegador exige mucho del modelo. Pruebe un modelo local con una tarea real antes de adoptarlo.

Ejecute una sola réplica por ahora

El gateway almacena en caché las instantáneas de las páginas en la memoria del proceso del servidor. Con dos réplicas, una instantánea tomada por un proceso no es visible para el otro. Por eso, las acciones fallan de forma intermitente con errores de elemento no encontrado que parecen aleatorios. La documentación del despliegue es explícita: ejecute una sola réplica y establezca en 1 el número máximo de instancias de la plataforma. Este límite dejará de ser necesario cuando el almacenamiento en caché de instantáneas pase a la base de datos. Hasta entonces, escale OpenBot aumentando la capacidad del servidor, no añadiendo servidores. El aislamiento entre bots sigue procediendo de los contenedores independientes de cada bot, del mismo modo que los sandbox de agentes autohospedados mantienen los errores de un agente alejados de los demás.

Modos de fallo y lo que verá

El proceso de arranque termina inmediatamente después de completar .env. El servidor valida la configuración antes de atender peticiones. Un bloque Intelligence incompleto, la ausencia de KEY_ENCRYPTION_KEY o un proveedor OAuth con un ID de cliente pero sin secreto detienen el arranque en lugar de degradar el funcionamiento de forma silenciosa. Lea el primer error, corrija ese campo y vuelva a iniciar el servidor.

Las migraciones fallan en una base de datos administrada. La extensión vector no está habilitada de forma predeterminada, por lo que la migración encuentra un tipo de columna que PostgreSQL no reconoce. Conéctese como superuser, ejecute CREATE EXTENSION vector; y vuelva a ejecutar el paso de migración.

La aplicación carga, pero el inicio de sesión nunca se conserva. Está sirviendo mediante http:// sin cifrado en una dirección pública, que no es un contexto seguro, por lo que el navegador descarta la cookie Secure. Configure TLS delante de la aplicación o use el túnel SSH para que el navegador vea localhost.

Los bots comparten sesiones que esperaba mantener separadas. El supervisor no se está ejecutando, por lo que no existe un equipo independiente por bot y todos usan el navegador compartido. Confirme que COMPUTER_SUPERVISOR_URL esté definido y que el supervisor pueda acceder al socket de Docker.

Un bot se detiene y solicita ayuda. Ese es el comportamiento previsto. El registro de auditoría registra computer.help_requested, usted toma el control en la pantalla activa y la transferencia queda registrada en ambos lados.

FAQ

¿Es seguro dejar activado OPENBOT_SINGLE_USER en una implementación de VPS?

Sólo cuando no se puede acceder al gateway desde Internet. OPENBOT_SINGLE_USER=true acepta todas las solicitudes como un único administrador sin autenticación, por lo que cualquiera que pueda abrir el puerto controla la implementación, sus credenciales almacenadas y el navegador con la sesión iniciada. Es aceptable cuando todos los puertos están vinculados a 127.0.0.1 y se accede a la aplicación mediante un túnel SSH o una interfaz de red privada. En una interfaz pública, desactívelo y configure Google, Microsoft Entra, Okta u OIDC junto con BETTER_AUTH_SECRET, BETTER_AUTH_URL, INITIAL_ADMIN_EMAILS y TRUSTED_ORIGINS.

¿Cuánta RAM necesita un bot de OpenBot?

Las cifras publicadas por el proyecto para un solo Bot en arm64 sitúan el uso máximo de memoria en 0.55 GB, con 2 GB como mínimo documentado y 4 GB recomendados. No hay una cifra publicada para varios bots simultáneos, porque cada uno mantiene su propio Chromium. Ejecute un bot con una tarea real, consulte la memoria de ese contenedor en docker stats, sume el gateway y la base de datos, y multiplique el resultado por el número de bots que espera ejecutar al mismo tiempo.

¿Necesito una cuenta de CopilotKit para alojar OpenBot por mi cuenta?

Sí. OpenBot depende de un proyecto de CopilotKit Intelligence para conservar los hilos y la memoria, y el servidor no se inicia si no están definidos la URL de la API de Intelligence, la URL WebSocket del gateway, la clave de API y el token de licencia. Hay un plan gratuito disponible desde agosto de 2026, y Intelligence se puede alojar por cuenta propia, por lo que es posible eliminar la dependencia del servicio alojado con trabajo adicional. También debe proporcionar su propia clave de API del modelo, porque OpenBot no incluye ningún modelo.

¿Por qué cada bot tiene su propio navegador en lugar de compartir uno?

Porque un perfil de navegador es una identidad. Un navegador compartido implica cookies y sesiones compartidas, por lo que un bot que haya iniciado sesión en una cuenta hace que todos los bots tengan la sesión iniciada en esa cuenta. Los contenedores independientes por bot proporcionan a cada compañero su propio perfil y sus propias sesiones. El coste es la memoria, ya que un Chromium por bot es el componente individual que más recursos consume.

¿Qué puertos de OpenBot deben estar abiertos en el firewall?

Ninguno de los puertos internos. El agent-computer en 4100, los endpoints de los bots en 4200 y 4201, el supervisor en 4500 y PostgreSQL en 5432 deben permanecer privados. El proyecto los protege con tokens y solicita que, aun así, permanezcan inaccesibles. Publique sólo lo que una persona necesite abrir y recuerde que un puerto de contenedor publicado con -p 3001:3001 es accesible independientemente de una regla ufw de denegación predeterminada, porque la regla DNAT de Docker coloca ese tráfico en la ruta FORWARD en lugar de INPUT.