SSD Nodes Learn Hosting plans →
Guías Matt ConnorPor Matt Connor

Cómo alojar sandboxd en un VPS con Docker

Instale sandboxd en su VPS con una versión fijada, claves de modelo y HTTPS. Conozca los mínimos de RAM y disco y cómo limpiar sandboxes obsoletos.

Qué es sandboxd y qué obtiene al ejecutarlo por su cuenta

Para alojar sandboxd por su cuenta necesita un servidor Linux con Docker y un nombre de dominio. Envía una instrucción, un agente de programación crea una aplicación real dentro de un contenedor aislado y la aplicación queda disponible en su propia URL de vista previa. Los generadores de aplicaciones a partir de instrucciones son la categoría alojada más visible de 2026, y sandboxd es la opción que se ejecuta en su VPS, bajo la licencia MIT, con el código generado almacenado en su propio disco.

El diseño es pequeño de forma intencionada. Un plano de control escrito en Go controla Docker, Traefik v3 enruta cada nombre de host de vista previa, SQLite almacena el estado y cada aplicación se ejecuta dentro de un contenedor. No hay Kubernetes ni un servidor de base de datos independiente. Por eso puede ejecutarse en un equipo con 2 vCPU.

Cuatro objetos componen todo el modelo. Una app es el proyecto persistente. Contiene su nombre, sus metadatos de git y sus secretos. Un sandbox es el contenedor de Docker en el que se ejecuta la app, y una app apunta a un sandbox cada vez. Un workspace son los archivos de la app. Se almacenan en el host y sobreviven al contenedor. Una task es una instrucción entregada al agente dentro del sandbox. Detener un sandbox libera memoria y conserva los archivos. Destruirlo elimina el contenedor, y la app puede iniciar uno nuevo.

¿En qué se diferencia sandboxd de Dify y OpenHands?

Estos tres proyectos se confunden porque todos ejecutan un LLM (modelo de lenguaje grande) en el servidor, pero generan resultados diferentes. Dify crea aplicaciones basadas en LLM: interfaces de chat, canalizaciones de recuperación y flujos de trabajo que llaman a un modelo cada vez que alguien los utiliza. El modelo forma parte del producto final. OpenHands trabaja con un repositorio existente: se le indica el código, lee archivos, ejecuta comandos y propone cambios. sandboxd parte de cero. Crea la estructura de un proyecto a partir de un preset, lo compila en un contenedor nuevo y proporciona una URL para consultarlo. El resultado es una aplicación React o FastAPI normal que no necesita ningún modelo para ejecutarse.

Por tanto, debe elegir según el resultado que necesite. sandboxd sirve para empezar con una frase y conservar después el código. Los otros dos sirven cuando el repositorio o el producto basado en modelos ya existen.

La otra diferencia es la antigüedad, y es el aspecto que debe valorar antes de crear algo real sobre esta base.

GráficoGitHub stars and forks, read from the GitHub API on 4 August 2026
Los datos de este gráfico
[
  {
    "tool": "sandboxd",
    "github_stars": "875",
    "forks": "50"
  },
  {
    "tool": "OpenHands",
    "github_stars": "83,091",
    "forks": "10,711"
  },
  {
    "tool": "Dify",
    "github_stars": "151,320",
    "forks": "23,886"
  }
]

sandboxd tiene 875 estrellas, frente a 83,091 de OpenHands y 151,320 de Dify. El repositorio se creó el 3 de junio de 2026, por lo que tiene dos meses en agosto de 2026, mientras que OpenHands se remonta a marzo de 2024 y Dify a abril de 2023. La versión v0.1.0 se publicó el 6 de junio de 2026 y la v0.3.6, el 1 de agosto de 2026. El proyecto se considera beta y advierte que las versiones 0.x pueden romper la compatibilidad. Interprete esas cifras como un indicador del riesgo asociado a las dependencias, no como una evaluación de la calidad: un proyecto con dos meses de antigüedad sólo ha tenido dos meses para que otras personas encuentren sus errores.

Qué necesita el servidor y qué falla cuando se queda corto

