SSD Nodes Learn Hosting plans →
Guías Matt ConnorPor Matt Connor · Actualizado 2026-08-28

Alojar OpenBot en un VPS con contenedores por bot

Aloje OpenBot con un gateway y un contenedor por compañero de IA. Cada uno tiene Chromium y workspace propios; revise cómo se autoriza cada acción y el consumo de RAM.

Qué obtiene al alojar sus propios compañeros de IA de OpenBot

Puede alojar sus propios compañeros 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 workspace, con un perfil de navegador que persiste entre sesiones. Todas las acciones que un bot realiza en un equipo, un archivo, un servidor MCP (model context protocol) o un componente de UI pasan por ese gateway. El gateway comprueba cada acción frente a una política antes de ejecutarla y la registra después. Si el bucle del agente que envuelve ese gateway todavía no le resulta familiar, la ruta gradual de aprendizaje de agentes de IA desde cero le permite escribir primero uno pequeño antes de proporcionar a un bot un navegador y sus credenciales.

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

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

Cómo decide el gateway cada acción

El servidor API del 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) respecto al 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 ese punto, escribe una segunda fila. La documentación establece claramente el límite: el equipo no decide la política; el gateway del servidor es el límite de las acciones. Esta separación tiene un nombre fuera de OpenBot, porque el bucle, las definiciones de herramientas, las comprobaciones de permisos y el estado de la sesión forman en conjunto el arnés que envuelve a un modelo, y este gateway es la parte de permisos de ese arnés.

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 es más importante que la sintaxis de las reglas. Si falta la política, no se permite nada, y una regla defectuosa 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 dejarlo actuar sin restricciones sobre sus cuentas. Esta capa controla lo que hace un bot, no lo que lee. Por ello, una página que contenga instrucciones dirigidas al agente sigue siendo un problema separado. Es la misma superficie de prompt injection que asume cuando entrega a un agente resultados de su propia instancia de SearXNG.

El registro de auditoría reside 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é recursos de RAM y disco consume un bot

El proyecto publica cifras medidas para un solo bot en arm64. Esos son los únicos datos de dimensionamiento que proporciona OpenBot. Describen un bot en una arquitectura concreta, así que deben tomarse como punto de partida y 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
  }
]

El uso máximo de memoria medido 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 aumente su consumo 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: alcanza 0.06 de un núcleo en el extremo superior del intervalo medido. Por tanto, la CPU no es el recurso que determina el dimensionamiento. El disco sí. 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.

Nada de esto indica cuánto consumen varios bots en conjunto, y el proyecto no publica ninguna cifra al respecto. Un mínimo documentado es el valor que un proyecto considera razonable publicar, no necesariamente el que alguien haya observado bajo carga. Por eso elegir entre PhotoPrism e Immich depende de sus mínimos de RAM medidos y no de los publicados. Mida su propia instalación. Inicie un bot, asígnele una tarea real con una página abierta y supervise el contenedor mientras trabaja.

docker stats --no-stream
free -m

Tome la columna MEM USAGE del contenedor del bot como valor por bot. Añada la carga del gateway y PostgreSQL. Después, multiplique el valor por bot por el número de bots que espera tener activos al mismo tiempo. Un bot inactivo sigue manteniendo un proceso del navegador, por lo que el multiplicador se aplica a los bots existentes y no sólo a los que están ocupados. El cálculo es el mismo que se usa para dimensionar la RAM y la CPU de una VPS para un agente de programación. La parte relacionada con el navegador se explica en ejecutar un navegador sin interfaz para agentes en una 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. Esto evita el bloqueo que se produce en hosts con un /dev/shm pequeño y traslada la presión al sistema de archivos raíz. Es otra razón por la que el disco recomendado es más grande que la imagen.

¿Cómo se aloja OpenBot en un VPS?

Necesita Docker, Bun 1.3 o posterior, un proyecto de CopilotKit Intelligence y una clave de API del modelo. La documentación de desarrollo también requiere 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

Después, instale e inicie los servicios.

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 indica que la aplicación está atendiendo peticiones. El segundo comando muestra en qué direcciones están asociados esos puertos. Esa es la información relevante 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 cualquier sistema con una ruta de red hasta el servidor puede acceder a él.

La imagen de contenedor única

La documentación de despliegue también incluye una imagen única 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 durante el arranque. El volumen con nombre conserva el historial de auditoría entre despliegues. Sin ese volumen, 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 aún no existe.

