«Tengo problemas enormes con mi VPS. Estoy reinstalando OpenClaw por 3.a o 4.a vez.»

Ese mensaje apareció en el Discord de OpenClaw el mes pasado. El usuario no era el único. Recorra los canales de la comunidad y encontrará docenas de variaciones del mismo tema: la herramienta del navegador falla, el agente no puede conectarse a Chromium, el VPS se queda sin memoria, todo funcionaba ayer y hoy no.

Si está leyendo esto porque acaba de buscar «OpenClaw navegador no funciona VPS», está en el lugar correcto. Este artículo explica las cinco cosas que fallan, por qué interactúan de forma frustrante, y cómo las resolvimos todas en el operador Kubernetes de OpenClaw.rocks para que nunca más tenga que preocuparse por la configuración del navegador.

El error que todos ven

El mensaje de error más común en la comunidad de OpenClaw es este:

Can't reach the OpenClaw browser control service
(timed out after 15000ms)

Aparece en Ubuntu, Debian, en Docker, en Hetzner, Hostinger, GCP y en cualquier otro lugar donde se intenta ejecutar OpenClaw con automatización del navegador. Los logs del gateway dicen «Browser control service ready.» Pero cuando el agente intenta usar el navegador, se agota el tiempo de espera.

El error es genérico. Las causas no lo son. Existen al menos cinco modos de fallo distintos, y todos se ven idénticos desde fuera.

Fallo 1: Snap Chromium y el muro de AppArmor

En un servidor Ubuntu 22.04+ recién instalado, which chromium-browser devuelve /usr/bin/chromium-browser. Parece correcto. No lo es.

Desde Ubuntu 22.04, el paquete Chromium predeterminado es un snap. Cuando el gateway de OpenClaw intenta ejecutar ese binario a través de un servicio systemd, la capa de confinamiento de AppArmor lo bloquea. El paquete snap no puede abrir los puertos de depuración del Chrome DevTools Protocol (CDP) a través de la sandbox. El binario se lanza, parece iniciarse, y luego falla silenciosamente al abrir el puerto que OpenClaw necesita.

Verá «Failed to start Chrome CDP on port 18800» en los logs, o a veces nada en absoluto. El proceso del navegador se inicia y muere antes de escribir una sola línea de log.

La solución es instalar el paquete .deb de Google Chrome o usar el binario autónomo de Chromium de Playwright desde ~/.cache/ms-playwright/. Ambos esquivan la sandbox de snap. Pero la solución no es obvia. La detección de navegador de OpenClaw escanea las rutas estándar en orden, encuentra primero el binario snap e intenta usarlo. La issue de GitHub #4978 tiene una descripción completa.

Fallo 2: Valores predeterminados de headless que asumen una pantalla

OpenClaw viene con headless: false y noSandbox: false como valores predeterminados del navegador. Esto tiene sentido en un Mac o un equipo Windows con pantalla. En un VPS no hay pantalla. Sin configuración explícita, Chromium intenta abrir una ventana en un servidor de pantalla que no existe.

Dos cambios de configuración lo solucionan:

openclaw config set browser.headless true
openclaw config set browser.noSandbox true

La mayoría de guías VPS lo mencionan. Pero si sigue las instrucciones de instalación estándar de OpenClaw, ninguna de estas líneas aparece. Instala, prueba el navegador, falla. Busca el error. Encuentra un artículo. Cambia la configuración. Reinicia. Y pasa al fallo número tres.

Fallo 3: El OOM kill invisible

Una sola pestaña de Chromium con unas cuantas páginas abiertas consume entre 2 y 4 GB de RAM. En un VPS de 4 GB, eso no deja casi nada para OpenClaw, el sistema operativo y cualquier otro servicio en ejecución.

Cuando Linux se queda sin memoria, el OOM killer del kernel termina el proceso que más memoria consume. Ese es Chromium. El proceso muere. OpenClaw registra un timeout del navegador. No hay informe de error, ni stack trace, ni indicación de que la memoria fuera el problema.

Hay también una versión más sutil de este problema. Chromium lanza procesos de renderizado hijo para cada pestaña. Si estos no se limpian correctamente, se acumulan. Una issue de GitHub documentó 39 procesos de renderizado huérfanos consumiendo 3,8 GB de RAM en un VPS que supuestamente tenía margen de sobra.

Puede verificarlo después con dmesg | grep -i "oom\|killed\|chromium", pero la mayoría de las personas no piensa en mirar ahí. Reinician OpenClaw, funciona unos minutos, y luego vuelve a pasar.

La página oficial de requisitos del servidor recomienda 4 GB mínimo para una instalación básica. Pero esa cifra asume que no hay automatización del navegador. Con el navegador activado, 8 GB es el mínimo realista. En Hetzner, es la diferencia entre un cpx22 (5 $/mes) y un cpx42 (17 $/mes).

Fallo 4: La memoria compartida que falta en Docker

