cover

Tu app en su propia caja: hosting paso a paso en EasyBits

author photo

Héctorbliss

@hectorbliss

Tienes una app de React Router que habla con un agente por ACP. Corre en tu Mac y quieres que corra en internet, con su URL, sin que tu laptop tenga que estar abierta. Este tutorial es esa mudanza, con los comandos que puedes copiar tal cual.

El resultado son dos cajas: una corre al agente, la otra corre a la app. Se hablan por WebSocket.

Diagrama: de tu Mac sale un JSON con la URL del repo; la caja clona, buildea y arranca; su URL pública habla con la caja del agente por ACP

Lo que necesitas

  • Una API key de EasyBits (panel → Ajustes → API keys).
  • El agente ya corriendo en su propia caja, con su endpoint wss://…/acp y su secreto. Ese paso está contado en Cómo correr tu agente de código en una microVM y conectarlo a VS Code.
  • El repo de tu app en GitHub, público o con token.
  • Que tu app arranque con un comando y escuche en un puerto. Nada más.

Las variables

Todo lo demás usa estas dos. Cópialas primero y ajusta la llave:

1. Lanzar

Una llamada provisiona la máquina, clona el repo adentro, buildea, arranca y expone HTTPS:

La respuesta trae lo que vas a usar en los pasos siguientes:

Guarda el id de la máquina:

Tu Mac mandó un JSON con la URL del repo. El git clone, el npm ci y el build ocurren dentro de la caja, sobre Linux. Un node_modules compilado en macOS no sobrevive el viaje, y por eso nunca se sube.

Con tier: "micro" (1 vCPU, 1 GB) el build de esta app tardó 6 segundos y bajó 375 paquetes. El nano de 256 MB se queda sin memoria a medio build.

2. Los secretos, al vault

Si intentas pasar tus llaves en el campo env del launch, la API te frena:

El env del runspec viaja dentro de cada release, así que ahí sólo van cosas públicas. Los secretos se cargan aparte, en un objeto plano de NOMBRE: valor:

Responde con los nombres que quedaron registrados:

Los valores se guardan cifrados y se materializan sólo dentro de la máquina, al buildear y al arrancar. Puedes listar los nombres cuando quieras; los valores no se recuperan por API, ni siquiera siendo el dueño.

La pantalla de Ajustes de la app hosteada, mostrando el endpoint ACP, el directorio de trabajo y la caja del agente

3. Redesplegar para que los tome

Los secretos se inyectan al arrancar, así que hay que publicar un release nuevo. El mismo endpoint, ahora con sandboxId para decir a qué máquina va:

Sube a "version": 2. Cada deploy es un release; el anterior queda disponible.

4. Verificar

Un exitCode: 0 dice que el arranque no reventó, no que el sitio conteste. Eso se comprueba con un GET:

Hasta que salga 200, la app no está publicada.

La app corriendo en su URL pública, con la lista de conversaciones y el input vacío

Tu propio dominio

La URL …sandboxes.easybits.cloud sirve para trabajar, no para presumir. Para colgar un dominio tuyo, pásalo en el mismo launch:

La respuesta trae domain.dns: ese es el registro exacto que hay que crear con tu proveedor. Una vez que propague, tu app responde en las dos direcciones.

Cuando algo falla

El log de la app, antes de reintentar nada:

Dos errores que vas a encontrar, con su arreglo:

node: .env: not found. El npm start de muchos proyectos es node --env-file=.env server.js. Ese archivo está en .gitignore, así que no llega a la caja. En producción las variables ya vienen del vault, así que el startCommand es node server.js a secas.

upstream unreachable / "nada escucha en el puerto 3000". Declaraste 3000 y tu server escucha en otro. En esta app el default era process.env.PORT ?? 4000. Cámbialo a 3000 en el código o declara "port": 4000 en el launch; lo que importa es que coincidan.

Si un release quedó peor que el anterior, vuelves atrás sin rebuildear:

La prueba de fuego

Abre la URL y pídele algo al agente. Si los secretos llegaron, la app despierta la otra caja, corre la herramienta y te devuelve el resultado con su costo:

La app hosteada respondiendo: corrió node --version en la caja del agente y contestó v22.22.3, con el conteo de tokens

La caja del agente es la del post anterior: la que levantamos con goose escuchando ACP en 0.0.0.0. Ahí quedó lista para que se conectara VS Code; hoy quien se conecta es una webapp con su propia URL.

Cada caja vive por su lado. La del agente se duerme a los 15 minutos sin actividad y despierta cuando llega el siguiente mensaje; la de la app se queda escuchando siempre, porque alguien puede abrir la URL en cualquier momento.

Este recorrido es el cierre de la segunda sesión del taller de Sistemas Agénticos, donde construimos la interfaz completa: la tarjeta que muestra qué comando corrió el agente, el envío de imágenes y este deploy. Si te interesa el tema, el taller vive aquí.

Abrazo. Blissmo. 🤓

meta cover

Claude Code vs GitHub Copilot vs Cursor: ¿Cuál Elegir?

Checa este otro Post

meta cover

Aclarando las confusiones: any vs unknown en TypeScript

Checa este otro Post

¡Nuevo curso!

Animaciones web con React + Motion 🧙🏻