Hosting

Fly.io

Objetivo: OpenClaw Gateway ejecutándose en una máquina de Fly.io con almacenamiento persistente, HTTPS automático y acceso a Discord/canales.

Qué necesitas

  • flyctl CLI instalada
  • Cuenta de Fly.io (el nivel gratuito funciona)
  • Autenticación del modelo: clave de API para el proveedor de modelo que elijas
  • Credenciales de canal: token de bot de Discord, token de Telegram, etc.

Ruta rápida para principiantes

  1. Clonar el repositorio → personalizar fly.toml
  2. Crear la app + volumen → configurar secretos
  3. Desplegar con fly deploy
  4. Entrar por SSH para crear la configuración o usar la UI de Control
  • Create the Fly app

    bash
    # Clone the repogit clone https://github.com/openclaw/openclaw.gitcd openclaw # Create a new Fly app (pick your own name)fly apps create my-openclaw # Create a persistent volume (1GB is usually enough)fly volumes create openclaw_data --size 1 --region iad

    Consejo: Elige una región cercana a ti. Opciones habituales: lhr (Londres), iad (Virginia), sjc (San José).

  • Configure fly.toml

    Edita fly.toml para que coincida con el nombre de tu app y tus requisitos.

    Nota de seguridad: La configuración predeterminada expone una URL pública. Para un despliegue reforzado sin IP pública, consulta Despliegue privado o usa deploy/fly.private.toml.

    toml
    app = "my-openclaw"  # Your app nameprimary_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"

    La imagen Docker de OpenClaw usa tini como punto de entrada. Los comandos de proceso de Fly reemplazan el CMD de Docker sin reemplazar el ENTRYPOINT, así que el proceso sigue ejecutándose bajo tini.

    Ajustes clave:

    Ajuste Por qué
    --bind lan Enlaza a 0.0.0.0 para que el proxy de Fly pueda llegar al gateway
    --allow-unconfigured Arranca sin archivo de configuración (lo crearás 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 demasiado poco; se recomiendan 2 GB
    OPENCLAW_STATE_DIR = "/data" Conserva el estado en el volumen
  • Set secrets

    bash
    # Required: Gateway token (for non-loopback binding)fly secrets set OPENCLAW_GATEWAY_TOKEN=$(openssl rand -hex 32) # Model provider API keysfly secrets set ANTHROPIC_API_KEY=example-anthropic-key-not-real # Optional: Other providersfly secrets set OPENAI_API_KEY=example-openai-key-not-realfly secrets set GOOGLE_API_KEY=... # Channel tokensfly secrets set DISCORD_BOT_TOKEN=example-discord-bot-token

    Notas:

    • Los enlaces que no son loopback (--bind lan) requieren una ruta de autenticación válida del gateway. Este ejemplo de Fly.io usa OPENCLAW_GATEWAY_TOKEN, pero gateway.auth.password o un despliegue trusted-proxy no loopback configurado correctamente también cumplen el requisito.
    • Trata estos tokens como contraseñas.
    • Prefiere variables de entorno en lugar del archivo de configuración para todas las claves de API y tokens. Esto mantiene los secretos fuera de openclaw.json, donde podrían exponerse o registrarse accidentalmente.
  • Deploy

    bash
    fly deploy

    El primer despliegue compila la imagen Docker (~2-3 minutos). Los despliegues posteriores son más rápidos.

    Después del despliegue, verifica:

    bash
    fly statusfly logs

    Deberías ver:

    Code
    [gateway] listening on ws://0.0.0.0:3000 (PID xxx)[discord] logged in to discord as xxx
  • Create config file

    Entra por SSH en la máquina para crear una configuración adecuada:

    bash
    fly ssh console

    Crea el directorio y el archivo de configuración:

    bash
    mkdir -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": {}}EOF

    Nota: Con OPENCLAW_STATE_DIR=/data, la ruta de configuración es /data/openclaw.json.

    Nota: Reemplaza https://my-openclaw.fly.dev por el origen real de tu app de Fly. El arranque del Gateway inicializa los orígenes locales de la UI de Control a partir de los valores de tiempo de ejecución --bind y --port, para que el primer arranque pueda continuar antes de que exista la configuración, pero el acceso desde el navegador a través de Fly aún necesita que el origen HTTPS exacto figure en gateway.controlUi.allowedOrigins.

    Nota: El token de Discord puede venir de cualquiera de estas fuentes:

    • Variable de entorno: DISCORD_BOT_TOKEN (recomendado para secretos)
    • Archivo de configuración: channels.discord.token

    Si usas una variable de entorno, no hace falta añadir el token a la configuración. El gateway lee DISCORD_BOT_TOKEN automáticamente.

    Reinicia para aplicar:

    bash
    exitfly machine restart <machine-id>
  • Access the Gateway

    UI de Control

    Abre en el navegador:

    bash
    fly open

    O visita https://my-openclaw.fly.dev/

    Autentícate con el secreto compartido configurado. Esta guía usa el token de gateway de OPENCLAW_GATEWAY_TOKEN; si cambiaste a autenticación por contraseña, usa esa contraseña en su lugar.

    Registros

    bash
    fly logs              # Live logsfly logs --no-tail    # Recent logs

    Consola SSH

    bash
    fly ssh console
  • Solución de problemas

    "La app no está escuchando en la dirección esperada"

    El gateway está enlazando a 127.0.0.1 en lugar de 0.0.0.0.

    Corrección: Añade --bind lan al comando del proceso en fly.toml.

    Fallan las comprobaciones de estado / conexión rechazada

    Fly no puede llegar al gateway en el puerto configurado.

    Corrección: Asegúrate de que internal_port coincida con el puerto del gateway (establece --port 3000 o OPENCLAW_GATEWAY_PORT=3000).

    OOM / Problemas de memoria

    El contenedor sigue reiniciándose o el proceso se termina. Señales: SIGABRT, v8::internal::Runtime_AllocateInYoungGeneration o reinicios silenciosos.

    Corrección: Aumenta la memoria en fly.toml:

    toml
    [[vm]]  memory = "2048mb"

    O actualiza una máquina existente:

    bash
    fly machine update <machine-id> --vm-memory 2048 -y

    Nota: 512 MB es demasiado poco. 1 GB puede funcionar, pero puede provocar OOM bajo carga o con registros detallados. Se recomiendan 2 GB.

    Problemas con el bloqueo del Gateway

    Gateway se niega a arrancar con errores de "already running".

    Esto ocurre cuando el contenedor se reinicia, pero el archivo de bloqueo de PID persiste en el volumen.

    Corrección: Elimina el archivo de bloqueo:

    bash
    fly ssh console --command "rm -f /data/gateway.*.lock"fly machine restart <machine-id>

    El archivo de bloqueo está en /data/gateway.*.lock (no en un subdirectorio).

    No se lee la configuración

    --allow-unconfigured solo omite la protección de arranque. No crea ni repara /data/openclaw.json, así que asegúrate de que tu configuración real exista e incluya gateway.mode="local" cuando quieras un arranque normal de gateway local.

    Verifica que la configuración exista:

    bash
    fly ssh console --command "cat /data/openclaw.json"

    Escribir la configuración por SSH

    El comando fly ssh console -C no admite redirección de shell. Para escribir un archivo de configuración:

    bash
    # Use echo + tee (pipe from local to remote)echo '{"your":"config"}' | fly ssh console -C "tee /data/openclaw.json" # Or use sftpfly sftp shell> put /local/path/config.json /data/openclaw.json

    Nota: fly sftp puede fallar si el archivo ya existe. Elimínalo primero:

    bash
    fly ssh console --command "rm /data/openclaw.json"

    El estado no persiste

    Si pierdes perfiles de autenticación, estado de canales/proveedores o sesiones después de un reinicio, el directorio de estado está escribiendo en el sistema de archivos del contenedor.

    Corrección: Asegúrate de que OPENCLAW_STATE_DIR=/data esté establecido en fly.toml y vuelve a desplegar.

    Actualizaciones

    bash
    # Pull latest changesgit pull # Redeployfly deploy # Check healthfly statusfly logs

    Actualizar el comando de la máquina

    Si necesitas cambiar el comando de arranque sin un redespliegue completo:

    bash
    # Get machine IDfly machines list # Update commandfly machine update <machine-id> --command "node dist/index.js gateway --port 3000 --bind lan" -y # Or with memory increasefly machine update <machine-id> --vm-memory 2048 --command "node dist/index.js gateway --port 3000 --bind lan" -y

    Nota: Después de fly deploy, el comando de la máquina puede restablecerse a lo que hay en fly.toml. Si hiciste cambios manuales, vuelve a aplicarlos después del despliegue.

    Despliegue privado (reforzado)

    De forma predeterminada, Fly asigna IP públicas, lo que hace que tu gateway sea accesible en https://your-app.fly.dev. Esto es práctico, pero significa que tu despliegue puede ser descubierto por escáneres de internet (Shodan, Censys, etc.).

    Para un despliegue reforzado sin exposición pública, usa la plantilla privada.

    Cuándo usar un despliegue privado

    • Solo haces llamadas/mensajes salientes (sin Webhooks entrantes)
    • Usas túneles de ngrok o Tailscale para cualquier callback de Webhook
    • Accedes al gateway mediante SSH, proxy o WireGuard en lugar del navegador
    • Quieres que el despliegue quede oculto a escáneres de internet

    Configuración

    Usa deploy/fly.private.toml en lugar de la configuración estándar:

    bash
    # Deploy with private configfly deploy -c deploy/fly.private.toml

    O convierte un despliegue existente:

    bash
    # List current IPsfly ips list -a my-openclaw # Release public IPsfly ips release <public-ipv4> -a my-openclawfly ips release <public-ipv6> -a my-openclaw # Switch to private config so future deploys don't re-allocate public IPs# (remove [http_service] or deploy with the private template)fly deploy -c deploy/fly.private.toml # Allocate private-only IPv6fly ips allocate-v6 --private -a my-openclaw

    Después de esto, fly ips list debería mostrar solo una IP de tipo private:

    Code
    VERSION  IP                   TYPE             REGIONv6       fdaa:x:x:x:x::x      private          global

    Acceder a un despliegue privado

    Como no hay URL pública, usa uno de estos métodos:

    Opción 1: Proxy local (lo más sencillo)

    bash
    # Forward local port 3000 to the appfly proxy 3000:3000 -a my-openclaw # Then open http://localhost:3000 in browser

    Opción 2: VPN WireGuard

    bash
    # Crear la configuración de WireGuard (una sola vez)fly wireguard create # Importar al cliente WireGuard y luego acceder mediante IPv6 interna# Ejemplo: http://[fdaa:x:x:x:x::x]:3000

    Opción 3: solo SSH

    bash
    fly ssh console -a my-openclaw

    Webhooks con despliegue privado

    Si necesitas callbacks de webhook (Twilio, Telnyx, etc.) sin exposición pública:

    1. Túnel ngrok - Ejecuta ngrok dentro del contenedor o como sidecar
    2. Tailscale Funnel - Expón rutas específicas mediante Tailscale
    3. Solo saliente - Algunos proveedores (Twilio) funcionan bien para llamadas salientes sin webhooks

    Ejemplo de configuración de llamadas de voz con ngrok:

    json5
    {  plugins: {    entries: {      "voice-call": {        enabled: true,        config: {          provider: "twilio",          tunnel: { provider: "ngrok" },          webhookSecurity: {            allowedHosts: ["example.ngrok.app"],          },        },      },    },  },}

    El túnel ngrok se ejecuta dentro del contenedor y proporciona una URL pública de webhook sin exponer la propia aplicación Fly. Configura webhookSecurity.allowedHosts con el nombre de host público del túnel para que se acepten los encabezados de host reenviados.

    Beneficios de seguridad

    Aspecto Público Privado
    Escáneres de Internet Detectable Oculto
    Ataques directos Posibles Bloqueados
    Acceso a la UI de control Navegador Proxy/VPN
    Entrega de webhook Directa Mediante túnel

    Notas

    • Fly.io usa arquitectura x86 (no ARM)
    • El Dockerfile es compatible con ambas arquitecturas
    • Para la incorporación de WhatsApp/Telegram, usa fly ssh console
    • Los datos persistentes residen en el volumen en /data
    • Signal requiere Java + signal-cli; usa una imagen personalizada y mantén la memoria en 2 GB o más.

    Costo

    Con la configuración recomendada (shared-cpu-2x, 2 GB de RAM):

    • Aproximadamente 10-15 USD/mes, según el uso
    • El nivel gratuito incluye cierta asignación

    Consulta precios de Fly.io para obtener más detalles.

    Siguientes pasos

    Relacionado

    Was this useful?
    On this page

    On this page