El proyecto indica que 2 vCPU y 4 GB de RAM bastan para empezar. Esto es correcto para el plano de control y un sandbox pequeño, pero no basta para que dos personas compilen al mismo tiempo. Presupueste la memoria por componentes. Traefik y el plano de control de Go consumen poco. Cada sandbox en ejecución contiene una cadena de herramientas completa de Node o Python, y el consumo máximo se alcanza durante un npm install seguido de una compilación de producción. Planifique 8 GB para un equipo que mantendrá varias aplicaciones activas y considere la swap una red de seguridad, no capacidad disponible, porque una compilación que usa swap tarda minutos en lugar de segundos.

Cuando se agota la memoria, se producen dos fallos distintos que no se parecen. Dentro de un sandbox, el contenedor alcanza el límite estricto de --memory que establece sandboxd y el kernel mata el proceso más grande. La compilación falla sin que el agente muestre un mensaje útil. docker ps -a muestra el código de salida 137 de ese contenedor y docker inspect sobre él informa de "OOMKilled": true. Una compilación de Node que muere de esta forma suele mostrar primero JavaScript heap out of memory.

El segundo fallo ocurre en el host. sandboxd ejecuta un recolector de procesos bajo presión que detiene los sandboxes cuando queda poca memoria en el host. Por eso, en un equipo pequeño, un sandbox puede desaparecer mientras observa su vista previa. Los archivos están a salvo y la siguiente petición a la URL de vista previa lo reactiva, pero una tarea que estaba ejecutándose cuando se detuvo el contenedor no se reanuda.

El disco es el problema menos visible. Cada aplicación mantiene su propio espacio de trabajo en el host, y un proyecto de JavaScript contiene un árbol node_modules que puede ocupar cientos de megabytes. Diez aplicaciones ocupan varios gigabytes de dependencias antes de contar las imágenes. Empiece con 40 GB y vigílelo:

docker system df
sudo du -sh /var/lib/sandboxed/workspaces

En v0.3.6, la versión fijada en esta guía, el directorio de datos predeterminado es /var/lib/sandboxed, escrito con el e adicional. Si escribe /var/lib/sandboxd allí, no obtendrá nada y perderá cinco minutos intentando entenderlo. Esto cambió en v0.3.9 (25 August 2026). Los instaladores más recientes colocan las instalaciones nuevas en /var/lib/sandboxd y conservan /var/lib/sandboxed sólo para una instalación que ya se encuentre allí. En un equipo configurado por primera vez con una versión posterior, use la ruta sin e en todos los comandos siguientes.

Instalar una versión fijada de sandboxd

Docker Engine con el plugin Compose, además de git, debe estar instalado primero en el servidor. Instalar Docker en un VPS cubre esa parte.

docker compose version
git --version

Ambos comandos deben mostrar una versión. docker: 'compose' is not a docker command indica que falta el plugin Compose v2. El instalador prefiere el plugin, pero usa como alternativa un binario independiente docker-compose si hay uno instalado. Sólo se detiene con Docker Compose not found cuando no hay ninguno de los dos. Los comandos de esta guía usan docker compose, por lo que instalar el plugin es la solución más sencilla.

El instalador es un script de shell que se descarga por la red. Léalo antes de ejecutarlo y fije la versión.

curl -fsSL https://raw.githubusercontent.com/tastyeffectco/sandboxd/v0.3.6/install.sh -o install-sandboxd.sh
less install-sandboxd.sh
SANDBOXD_REF=v0.3.6 bash install-sandboxd.sh

SANDBOXD_REF es la referencia de git que el instalador extrae en $HOME/.sandboxd/src y, de forma predeterminada, usa main. Si no la define, la instalación incluirá todo lo que se haya fusionado esa mañana. Esto es importante en un proyecto que publicó seis versiones sólo en julio de 2026. Fije la versión y actualícela de forma intencionada después de leer el registro de cambios. A fecha del 12 de octubre de 2026, la versión más reciente es v0.3.22, dieciséis versiones posterior a la v0.3.6 fijada aquí.

El script clona el código fuente, compila las imágenes, inicia la pila con docker compose up -d y muestra al final la URL de la consola y un token de API. Guarde ese token en un lugar seguro. Es la credencial de una API que controla Docker como root.

curl http://127.0.0.1:9090/healthz