Si ejecuta OpenClaw en Docker (habitual en despliegues VPS), hay otra trampa. El /dev/shm predeterminado de Docker es de 64 MB. Chromium usa memoria compartida para la comunicación entre procesos. Cuando se agota, las pestañas se cierran silenciosamente o muestran páginas en blanco.

La solución es una línea en su docker-compose.yml:

shm_size: '2gb'

O móntela explícitamente:

volumes:
  - /dev/shm:/dev/shm

Esto no está documentado en la guía de instalación de OpenClaw. Es un comportamiento específico de Docker que afecta a cualquier aplicación que use Chromium, pero si nunca ha desplegado navegadores headless en Docker, no sabría que debe buscar esto.

Fallo 5: Colisiones de puertos de las que nadie le advierte

El servicio de control del navegador de OpenClaw funciona en un puerto separado del gateway. Por defecto, es el puerto del gateway más 2. Si su gateway está en 18789, el servicio de control del navegador debería estar en 18791, y el relay de extensiones en 18792.

En Docker, si solo expone el puerto 18789, el servicio de control del navegador es inalcanzable desde fuera del contenedor. Y lo que es peor, el gateway registra «Browser control service ready» incluso cuando el puerto 18791 nunca se enlaza realmente. La issue #17584 rastreó esto hasta el gateway importando el módulo equivocado: uno que registra el mensaje «ready» sin iniciar el servidor HTTP. El log le dice que todo está bien. El puerto está muerto.

En Kubernetes, si otro contenedor en el mismo pod ya usa el puerto 9222 (el puerto CDP estándar), la función ensurePortAvailable() de OpenClaw detecta el puerto como ocupado y rechaza la conexión, incluso si el ocupante es exactamente la instancia de Chromium con la que OpenClaw debería comunicarse.

La issue de GitHub #10994 documenta un caso en el que la configuración VPS del usuario funcionaba correctamente. Luego, tras unas cuantas acciones automatizadas, el puerto CDP se quedó bloqueado. La única solución fue encontrar y matar los procesos de Chromium residuales que retenían el puerto.

Por qué estos fallos se acumulan

Cada uno de estos cinco problemas tiene una solución conocida. Pero interactúan entre sí. Resuelve el problema del snap y se topa con el valor predeterminado de headless. Corrige la configuración y Chromium arranca. Funciona diez minutos, luego el OOM killer lo elimina. Añade espacio swap, y ahora el límite de memoria compartida de Docker causa errores de renderizado silenciosos. Lo arregla y descubre que el puerto 18791 no está expuesto.

El ciclo de depuración es así: buscar error, encontrar solución parcial, aplicar solución, toparse con el siguiente error, repetir. Un usuario de Discord describió haber reinstalado su sistema operativo entero «por 3.a o 4.a vez». Otro informó que el navegador era «inestable» tras lo que creía una instalación completa. Un tercero abrió una issue titulada simplemente «Browser tool consistently fails on VPS».

El problema no es que cada solución individual sea difícil. El problema es que hay cinco, dependen de su sistema operativo, gestor de paquetes, runtime de contenedores y proveedor VPS específicos, y un solo error en la cadena significa que el navegador no funciona.

Hay que reconocer que el equipo de OpenClaw ha ido corrigiendo bugs relacionados de forma constante. El log «ready» engañoso, la limpieza de renderers huérfanos y la gestión del puerto CDP han mejorado en versiones recientes. Pero las correcciones upstream abordan síntomas dentro del código de OpenClaw. No pueden instalar el binario correcto de Chromium en su servidor, configurar la memoria compartida de Docker, ni asignar suficiente RAM para la automatización del navegador. Eso sigue siendo responsabilidad suya.

Cómo rompimos Chromium tres veces (y qué aprendimos)

Ejecutamos cada agente de OpenClaw.rocks en Kubernetes con nuestro operador de código abierto. El sidecar del navegador nos llevó semanas hasta que funcionó correctamente. Experimentamos nuestra propia versión de cada problema descrito arriba, más algunos que solo aparecen en el contexto de orquestación de contenedores.

La idea era simple: ejecutar Chromium como un contenedor separado junto a OpenClaw, conectado por CDP. Una línea en el Custom Resource y el navegador simplemente funciona.

spec:
  chromium:
    enabled: true

Así es como esa única línea llegó a existir.

Crash 1: Usuario equivocado, sistema de archivos de solo lectura

Nuestro primer intento ejecutaba el contenedor de Chromium como UID 1001 con un sistema de archivos raíz de solo lectura. Buena práctica de seguridad. Y completamente roto. La imagen browserless espera UID 999 (blessuser), y Node.js llama a os.userInfo() al arrancar, lo que falla con ENOENT cuando el UID no tiene entrada en /etc/passwd. Incluso tras corregir el UID, el sistema de archivos de solo lectura impedía que Chrome escribiera archivos temporales. El sidecar se estrellaba en cada arranque sin escribir una sola línea de log. La issue #12 cuenta toda la historia.

