Hermes Agent y Tailscale que no conecta: soluciones
¿Hermes Desktop no llega a tu gateway remoto por Tailscale? Cuatro causas cubren casi todos los casos, del bind a localhost al regex de CORS.
La Tailnet Está Levantada y Hermes Sigue Sin Responder
Instalaste Tailscale en el VPS, entraste a la tailnet desde tu portátil y confirmaste que ambos lados se hacen ping en sus direcciones 100.x.x.x. hermes serve corre en el host con el puerto abierto, y la app de Hermes Desktop en el portátil se queda girando en "Could not connect to Hermes gateway." Nada en el log del gateway parece enfadado. Nada en Tailscale se ve en rojo.
Ese fallo silencioso casi siempre es una de cuatro causas, y tres de ellas fallan en silencio por diseño. Este post recorre cada una, cómo confirmar que es la tuya y el arreglo exacto. Empieza por arriba: la primera causa se lleva la mayoría de los setups remotos recién estrenados, y cada causa siguiente asume que las anteriores ya están descartadas.
Causa 1: hermes serve Está Ligado a 127.0.0.1
hermes serve se liga a 127.0.0.1 por defecto. Es el valor correcto para un setup solo-portátil y el equivocado para cualquier cosa que quieras alcanzar por la tailnet. Un proceso ligado a loopback solo responde a peticiones que se originan en la misma máquina, y un peer de Tailscale no es la misma máquina. El puerto está abierto, el firewall está bien, el túnel está arriba y el socket rechaza la conexión.
Síntoma: desde el portátil, curl -v http://<hermes-vps>:8642/api/health devuelve Connection refused o se queda colgado hasta agotar el timeout. Desde una sesión SSH en el VPS, el mismo curl http://127.0.0.1:8642/api/health responde al instante. Si loopback responde y la tailnet no, esta es tu causa.
El arreglo es ligar hermes serve a la IP de Tailscale del host explícitamente:
TAILSCALE_IP=$(tailscale ip -4)
hermes serve --host "$TAILSCALE_IP" --port 8642
Ligar a la interfaz de la tailnet en vez de a 0.0.0.0 es la forma que quieres. 0.0.0.0 también funciona y es lo que aconsejan muchas guías, pero expone el socket en cada interfaz que tiene la máquina, incluida cualquiera accidentalmente pública, y devuelve toda la responsabilidad de autenticación a la capa de aplicación. Ligar a la IP de Tailscale es defensa en profundidad: el socket solo es alcanzable desde dentro de la tailnet.
Hazlo permanente poniendo el mismo flag en la unit de systemd o en el command del docker-compose.yml. Si corres en Docker, publica el puerto directamente en la IP de Tailscale con -p ${TAILSCALE_IP}:8642:8642 en vez del -p 8642:8642 por defecto (que publica en todas las interfaces del host).
Para la instalación inicial completa con Tailscale, la guía de acceso remoto seguro con Hermes Agent + Tailscale recorre la receta de principio a fin.
Causa 2: El Regex de CORS del Dashboard Rechaza tu Origen de Tailscale
Ligas el gateway a la IP de Tailscale, la API responde /api/health y el dashboard web carga su HTML desde http://<hermes-vps>:8642/. Después cada llamada de API que hace el dashboard falla con un error de CORS en la consola del navegador: has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Lo que pasa: builds antiguos de Hermes traían un allow_origin_regex hardcodeado en el dashboard que solo matcheaba ^https?://(localhost|127\.0\.0\.1)(:\d+)?$. El regex era seguro en un portátil e inútil en silencio en cualquier otro sitio. Un hostname de Tailscale como http://hermes-vps:8642 o una IP como http://100.64.1.5:8642 nunca matchea, así que la preflight falla y el navegador tira el fetch. La feature request que sigue el arreglo tiene el historial completo.
El arreglo es una variable de entorno:
export HERMES_DASHBOARD_CORS_ORIGINS="http://hermes-vps:8642,http://100.64.1.5:8642"
hermes serve --host "$TAILSCALE_IP" --port 8642
Lista cada origen desde el que realmente cargas el dashboard: el nombre de MagicDNS, la IP cruda de Tailscale y cualquier alias de Funnel o serve que hayas añadido. Se admiten comodines (http://*.tail1a2b3.ts.net:8642) si prefieres matchear el nombre completo de la tailnet en vez de listar cada dispositivo.
Dos perillas relacionadas que tropiezan a la gente:
HERMES_DASHBOARD_HOSTsobreescribe la dirección que el dashboard anuncia al navegador. Si la dejaste enlocalhost, el dashboard genera enlaces de vuelta ahttp://localhost:8642/api/...y el navegador intenta llegar a su propio loopback en vez de a la tailnet. Ponla a tu hostname o IP de Tailscale.- La app Hermes Desktop también lleva un Origin. Si usas el desktop empaquetado en vez del dashboard del navegador, su renderer envía
Origin: null(Electron carga porfile://). Builds antiguos lo aceptaban solo cuando el servidor estaba ligado a loopback, que es la exclusividad mutua descrita en el issue #38412. Los builds recientes aceptannullcuando está presente enHERMES_DASHBOARD_CORS_ORIGINSjunto a tus origines reales: añade la cadena literalnulla la lista para permitir el cliente desktop.
Reinicia hermes serve tras cualquier cambio a estas env vars. Los valores se leen al arranque, no en cada request.
Causa 3: El Túnel de Tailscale Está Cayendo a DERP o No Sube
Si el dashboard acaba cargando pero cada mensaje tarda varios segundos en enviarse y las notas de voz se cortan, el túnel está arriba pero lento. Tailscale está retransmitiendo cada paquete por un servidor DERP hasta tu VPS, y el round-trip lo domina ese salto extra en vez del modelo. Si no pasa nada de nada, probablemente el túnel nunca llegó a levantarse.
Confirma cuál tienes con tailscale status. Un peer sano muestra direct <ip>:<port> en su línea. Un peer relayed por DERP muestra relay "<region>". Si el peer no aparece o está marcado offline, el túnel nunca se estableció.
El arreglo es distinto en cada caso:
- Atascado en DERP. Abre UDP
41641de salida tanto en el firewall del host VPS como en el firewall de la red del cliente. Ese es el puerto que Tailscale usa para túneles WireGuard directos; si cualquier lado bloquea la salida UDP, ambos peers caen a DERP aunque el par esté autenticado. Confírmalo consudo ufw allow 41641/udpen el VPS y volviendo a hacer ping al peer trastailscale down && tailscale up. Redes corporativas y Wi-Fi de hotel son los sospechosos habituales de bloquear la salida UDP. Si la conexión directa sigue siendo imposible, DERP va bien para texto pero se nota en voz. - Peer marcado offline o el túnel nunca subió. La clave del nodo caducó. Tailscale rota las claves cada 180 días por defecto, y un dispositivo que estuvo offline durante la ventana de rotación vuelve como "offline" en la consola de admin hasta que reautentiques. Arréglalo con
tailscale up --force-reauthen el lado afectado y vuelve a entrar por el navegador. Para evitar la rotación por completo en instalaciones VPS del lado servidor, etiqueta el nodo (tailscale up --advertise-tags=tag:server) y desactiva la caducidad de clave para esa etiqueta en la consola de admin de Tailscale: los nodos etiquetados saltan la comprobación de 180 días por defecto. - El modo de ahorro de batería mató al cliente en el portátil. macOS y Windows dejan al SO pausar servicios en segundo plano en modos agresivos, y la app de bandeja de Tailscale puede desconectarse sola en silencio. Si la tailnet se apagó justo después de desenchufar, mira el icono de la bandeja antes de diagnosticar nada más.
Causa 4: Apuntas a una URL de Localhost desde un Cliente Remoto
El último caso silencioso es aquel en el que cada capa funciona y el cliente hace la pregunta equivocada. Si configuraste la Remote Gateway URL de Hermes Desktop como http://localhost:8642 o http://127.0.0.1:8642, la app intenta llegar a su propia interfaz de loopback en vez de cruzar la tailnet, y ningún arreglo del lado servidor va a ayudar.
Síntoma: en el portátil, la app desktop muestra "Could not connect." Desde ese mismo portátil, curl http://<hermes-vps>:8642/api/health responde sano.
El arreglo es una sola opción. En Hermes Desktop, abre Settings luego Connection y pon la Remote Gateway URL a una de estas:
http://<magic-dns-name>:8642- preferido, sobrevive a cambios de IP de Tailscale.http://<tailscale-ip>:8642- la dirección cruda100.x.x.x. Suficientemente estable para un setup estático.
El nombre de MagicDNS es lo que tailscale status muestra en la primera columna para la fila del VPS. Si nunca habilitaste MagicDNS, hazlo en la consola de admin bajo DNS: es un solo toggle y te ahorra cada sesión de debug por cambio de IP durante toda la vida de la tailnet.
Ya que estás en Settings, revisa el campo de credenciales. Si el gateway va detrás de un token (HERMES_AUTH_TOKEN), el cliente necesita el mismo token, y uno caducado produce un 4403 en el WebSocket que se parece mucho a un fallo de conexión. El issue del WebSocket 4403 tiene más detalle sobre ese modo de fallo concreto.
Orden de Diagnóstico que Ahorra Tiempo
Cuando la tailnet está arriba y Hermes no responde, recorre las causas en este orden en vez de reconstruir tu setup de Tailscale:
- ¿hermes serve está ligado a loopback?
curl http://<tailscale-ip>:8642/api/healthdesde el cliente responde en un segundo. La tasa de aciertos más alta en setups remotos recién estrenados. - ¿El regex de CORS del dashboard rechaza tu origen? Abre las devtools del navegador en el dashboard y busca una entrada CORS en rojo en la pestaña de red. Si aparece, pon
HERMES_DASHBOARD_CORS_ORIGINSy reinicia. - ¿El túnel es directo o relayed?
tailscale statusmuestradirectorelaypor peer.Offlinesignifica que la clave del nodo caducó y necesitas--force-reauth. - ¿El cliente pide localhost? Abre la configuración de conexión de la app desktop y confirma que la Remote Gateway URL apunta al hostname de la tailnet, no a
localhost.
Para la receta Docker de fondo en el VPS, mira la guía Docker de Hermes Agent. Si prefieres saltarte la malla del todo, self-hosting vs Hermes Agent gestionado cubre las contrapartidas.
Cuando Prefieres No Correr una Malla
Tailscale es la forma correcta para un Hermes autoalojado cuando quieres mantener la caja en tu propio VPS y alcanzarla desde cualquier sitio. Es también un sistema más que hay que mantener vivo: una ventana de rotación de claves, una env var de CORS, una regla de firewall para UDP 41641 y un ajuste de cliente que tiene que casar con el nombre de la tailnet del día. Si tu lectura es que un asistente de IA personal no debería requerir una VPN en malla y una sesión de debug en consola del navegador para saludarte de vuelta, empieza con Hermify. Hermify ejecuta un Hermes Agent gestionado en Telegram con la misma memoria y skills, listo en cerca de un minuto, sin puertos que abrir ni tailnet que mantener.
Fuentes
- Hermes Agent Issue #38061: Can't connect to Remote Gateway via Tailscale for Hermes Desktop
- Hermes Agent Issue #10567: Add --host and CORS config for hermes dashboard to enable Tailscale/VPN access
- Hermes Agent Issue #34390: dashboard --allowed-hosts flag for reverse-proxy and Tailscale access
- Hermes Agent Issue #38412: Desktop Remote gateway can't connect over WebSocket
- Tailscale: firewall ports and UDP 41641
- Tailscale: key expiry and re-authentication
- Securely Connecting a Remote Hermes Agent to Your Local Desktop App via Tailscale (Medium)
Lanza tu propio agente Hermes
Trae tu clave de API, conecta Telegram y ten un agente de IA que evoluciona solo activo en 60 segundos.
Empezar