Esto muestra ok cuando el plano de control está activo. Si no muestra nada, la pila no se inició. Ejecute docker compose ps desde ~/.sandboxd/src para comprobar qué servicio está detenido y, después, docker compose logs sandboxd para ver la causa.

Acceso a la consola en un equipo remoto

La consola se publica mediante Traefik en HTTP_PORT, que de forma predeterminada es 80, con el nombre de host http://console.localhost. Traefik enruta según el nombre de host, por lo que introducir la dirección IP del servidor en el navegador no coincide con ninguna regla y devuelve un 404. Hasta que configure un dominio real, redirija el puerto y conserve el nombre de host:

ssh -L 8080:127.0.0.1:80 you@your-vps

A continuación, abra http://console.localhost:8080 en su portátil. En Linux y macOS, cualquier nombre que termine en .localhost se resuelve en 127.0.0.1, por lo que la solicitud atraviesa el túnel con la cabecera Host correcta. Configure la contraseña de la consola en la primera visita.

Proporcione un modelo al agente

La imagen base incluye dos agentes de programación: OpenCode y Claude Code. SANDBOXD_DEFAULT_AGENT decide cuál ejecuta una tarea que no especifica ninguno y, de forma predeterminada, usa opencode. Sin ninguna clave conectada, las tareas se ejecutan con los modelos gratuitos sin clave de OpenCode Zen. Así, la primera compilación no tiene ningún coste y puede probar todo el flujo antes de gastar dinero.

Conecte su propia clave cuando necesite un modelo más potente. Las claves se envían al plano de control, nunca al sandbox: se almacenan cifradas en el directorio de datos y un proxy de credenciales las inyecta durante la comunicación. Por tanto, ni el agente ni el código que escribe pueden leerlas.

export API=http://127.0.0.1:9090
export SANDBOXD_TOKEN=sk_...                       # printed by the installer
export AUTH="Authorization: Bearer $SANDBOXD_TOKEN"

curl -s -XPOST $API/v1/agents/claude-code/api-key -H "$AUTH" \
  -H 'content-type: application/json' \
  -d '{"api_key":"sk-ant-..."}'

La consola ofrece la misma configuración en Settings, AI Agents, incluido un flujo guiado de OAuth si quiere usar una suscripción de Claude en lugar de una clave de API. El modelo predeterminado de cada agente se configura en el mismo panel, y una tarea concreta puede sustituirlo.

Crear una aplicación pequeña de principio a fin

Cree la aplicación, inicie su sandbox y envíe un prompt. Los identificadores se devuelven como JSON, y el inicio rápido los extrae con sed, por lo que no necesita tener jq instalado.

APP=$(curl -s -XPOST $API/v1/apps -H "$AUTH" \
  -H 'content-type: application/json' \
  -d '{"name":"todo","runtime_preset":"react-vite"}' \
  | sed -E 's/.*"id":"([^"]+)".*/\1/')

SB=$(curl -s -XPOST $API/v1/apps/$APP/sandbox -H "$AUTH" \
  -H 'content-type: application/json' -d '{"ports":[3000]}' \
  | sed -E 's/.*"id":"([^"]+)".*/\1/')

echo "app=$APP sandbox=$SB"

Ambas variables deben contener un identificador. Un $SB vacío significa que el sandbox nunca se inició. La causa habitual es que la imagen base todavía se está compilando o que el host se ha quedado sin memoria. Un 401 en lugar de un identificador significa que el bearer token no es válido.

curl -s -XPOST $API/v1/sandboxes/$SB/tasks -H "$AUTH" \
  -H 'content-type: application/json' \
  -d '{"prompt":"Add a todo list with a text input, an add button, and a delete button on each row. Keep the list in localStorage.","agent":"opencode"}'

La respuesta contiene un identificador de tarea. GET /v1/sandboxes/$SB/tasks/<task id> devuelve su resultado, y la ruta /events de la misma tarea es un flujo SSE (eventos enviados por el servidor) en tiempo real que muestra lo que hace el agente. La consola muestra el mismo flujo como un chat.

