Hosting
Fly.io
Objetivo: Gateway de OpenClaw ejecutándose en una máquina de Fly.io con almacenamiento persistente, HTTPS automático y acceso a Discord/canales.
Qué se necesita
- CLI flyctl instalada
- Cuenta de Fly.io (el nivel gratuito funciona)
- Autenticación del modelo: clave de API del proveedor de modelos elegido
- Credenciales del canal: token de bot de Discord, token de Telegram, etc.
Ruta rápida para principiantes
- Clonar el repositorio y personalizar
fly.toml - Crear la aplicación y el volumen, y establecer los secretos
- Desplegar con
fly deploy - Acceder mediante SSH para crear la configuración o usar la interfaz de control
Crear la aplicación de Fly
git clone https://github.com/openclaw/openclaw.gitcd openclaw # elija su propio nombrefly apps create my-openclaw # 1 GB suele ser suficientefly volumes create openclaw_data --size 1 --region iadElija una región cercana. Opciones habituales: lhr (Londres), iad (Virginia), sjc (San José).
Configurar fly.toml
Edite fly.toml para que coincida con el nombre y los requisitos de la aplicación. El archivo fly.toml incluido en el repositorio es la plantilla pública que se muestra a continuación; deploy/fly.private.toml es la variante reforzada sin IP pública (consulte Despliegue privado).
app = "my-openclaw" # nombre de la aplicaciónprimary_region = "iad" [build] dockerfile = "Dockerfile" [env] NODE_ENV = "production" OPENCLAW_PREFER_PNPM = "1" OPENCLAW_STATE_DIR = "/data" NODE_OPTIONS = "--max-old-space-size=1536" [processes] app = "node dist/index.js gateway --allow-unconfigured --port 3000 --bind lan" [http_service] internal_port = 3000 force_https = true auto_stop_machines = false auto_start_machines = true min_machines_running = 1 processes = ["app"] [[vm]] size = "shared-cpu-2x" memory = "2048mb" [mounts] source = "openclaw_data" destination = "/data"El punto de entrada de la imagen Docker de OpenClaw es tini, que ejecuta node openclaw.mjs gateway de forma predeterminada. El [processes] de Fly sustituye el CMD de Docker (aquí ejecuta directamente node dist/index.js gateway ..., el mismo punto de entrada compilado) sin modificar ENTRYPOINT, por lo que el proceso continúa ejecutándose bajo tini.
Configuración clave:
| Configuración | Motivo |
|---|---|
--bind lan |
Se enlaza a 0.0.0.0 para que el proxy de Fly pueda acceder al Gateway |
--allow-unconfigured |
Se inicia sin un archivo de configuración (se crea después) |
internal_port = 3000 |
Debe coincidir con --port 3000 (o OPENCLAW_GATEWAY_PORT) para las comprobaciones de estado de Fly |
memory = "2048mb" |
512 MB es insuficiente; se recomiendan 2 GB |
OPENCLAW_STATE_DIR = "/data" |
Conserva el estado en el volumen |
Establecer los secretos
# obligatorio: token de autenticación del Gateway para el enlace fuera de loopbackfly secrets set OPENCLAW_GATEWAY_TOKEN=$(openssl rand -hex 32) # claves de API de los proveedores de modelosfly secrets set ANTHROPIC_API_KEY=example-anthropic-key-not-real # opcional: otros proveedoresfly secrets set OPENAI_API_KEY=example-openai-key-not-realfly secrets set GOOGLE_API_KEY=... # tokens de canalesfly secrets set DISCORD_BOT_TOKEN=example-discord-bot-tokenLos enlaces fuera de loopback (--bind lan) requieren una ruta válida de autenticación del Gateway. Este ejemplo usa OPENCLAW_GATEWAY_TOKEN, pero gateway.auth.password o un despliegue de proxy de confianza fuera de loopback correctamente configurado también satisfacen el requisito. Consulte Gestión de secretos para conocer el contrato de SecretRef.
Trate estos tokens como contraseñas. Es preferible usar variables de entorno/fly secrets en lugar del archivo de configuración para las claves de API y los tokens, de modo que los secretos no se incluyan en openclaw.json.
Desplegar
fly deployEl primer despliegue compila la imagen Docker. Verifique el resultado después del despliegue:
fly statusfly logsLos registros de inicio del Gateway muestran gateway ready una vez que el servidor HTTP/WebSocket está activo. La comprobación de estado propia de Fly supervisa internal_port = 3000 según fly.toml; además, la directiva Docker HEALTHCHECK de la imagen consulta /healthz en su puerto predeterminado 18789, que no se utiliza aquí porque este despliegue sustituye el puerto del Gateway por --port 3000.
Crear el archivo de configuración
Acceda a la máquina mediante SSH para crear una configuración adecuada:
fly ssh consolemkdir -p /datacat > /data/openclaw.json << 'EOF'{ "agents": { "defaults": { "model": { "primary": "anthropic/claude-opus-4-6", "fallbacks": ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4"] }, "maxConcurrent": 4 }, "list": [ { "id": "main", "default": true } ] }, "auth": { "profiles": { "anthropic:default": { "mode": "token", "provider": "anthropic" }, "openai:default": { "mode": "token", "provider": "openai" } } }, "bindings": [ { "agentId": "main", "match": { "channel": "discord" } } ], "channels": { "discord": { "enabled": true, "groupPolicy": "allowlist", "guilds": { "YOUR_GUILD_ID": { "channels": { "general": { "allow": true } }, "requireMention": false } } } }, "gateway": { "mode": "local", "bind": "auto", "controlUi": { "allowedOrigins": [ "https://my-openclaw.fly.dev", "http://localhost:3000", "http://127.0.0.1:3000" ] } }, "meta": {}}EOFCon OPENCLAW_STATE_DIR=/data, la ruta de configuración es /data/openclaw.json.
Sustituya https://my-openclaw.fly.dev por el origen real de la aplicación de Fly. El inicio del Gateway genera los orígenes locales de la interfaz de control a partir de los valores de tiempo de ejecución --bind y --port, de modo que el primer arranque pueda continuar antes de que exista la configuración; sin embargo, el acceso desde el navegador a través de Fly sigue requiriendo que el origen HTTPS exacto aparezca en gateway.controlUi.allowedOrigins.
El token de Discord puede proceder de cualquiera de estas fuentes:
- Variable de entorno
DISCORD_BOT_TOKEN(recomendada para secretos); no es necesario añadirla a la configuración, ya que el Gateway la lee automáticamente - Archivo de configuración
channels.discord.token
Reinicie para aplicar los cambios:
exitfly machine restart <machine-id>Acceder al Gateway
Interfaz de control
fly openTambién puede visitar https://my-openclaw.fly.dev/.
Autentíquese con el secreto compartido configurado: el token del Gateway de OPENCLAW_GATEWAY_TOKEN o la contraseña si cambió a la autenticación mediante contraseña.
Registros
fly logs # registros en directofly logs --no-tail # registros recientesConsola SSH
fly ssh consoleSolución de problemas
«La aplicación no escucha en la dirección esperada»
El Gateway se enlaza a 127.0.0.1 en lugar de 0.0.0.0.
Solución: añada --bind lan al comando del proceso en fly.toml.
Las comprobaciones de estado fallan o se rechaza la conexión
Fly no puede acceder al Gateway en el puerto configurado.
Solución: asegúrese de que internal_port coincida con el puerto del Gateway (--port 3000 o OPENCLAW_GATEWAY_PORT=3000).
Problemas de memoria/OOM
El contenedor continúa reiniciándose o el sistema finaliza su proceso. Indicadores: SIGABRT, v8::internal::Runtime_AllocateInYoungGeneration o reinicios silenciosos.
Solución: aumente la memoria en fly.toml:
[[vm]] memory = "2048mb"También puede actualizar una máquina existente:
fly machine update <machine-id> --vm-memory 2048 -y512 MB es insuficiente. 1 GB puede funcionar, pero podría producirse un error OOM bajo carga o con registros detallados. Se recomiendan 2 GB.
Problemas de bloqueo del Gateway
El Gateway se niega a iniciarse con errores de «ya está en ejecución» después de reiniciar un contenedor.
Los archivos de bloqueo del entorno de ejecución se encuentran en <tmpdir>/openclaw-<uid>/gateway.<hash>.lock
y gateway.state.<hash>.lock (Linux:
/tmp/openclaw-<uid>/gateway.*.lock), no en el volumen persistente /data, por lo que
un reinicio completo del contenedor normalmente los elimina junto con el resto del
sistema de archivos del contenedor. Si un bloqueo persiste (por ejemplo, un fly machine restart
que conserva el sistema de archivos del contenedor) e impide el inicio, elimínelo
manualmente:
fly ssh console --command "rm -f /tmp/openclaw-*/gateway.*.lock"fly machine restart <machine-id>No se lee la configuración
--allow-unconfigured solo omite la protección de inicio. No crea ni repara /data/openclaw.json, así que asegúrese de que la configuración real exista e incluya "gateway": { "mode": "local" } para iniciar normalmente un Gateway local.
Compruebe que la configuración exista:
fly ssh console --command "cat /data/openclaw.json"Escritura de la configuración mediante SSH
fly ssh console -C no admite la redirección del shell. Para escribir un archivo de configuración:
# echo + tee (canalización del equipo local al remoto)echo '{"your":"config"}' | fly ssh console -C "tee /data/openclaw.json" # o sftpfly sftp shell> put /local/path/config.json /data/openclaw.jsonfly sftp puede fallar si el archivo ya existe; elimínelo primero:
fly ssh console --command "rm /data/openclaw.json"El estado no persiste
Si se pierden los perfiles de autenticación, el estado del canal/proveedor o las sesiones después de reiniciar, el directorio de estado está escribiendo en el sistema de archivos del contenedor en lugar de hacerlo en el volumen.
Solución: asegúrese de que OPENCLAW_STATE_DIR=/data esté definido en fly.toml y vuelva a desplegar.
Actualización
git pullfly deployfly statusfly logsgit pull + fly deploy es la ruta supervisada en este caso: recompila la imagen a partir del Dockerfile, por lo que la versión de la CLI/del Gateway, la imagen base del sistema operativo y cualquier cambio en el Dockerfile se actualizan conjuntamente. Ejecutar openclaw update dentro del contenedor no es la misma operación, ya que la imagen se distribuye como un árbol dist/ compilado con Docker, sin un repositorio .git y sin una instalación global administrada por npm que pueda detectar; consulte Actualización para conocer ese flujo en instalaciones de tipo VM.
Actualización del comando de la máquina
Para cambiar el comando de inicio sin realizar un despliegue completo:
fly machines listfly machine update <machine-id> --command "node dist/index.js gateway --port 3000 --bind lan" -y # o con un aumento de memoriafly machine update <machine-id> --vm-memory 2048 --command "node dist/index.js gateway --port 3000 --bind lan" -yUn fly deploy posterior restablece el comando de la máquina al valor definido en fly.toml; vuelva a aplicar los cambios manuales después de volver a desplegar.
Despliegue privado (reforzado)
De forma predeterminada, Fly asigna IP públicas, por lo que el Gateway está disponible en https://your-app.fly.dev y puede ser descubierto por escáneres de Internet (Shodan, Censys, etc.).
Use deploy/fly.private.toml para un despliegue reforzado sin IP pública: omite [http_service], por lo que no se asigna ninguna entrada pública.
Cuándo usar un despliegue privado
- Solo llamadas/mensajes salientes (sin webhooks entrantes)
- Los túneles de ngrok o Tailscale gestionan cualquier devolución de llamada de Webhook
- Se accede al Gateway mediante SSH, proxy o WireGuard en lugar de un navegador
- El despliegue debe permanecer oculto para los escáneres de Internet
Configuración
fly deploy -c deploy/fly.private.tomlTambién puede convertir un despliegue existente:
# mostrar las IP actualesfly ips list -a my-openclaw # liberar las IP públicasfly ips release <public-ipv4> -a my-openclawfly ips release <public-ipv6> -a my-openclaw # cambiar a la configuración privada para que los despliegues futuros no vuelvan a asignar IP públicasfly deploy -c deploy/fly.private.toml # asignar una IPv6 exclusivamente privadafly ips allocate-v6 --private -a my-openclawDespués de esto, fly ips list debería mostrar solo una IP de tipo private:
VERSIÓN IP TIPO REGIÓNv6 fdaa:x:x:x:x::x privada globalAcceso a un despliegue privado
Opción 1: proxy local (la más sencilla)
fly proxy 3000:3000 -a my-openclaw# abrir http://localhost:3000 en un navegadorOpción 2: VPN WireGuard
fly wireguard create# importar en un cliente WireGuard y acceder mediante la IPv6 interna# ejemplo: http://[fdaa:x:x:x:x::x]:3000Opción 3: solo SSH
fly ssh console -a my-openclawWebhooks con un despliegue privado
Para devoluciones de llamada de Webhook (Twilio, Telnyx, etc.) sin exposición pública:
- túnel de ngrok: ejecutar ngrok dentro del contenedor o como contenedor auxiliar
- Tailscale Funnel: exponer rutas específicas mediante Tailscale
- Solo saliente: algunos proveedores (Twilio) funcionan para llamadas salientes sin webhooks
Ejemplo de configuración de llamadas de voz con ngrok, en plugins.entries.voice-call.config:
{ plugins: { entries: { "voice-call": { enabled: true, config: { provider: "twilio", tunnel: { provider: "ngrok" }, webhookSecurity: { allowedHosts: ["example.ngrok.app"], }, }, }, }, },}El túnel de ngrok se ejecuta dentro del contenedor y proporciona una URL pública de Webhook sin exponer la propia aplicación de Fly. Establezca webhookSecurity.allowedHosts en el nombre de host del túnel para que se acepten las cabeceras de host reenviadas.
Consideraciones de seguridad
| Aspecto | Público | Privado |
|---|---|---|
| Escáneres de Internet | Detectable | Oculto |
| Ataques directos | Posibles | Bloqueados |
| Acceso a la interfaz de control | Navegador | Proxy/VPN |
| Entrega de webhooks | Directa | Mediante un túnel |
Notas
- Fly.io utiliza arquitectura x86; el Dockerfile es compatible tanto con x86 como con ARM.
- Para la incorporación de WhatsApp/Telegram, utilice
fly ssh console. - Los datos persistentes se almacenan en el volumen ubicado en
/data. - Signal requiere signal-cli (una CLI basada en Java) en la imagen; utilice una imagen personalizada y mantenga la memoria en 2 GB o más.
Coste
Con la configuración recomendada (shared-cpu-2x, 2 GB de RAM), el coste aproximado es de $10-15 al mes, según el uso; el nivel gratuito cubre parte de la asignación básica. Consulte los precios de Fly.io para conocer las tarifas actuales.
Siguientes pasos
- Configurar canales de mensajería: Canales
- Configurar el Gateway: Configuración del Gateway
- Mantener OpenClaw actualizado: Actualización