Acceso remoto (SSH, túneles y tailnets)

Este repositorio soporta “remoto vía SSH” manteniendo un único Gateway (el maestro) ejecutándose en un host dedicado (escritorio/servidor) y conectando clientes a él.

  • Para operadores (tú / la app de macOS): el túnel SSH es el respaldo universal.
  • Para nodos (iOS/Android y futuros dispositivos): conéctate al WebSocket del Gateway (LAN/tailnet o túnel SSH según sea necesario).

La idea central

  • El WebSocket del Gateway se enlaza a loopback en tu puerto configurado (por defecto 18789).
  • Para uso remoto, reenvías ese puerto loopback por SSH (o usas tailnet/VPN y reduces la necesidad de túneles).

Configuraciones comunes VPN/tailnet (dónde vive el agente)

Piensa en el host del Gateway como “donde vive el agente”. Él gestiona sesiones, perfiles de autenticación, canales y estado. Tu laptop/escritorio (y los nodos) se conectan a ese host.

1) Gateway siempre activo en tu tailnet (VPS o servidor doméstico)

Ejecuta el Gateway en un host persistente y accede a él vía Tailscale o SSH.

  • Mejor experiencia: mantén gateway.bind: "loopback" y usa Tailscale Serve para la UI de control.
  • Respaldo: mantén loopback + túnel SSH desde cualquier máquina que necesite acceso.
  • Ejemplos: exe.dev (VM fácil) o Hetzner (VPS de producción).

Ideal cuando tu laptop entra en reposo con frecuencia pero quieres que el agente esté siempre activo.

2) El escritorio doméstico ejecuta el Gateway, la laptop es el control remoto

La laptop no ejecuta el agente. Se conecta remotamente:

  • Usa el modo Remote over SSH de la app de macOS (Ajustes -> General -> “OpenClaw runs”).
  • La app abre y gestiona el túnel, así que WebChat + verificaciones de salud “simplemente funcionan”.

Guía: Acceso remoto en macOS.

3) La laptop ejecuta el Gateway, acceso remoto desde otras máquinas

Mantén el Gateway local pero expónlo de forma segura:

  • Túnel SSH a la laptop desde otras máquinas, o
  • Tailscale Serve para la UI de control manteniendo el Gateway solo en loopback.

Guía: Tailscale y Visión general Web.

Flujo de comandos (qué se ejecuta dónde)

Un servicio de gateway gestiona el estado + canales. Los nodos son periféricos.

Ejemplo de flujo (Telegram -> nodo):

  • El mensaje de Telegram llega al Gateway.
  • El Gateway ejecuta el agente y decide si llamar a una herramienta de nodo.
  • El Gateway llama al nodo a través del WebSocket del Gateway (RPC node.*).
  • El nodo devuelve el resultado; el Gateway responde de vuelta a Telegram.

Notas:

  • Los nodos no ejecutan el servicio de gateway. Solo un gateway debería ejecutarse por host a menos que intencionalmente ejecutes perfiles aislados (consulta Múltiples gateways).
  • El “modo nodo” de la app de macOS es simplemente un cliente de nodo sobre el WebSocket del Gateway.

Túnel SSH (CLI + herramientas)

Crea un túnel local al WS del Gateway remoto:

ssh -N -L 18789:127.0.0.1:18789 user@host

Con el túnel activo:

  • openclaw health y openclaw status --deep ahora alcanzan el gateway remoto vía ws://127.0.0.1:18789.
  • openclaw gateway {status,health,send,agent,call} también pueden apuntar a la URL reenviada vía --url cuando sea necesario.

Nota: reemplaza 18789 con tu gateway.port configurado (o --port/OPENCLAW_GATEWAY_PORT). Nota: cuando pasas --url, el CLI no recurre a las credenciales de configuración o entorno. Incluye --token o --password explícitamente. No incluir credenciales explícitas es un error.

Valores remotos por defecto del CLI

Puedes persistir un destino remoto para que los comandos CLI lo usen por defecto:

{
  gateway: {
    mode: "remote",
    remote: {
      url: "ws://127.0.0.1:18789",
      token: "your-token",
    },
  },
}

Cuando el gateway es solo-loopback, mantén la URL en ws://127.0.0.1:18789 y abre el túnel SSH primero.