La aplicación estará disponible en http://s-<sandbox id>-3000.preview.localhost, donde 3000 es el puerto que solicitó. Si el sandbox estaba inactivo, la primera solicitud llega al catch-all de Traefik, sandboxd inicia el contenedor, espera a que el puerto responda y muestra una página breve de inicialización que se actualiza para cargar la aplicación. Una vista previa que nunca abandona esa página indica que el proceso dentro del sandbox no está escuchando en el puerto declarado en sandbox.yaml de la aplicación.

Publica las previsualizaciones en un dominio real con HTTPS

Cada sandbox obtiene su propio nombre de host, por lo que un único registro DNS comodín cubre todos. Apunta *.preview.yourdomain.com a la dirección IP del servidor mediante un registro A. Después, establece las variables de previsualización en .env dentro de ~/.sandboxd/src:

PREVIEW_DOMAIN=yourdomain.com
PREVIEW_ENTRYPOINT=websecure
PREVIEW_TLS=true
SANDBOXD_API_AUTH_DISABLED=false

Traefik necesita la configuración correspondiente: habilita el punto de entrada websecure en traefik/traefik.yml y añade un resolvedor de certificados. Usa el desafío DNS-01, porque un único certificado comodín cubre todos los nombres de host de las previsualizaciones. Con HTTP-01, cada sandbox nuevo necesitaría su propia emisión, y una tarde con mucha actividad de compilación puede alcanzar rápidamente los límites de tasa de Let's Encrypt. Certificados comodín mediante el desafío DNS-01 explica la configuración de DNS.

cd ~/.sandboxd/src
docker compose up -d

Las URL de previsualización serán https://s-<id>-3000.preview.yourdomain.com. Abre 80 y 443 en el firewall y deja 9090 cerrado al exterior: consulta reglas básicas del firewall ufw. Recuerda que cualquiera que adivine un nombre de host de previsualización puede cargar la aplicación, así que trata las previsualizaciones como públicas.

Si prefieres omitir por completo el dominio, DNS y los certificados, los mantenedores ahora ofrecen sandboxd Cloud. Proporciona a tu servidor una dirección HTTPS pública bajo sandboxd.io por 9.99 dólares por servidor al mes, o 4.99 con el descuento de lanzamiento, según los precios de octubre de 2026. Comprueba qué versión necesita antes de depender de ella fijando v0.3.6.

¿Dónde se guarda el código generado y se puede exportar?

En el host, dentro del directorio de datos. Cada espacio de trabajo es un directorio normal en /var/lib/sandboxed/workspaces/<id>/ en una instalación v0.3.6, montado mediante bind en el contenedor, y los archivos de la aplicación se encuentran en /home/sandbox/workspace/app dentro del entorno aislado. El estado del plano de control está en un único archivo SQLite en state/sandboxd.db, y las credenciales cifradas del agente están en agent-auth/. No se oculta nada en una capa del contenedor, por lo que una copia de seguridad consiste en copiar el directorio y ese archivo de base de datos. las copias de seguridad de restic en un VPS se encarga de ambos.