Crash 2: El muro de seguridad WebSocket

Con el contenedor finalmente funcionando, Chromium estaba activo, CDP respondía en el puerto 9222, pero OpenClaw se negaba a usarlo. El gateway se enlazaba a la IP LAN del pod (necesario para el enrutamiento de Kubernetes Service), y la capa de seguridad de OpenClaw bloqueaba conexiones ws:// en texto plano a direcciones no-loopback: «SECURITY ERROR: Gateway URL uses plaintext ws:// to a non-loopback address. Both credentials and chat data would be exposed to network interception.»

Una verificación de seguridad legítima. Pero en un pod de Kubernetes, todos los contenedores comparten un namespace de red. El tráfico entre ellos nunca abandona el nodo. No podíamos cambiar la verificación de seguridad de OpenClaw, así que añadimos un sidecar de reverse proxy nginx que escucha en todas las interfaces y reenvía al gateway en loopback. El gateway permanece seguro. El Service sigue accesible. La issue #135 documenta la depuración.

Crash 3: Colisión en el puerto 3000

Chromium funcionaba. El gateway tenía su proxy. Pero el navegador seguía sin conectarse. La imagen browserless usa el puerto 3000 por defecto, que colisionaba con el servicio de control del navegador interno de OpenClaw. Y cuando cambiamos al puerto 9222, la función ensurePortAvailable() de OpenClaw lo detectó como «en uso por otra cosa» y rechazó la conexión, porque en un namespace de red compartido, el puerto del sidecar parece local.

La solución fue usar la dirección IP del pod (a través de la Kubernetes Downward API) en lugar de localhost para la URL CDP. Una dirección no-loopback le indica a OpenClaw que use el modo remote/attach-only: conectarse a lo que ya está en ejecución en lugar de intentar lanzar su propio navegador. El PR #183 resolvió esto.

El resultado: cinco correcciones, aplicadas automáticamente

Cada uno de estos crashes nos enseñó algo. El operador actual codifica todo ese conocimiento:

Aislamiento por sidecar. Chromium se ejecuta en su propio contenedor. Sin snap. Sin Playwright. Sin flags headless. La imagen browserless se encarga de todo eso.

Recursos dedicados. El sidecar tiene sus propios límites de CPU y memoria (250m-1000m CPU, 512Mi-2Gi RAM por defecto, configurable). Si Chromium excede su límite de memoria, Kubernetes solo reinicia el contenedor del navegador. Su agente sigue funcionando.

Memoria compartida. El operador monta automáticamente un volumen de 1 GB respaldado en memoria en /dev/shm. Sin necesidad de configuración shm_size de Docker.

Enrutamiento de puertos. La IP del pod para la URL CDP activa el modo remoto. OpenClaw se conecta al sidecar en lugar de intentar reclamar el puerto. El conflicto ensurePortAvailable() desaparece.

Detección anti-bot integrada. Muchos sitios web detectan el Chromium headless predeterminado y bloquean la automatización. El operador soporta extraArgs en el sidecar de Chromium, para que pueda pasar flags como --disable-blink-features=AutomationControlled y user agents personalizados sin construir una imagen de contenedor personalizada:

spec:
  chromium:
    enabled: true
    extraArgs:
      - "--disable-blink-features=AutomationControlled"
      - "--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
      - "--window-size=1920,1080"

Seguridad sin concesiones. Todas las capacidades Linux eliminadas, escalada de privilegios deshabilitada, seccomp RuntimeDefault, UID 999 no root. Sin --no-sandbox como root.

Qué significa esto para usted

Si ejecuta OpenClaw en un VPS y el navegador funciona, enhorabuena. Ha sorteado cinco modos de fallo distintos y ha salido del otro lado. Conserve su configuración. Haga una copia de seguridad.

Si el navegador no funciona, o funciona de forma intermitente, o está harto de depurar Chromium en un VPS de 5 dólares, piense en cuánto vale su tiempo.

OpenClaw.rocks ejecuta cada agente en Kubernetes con el operador descrito arriba. El sidecar del navegador está preconfigurado. La memoria está asignada. Los puertos están enrutados. La seguridad está reforzada. No instala nada, no configura nada y no depura nada.

Su agente obtiene un navegador que funciona. Cada vez. Listo para usar.

Las cinco correcciones en resumen

Si quiere seguir con el auto-hosting, aquí tiene la lista de verificación completa:

  1. Sustituir Chromium snap por el .deb de Google Chrome o el binario autónomo de Playwright
  2. Activar el modo headless: openclaw config set browser.headless true y browser.noSandbox true
  3. Asignar 8 GB+ de RAM o añadir 4 GB de swap para automatización del navegador
  4. Montar memoria compartida en Docker: shm_size: '2gb'
  5. Exponer los tres puertos: gateway, control del navegador (gateway + 2) y relay de extensiones (gateway + 3)

O salte la lista. Obtenga su asistente en OpenClaw.rocks y déjenos la infraestructura a nosotros.