Precedencia de credenciales

La resolución de credenciales del Gateway sigue un contrato compartido a través de rutas call/probe/status y monitorización de exec-approval de Discord. El node-host usa el mismo contrato base con una excepción de modo local (ignora intencionalmente gateway.remote.*):

  • Las credenciales explícitas (--token, --password, o herramienta gatewayToken) siempre ganan en rutas de llamada que aceptan autenticación explícita.
  • Seguridad de sobrescritura de URL:
    • Las sobrescrituras de URL del CLI (--url) nunca reutilizan credenciales implícitas de config/env.
    • Las sobrescrituras de URL por env (OPENCLAW_GATEWAY_URL) pueden usar solo credenciales de env (OPENCLAW_GATEWAY_TOKEN / OPENCLAW_GATEWAY_PASSWORD).
  • Valores por defecto en modo local:
    • token: OPENCLAW_GATEWAY_TOKEN -> gateway.auth.token -> gateway.remote.token (el respaldo remoto aplica solo cuando la entrada de token de autenticación local no está configurada)
    • password: OPENCLAW_GATEWAY_PASSWORD -> gateway.auth.password -> gateway.remote.password (el respaldo remoto aplica solo cuando la entrada de password de autenticación local no está configurada)
  • Valores por defecto en modo remoto:
    • token: gateway.remote.token -> OPENCLAW_GATEWAY_TOKEN -> gateway.auth.token
    • password: OPENCLAW_GATEWAY_PASSWORD -> gateway.remote.password -> gateway.auth.password
  • Excepción de node-host en modo local: gateway.remote.token / gateway.remote.password se ignoran.
  • Las verificaciones de token de probe/status remotos son estrictas por defecto: usan solo gateway.remote.token (sin respaldo de token local) cuando apuntan al modo remoto.
  • Las variables de entorno heredadas CLAWDBOT_GATEWAY_* solo se usan en rutas de llamada de compatibilidad; probe/status/resolución de autenticación usa solo OPENCLAW_GATEWAY_*.

Chat UI vía SSH

WebChat ya no usa un puerto HTTP separado. La UI de chat SwiftUI se conecta directamente al WebSocket del Gateway.

  • Reenvía 18789 por SSH (ver arriba), luego conecta los clientes a ws://127.0.0.1:18789.
  • En macOS, prefiere el modo “Remote over SSH” de la app, que gestiona el túnel automáticamente.

App de macOS “Remote over SSH”

La app de barra de menú de macOS puede manejar la misma configuración de principio a fin (verificaciones de estado remotas, WebChat y reenvío de Voice Wake).

Guía: Acceso remoto en macOS.

Reglas de seguridad (remoto/VPN)

Versión corta: mantén el Gateway solo en loopback a menos que estés seguro de que necesitas un enlace.

  • Loopback + SSH/Tailscale Serve es el valor por defecto más seguro (sin exposición pública).
  • ws:// en texto plano es solo loopback por defecto. Para redes privadas de confianza, establece OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1 en el proceso del cliente como solución de emergencia.
  • Enlaces no-loopback (lan/tailnet/custom, o auto cuando loopback no está disponible) deben usar tokens/passwords de autenticación.
  • gateway.remote.token / .password son fuentes de credenciales del cliente. No configuran la autenticación del servidor por sí mismos.
  • Las rutas de llamada locales pueden usar gateway.remote.* como respaldo solo cuando gateway.auth.* no está configurado.
  • Si gateway.auth.token / gateway.auth.password está explícitamente configurado mediante SecretRef y no se resuelve, la resolución falla de forma cerrada (sin enmascaramiento por respaldo remoto).
  • gateway.remote.tlsFingerprint ancla el certificado TLS remoto cuando se usa wss://.
  • Tailscale Serve puede autenticar el tráfico de la UI de Control/WebSocket mediante headers de identidad cuando gateway.auth.allowTailscale: true; los endpoints de la API HTTP aún requieren autenticación por token/password. Este flujo sin token asume que el host del gateway es de confianza. Establece false si quieres tokens/passwords en todas partes.
  • Trata el control del navegador como acceso de operador: solo tailnet + emparejamiento deliberado de nodos.

Análisis profundo: Seguridad.