sudo ls /var/lib/sandboxed/workspaces
sudo du -sh /var/lib/sandboxed/workspaces/*

La exportación a Git está integrada, no añadida como un componente externo. La API expone el estado y las diferencias para su consulta, y después permite hacer commit y push:

curl -s $API/v1/apps/$APP/git/status -H "$AUTH"

curl -s -XPOST $API/v1/apps/$APP/git/commit -H "$AUTH" \
  -H 'content-type: application/json' \
  -d '{"message":"todo list, first pass"}'

curl -s -XPOST $API/v1/apps/$APP/git/push -H "$AUTH" \
  -H 'content-type: application/json' -d '{"branch":"todo-first-pass"}'

El push siempre se realiza a una rama nueva. Omita branch y se usará sandboxd/<slug>-<shortsha> de forma predeterminada. main, master y la rama desde la que importó se rechazan, por lo que debe hacer el merge en el lado remoto.

Un remoto privado necesita un personal access token, que se configura una sola vez en la consola, en Settings, Git credentials. Se almacena cifrado y permanece fuera del entorno aislado, por lo que el agente no puede leerlo ni hacer push con él sin que usted lo sepa. Haga push pronto y con frecuencia. Hasta entonces, el directorio del espacio de trabajo es la única copia del código, y DELETE /v1/apps/<id> lo elimina sin posibilidad de recuperación.

¿Cuántos tokens del modelo cuesta una compilación?

sandboxd no mide su gasto, por lo que la cifra relevante se encuentra en la consola de su proveedor. Los modelos gratuitos de OpenCode Zen no tienen coste y son más lentos y menos capaces que un modelo de pago. Esto se refleja en más rondas de corrección para cualquier aplicación que supere un ejemplo básico.

La factura depende de cómo funciona el bucle del agente. Cada turno vuelve a enviar el contexto que necesita, por lo que el coste depende del número de turnos, no del número de aplicaciones. Un prompt que produce el resultado esperado es barato. Quince rondas de «ahora corrija el espaciado» sobre un proyecto con cincuenta archivos no lo son, porque el contenido de los archivos se envía cada vez. Los tokens de entrada y salida se facturan de forma diferente, y el coste de un agente de programación por sesión ofrece un intervalo realista. Establezca un límite de gasto estricto en el proveedor antes de entregar las credenciales a un bucle que se ejecuta sin supervisión.

Limpieza de sandboxes obsoletos

El proceso de limpieza por inactividad detiene cualquier sandbox que haya estado inactivo durante más de SANDBOXD_IDLE_THRESHOLD_SECONDS, cuyo valor predeterminado es 2100 segundos, o 35 minutos. Esto libera la RAM y conserva los archivos. La siguiente solicitud a la URL de vista previa vuelve a activar el contenedor. Reduzca este valor en un servidor pequeño, porque 35 minutos de contenedores inactivos son 35 minutos de memoria que no puede utilizar.

Detener no equivale a eliminar. Aquí es donde los discos se llenan silenciosamente. Un sandbox detenido todavía conserva su espacio de trabajo y su contenedor. Eliminar el sandbox pero conservar la aplicación es un DELETE del sandbox, que elimina el contenedor y el espacio de trabajo. Eliminar la aplicación elimina todo de forma permanente.

curl -s -XPOST $API/v1/sandboxes/$SB/stop -H "$AUTH"     # frees RAM, keeps files
curl -s -XDELETE $API/v1/sandboxes/$SB -H "$AUTH"        # container and workspace gone
curl -s -XDELETE $API/v1/apps/$APP -H "$AUTH"            # app and everything under it

Después de varias semanas de pruebas, docker system df mostrará más espacio recuperable de imágenes del que esperaba, porque cada aplicación que descargó su propia cadena de herramientas dejó capas sin utilizar. docker image prune elimina las capas huérfanas. Compruebe primero GET /v1/apps, porque una imagen a la que todavía hace referencia un sandbox suspendido no es basura.

Qué ofrece y qué no ofrece el aislamiento del contenedor

Cada sandbox se ejecuta con un usuario sin privilegios, un sistema de archivos raíz de solo lectura, todas las capacidades de Linux eliminadas, no-new-privileges establecido, un límite de memoria y un límite de procesos. El proyecto reconoce claramente ese límite: un contenedor Linux con un kernel compartido ofrece un aislamiento sólido y una frontera de seguridad débil. Un error del kernel puede comprometer el host.

Hay dos aspectos que requieren medidas. La salida de red desde un sandbox está abierta en la compilación autoalojada, por lo que el código generado puede acceder a Internet, a la red local y a los endpoints de metadatos de la nube. Existe un subsistema de salida de nftables en el código fuente, pero está desactivado en la compilación portable de Docker Compose. Por tanto, los límites deben aplicarse mediante el firewall del host. Además, la API del plano de control equivale de hecho a root en el host porque controla el socket de Docker. De forma predeterminada, se enlaza a 127.0.0.1:9090, SANDBOXD_API_AUTH_DISABLED debe permanecer en false y nunca debe publicarse en Internet.

Si tiene previsto permitir que otras personas envíen prompts a su equipo, este modelo es demasiado débil por sí solo. El proyecto recomienda gVisor con SANDBOXD_RUNTIME=runsc, que coloca un kernel en espacio de usuario entre el sandbox y el host. Según las mediciones del propio proyecto, esto hace que las instalaciones de paquetes sean aproximadamente 1.7 veces más lentas y que las tareas con un uso intensivo de llamadas al sistema sean aproximadamente 4 veces más lentas. La opción más sólida es usar una máquina por tenant, que sigue el mismo razonamiento que ejecutar agentes de programación en una VM desechable.

¿Conviene crear proyectos sobre uno que tiene dos meses?

Para un servidor de desarrollo personal, sí, con las precauciones habituales: fija SANDBOXD_REF, haz una copia de seguridad del directorio de datos (/var/lib/sandboxed en v0.3.6, /var/lib/sandboxd en una instalación nueva de v0.3.9 o posterior) y envía cada aplicación que te importe a un repositorio remoto de git. Para cualquier aplicación que vaya a usar un cliente, espera a la versión 1.0 o reserva tiempo y presupuesto para corregir fallos, porque los mantenedores indican claramente que la API puede cambiar durante la serie 0.x. Los mantenedores también ofrecen una instalación gestionada: 199 dólares por la configuración y 79 dólares al mes por el servicio en octubre de 2026. Conviene tenerlo en cuenta al valorar si el proyecto tiene motivos para seguir existiendo.

El riesgo es tolerable por el resultado. sandboxd genera una aplicación normal en un repositorio git normal. Si el desarrollo del proyecto se detiene, conservas el código y sólo pierdes la capa envolvente. Es una situación mucho mejor que la de un generador alojado que controla tu proyecto. Para conocer la perspectiva general sobre qué merece un lugar en tu servidor este año, consulta qué merece la pena alojar por cuenta propia en 2026.

FAQ

¿Cuáles son las especificaciones mínimas del servidor para sandboxd?

El proyecto indica que 2 vCPU y 4 GB de RAM bastan para empezar. Esto cubre el plano de control, Traefik y un sandbox pequeño. Use 8 GB y 40 GB de disco si quiere mantener varias aplicaciones activas a la vez, porque cada sandbox en ejecución contiene una cadena de herramientas completa de Node o Python y cada espacio de trabajo conserva su propio árbol de dependencias en disco. Cuando al host le faltan recursos, el recolector de presión de sandboxd detiene sandboxes para liberar memoria. Además, el kernel termina una compilación que supera el límite de memoria de su contenedor: docker ps -a muestra el código de salida 137.

¿En qué se diferencia sandboxd de Dify u OpenHands?

Generan artefactos distintos. Dify crea aplicaciones que llaman a un modelo durante la ejecución, como interfaces de chat y canalizaciones de recuperación. OpenHands modifica un repositorio existente, ejecuta comandos y propone cambios en el código actual. sandboxd genera la estructura de un proyecto nuevo a partir de una instrucción, lo compila dentro de su propio contenedor y lo sirve en una URL de vista previa. El resultado es una aplicación web normal que no necesita un modelo para ejecutarse.

¿Dónde se guarda realmente el código que escribe el agente?

En el sistema de archivos del host, no dentro de una imagen de contenedor. Cada aplicación obtiene un directorio en /var/lib/sandboxed/workspaces/<id>/ en una instalación de v0.3.6 (/var/lib/sandboxd/workspaces/<id>/ en una instalación nueva de v0.3.9 o posterior). Ese directorio se monta mediante bind en su sandbox y los archivos aparecen en /home/sandbox/workspace/app dentro de él. El estado del plano de control es un único archivo SQLite en state/, dentro del mismo directorio de datos. Puede confirmar los cambios y hacer push a una rama nueva de un remoto git desde la pestaña Git de la consola o mediante los endpoints /v1/apps/<id>/git/commit y /git/push. El plano de control almacena cifrado el token para remotos privados, en lugar de entregárselo al sandbox.

¿Es seguro exponer sandboxd a Internet?

Exponga las URL de vista previa y la consola, pero nunca la API del plano de control. Esa API controla Docker en el host, por lo que equivale a root. Por ese motivo, se enlaza a 127.0.0.1:9090 de forma predeterminada. Los sandboxes también tienen salida de red abierta en la compilación autoalojada. Esto significa que el código escrito por el agente puede acceder a la red local y a los endpoints de metadatos de la nube. Añada reglas de firewall del host si el equipo tiene sistemas vecinos que deba proteger. Para instrucciones de personas en las que no confía, use un host por tenant en lugar de depender del límite del contenedor.

#sandboxd#ai-agents#self-hosted#app-builder#docker