Ejecute las migraciones como un paso del lanzamiento 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 y las plataformas serverless no lo proporcionan. Sin el supervisor, todos los bots comparten un navegador y, por tanto, las mismas credenciales. Esto elimina el aislamiento que justificaba ejecutar contenedores separados para cada 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 esta limitación. Un proceso que pueda comunicarse con el socket de Docker puede iniciar un contenedor privilegiado. En la práctica, tiene privilegios de root sobre el host. Por eso conviene mantener OpenBot en una máquina independiente, siguiendo el mismo criterio que asignar una VM desechable a los agentes de programación.

Por qué OPENBOT_SINGLE_USER sólo sirve para un portátil

.env.example se distribuye con OPENBOT_SINGLE_USER=true. Este ajuste acepta todas las solicitudes como si fueran 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, vincula todos los puertos a 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 en tu propio navegador. Esto se considera un contexto seguro, por lo que funcionan las cookies de inicio de sesión y 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 establecido en 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 añades cuentas porque cada persona del equipo quiere tener su propio agente y no su propio navegador, OneCLI está diseñado desde el principio para ese modelo, con un agente aislado en un sandbox por persona y las claves de los modelos almacenadas en una única gateway.

Si se puede acceder a la aplicación mediante un nombre público, coloca TLS (seguridad de la capa de transporte) delante de ella. Una página servida mediante http:// sin cifrado, salvo en localhost, no es un contexto seguro. Por tanto, las cookies marcadas con Secure no se almacenan y el inicio de sesión falla de una forma que parece un error de OpenBot.

Filtre los puertos de nivel inferior

La propia nota de seguridad de OpenBot indica que los endpoints de los servicios de nivel inferior 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 único 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 creen 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 gestiona 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 con 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. Esta trampa no es exclusiva de OpenBot. Por tanto, realiza la misma comprobación en todos los demás contenedores que hayas publicado en el equipo, incluido el que sirva una biblioteca de Jellyfin reconstruida como un videoclub de los años 90.

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 al iniciar, y los cuatro deben estar presentes al mismo tiempo o el inicio falla. Hay un plan gratuito disponible desde agosto de 2026, e Intelligence también se puede alojar de forma autónoma, por lo que es posible 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, y OPENAI_BASE_URL dirige la ruta de OpenAI a cualquier endpoint compatible. Esto permite ejecutar Ollama en un VPS para alojar un LLM si quiere que los tokens permanezcan en su propio hardware. El control del navegador exige mucho del modelo, por lo que debe probar un modelo local con una tarea real antes de adoptarlo.

Ejecute una sola réplica por ahora

La 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 de 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 se traslade a la base de datos. Hasta entonces, escale OpenBot aumentando los recursos del servidor, no añadiendo servidores. El aislamiento entre bots sigue proporcionando los contenedores independientes de cada bot, del mismo modo que los entornos aislados de agentes autohospedados mantienen los errores de un agente separados 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 servicio silenciosamente. Lea el primer error, corrija ese campo y vuelva a iniciar el servicio.

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. Eso no constituye un contexto seguro, por lo que se descarta la cookie Secure. Coloque TLS delante de la aplicación o use el túnel SSH para que el navegador vea localhost.

Los bots comparten credenciales que esperaba que fueran independientes. El supervisor no se está ejecutando, por lo que no existe un navegador 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 conserva computer.help_requested, usted toma el control en la pantalla activa y la transferencia queda registrada en ambos lados.

FAQ

¿Es seguro dejar OPENBOT_SINGLE_USER activado en un despliegue de VPS?

Sólo cuando no se puede acceder a la 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 el despliegue, las 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 pico 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, lea la memoria de ese contenedor en docker stats, sume la gateway y la base de datos y multiplique el resultado por el número de bots que espera tener activos 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 arranca si no se configuran la URL de la API de Intelligence, la URL WebSocket de la gateway, la clave de API y el token de licencia. En agosto de 2026 hay un plan gratuito disponible, y Intelligence puede alojarse por cuenta propia, por lo que es posible eliminar la dependencia alojada 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 significa que todos los bots tienen la sesión iniciada en esa cuenta. Los contenedores independientes por bot proporcionan a cada colaborador 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 requiere.

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

Ninguno de los puertos de nivel inferior. 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 recomienda mantenerlos inaccesibles de todos modos. 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.