«Estou com problemas enormes no meu VPS. A reinstalar o OpenClaw pela 3.a ou 4.a vez.»

Esta mensagem apareceu no Discord do OpenClaw no mês passado. O utilizador não estava sozinho. Percorra os canais da comunidade e encontrará dezenas de variações do mesmo tema: a ferramenta de browser falha, o agente não consegue contactar o Chromium, o VPS fica sem memória, ontem funcionava tudo e hoje não.

Se está a ler isto porque acabou de pesquisar «OpenClaw browser não funciona VPS», está no sítio certo. Este artigo explica as cinco coisas que falham, porque interagem de formas frustrantes, e como as resolvemos todas no operador Kubernetes do OpenClaw.rocks para que nunca mais tenha de se preocupar com a configuração do browser.

O erro que toda a gente vê

A mensagem de erro mais comum na comunidade OpenClaw é esta:

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

Aparece no Ubuntu, Debian, em Docker, na Hetzner, Hostinger, GCP e em qualquer outro lugar onde se tente executar o OpenClaw com automatização de browser. Os logs do gateway dizem «Browser control service ready.» Mas quando o agente tenta usar o browser, o tempo esgota-se.

O erro é genérico. As causas não são. Existem pelo menos cinco modos de falha distintos, e do exterior parecem todos iguais.

Falha 1: Snap Chromium e o muro do AppArmor

Num servidor Ubuntu 22.04+ acabado de instalar, which chromium-browser devolve /usr/bin/chromium-browser. Parece correto. Não é.

Desde o Ubuntu 22.04, o pacote Chromium predefinido é um snap. Quando o gateway do OpenClaw tenta iniciar esse binário através de um serviço systemd, a camada de confinamento do AppArmor bloqueia-o. O pacote snap não consegue abrir as portas de depuração do Chrome DevTools Protocol (CDP) através da sandbox. O binário arranca, parece iniciar, e depois falha silenciosamente ao abrir a porta que o OpenClaw precisa.

Nos logs verá «Failed to start Chrome CDP on port 18800», ou por vezes nada. O processo do browser arranca e morre antes de escrever uma única linha de log.

A solução é instalar o pacote .deb do Google Chrome ou usar o binário Chromium autónomo do Playwright em ~/.cache/ms-playwright/. Ambos contornam a sandbox snap. Mas a solução não é óbvia. A deteção de browser do OpenClaw percorre os caminhos padrão por ordem, encontra primeiro o binário snap e tenta usá-lo. A issue do GitHub #4978 tem uma descrição completa.

Falha 2: Predefinições headless que assumem um ecrã

O OpenClaw vem com headless: false e noSandbox: false como predefinições do browser. Faz sentido num Mac ou PC Windows com ecrã. Num VPS, não existe ecrã. Sem configuração explícita, o Chromium tenta abrir uma janela num servidor de ecrã que não existe.

Duas alterações de configuração resolvem o problema:

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

A maioria dos guias VPS menciona isto. Mas se seguir as instruções de instalação padrão do OpenClaw, nenhuma das linhas aparece. Instala, testa o browser, falha. Pesquisa o erro. Encontra um artigo. Altera a configuração. Reinicia. E passa para a falha número três.

Falha 3: O OOM kill invisível

Um único separador Chromium com algumas páginas abertas consome 2 a 4 GB de RAM. Num VPS de 4 GB, não sobra quase nada para o OpenClaw, o sistema operativo e quaisquer outros serviços em execução.

Quando o Linux fica sem memória, o OOM killer do kernel termina o processo que mais memória consome. Esse é o Chromium. O processo morre. O OpenClaw regista um timeout do browser. Sem relatório de crash, sem stack trace, sem indicação de que a memória foi o problema.

Há também uma versão mais subtil deste problema. O Chromium gera processos renderer filhos para cada separador. Se estes não forem devidamente limpos, acumulam-se. Uma issue do GitHub documentou 39 processos renderer órfãos a consumir 3,8 GB de RAM num VPS que supostamente tinha margem de sobra.

Pode verificar depois com dmesg | grep -i "oom\|killed\|chromium", mas a maioria das pessoas não pensa em olhar ali. Reiniciam o OpenClaw, funciona uns minutos, e depois acontece outra vez.

A página oficial de requisitos do servidor recomenda 4 GB mínimo para uma instalação básica. Mas esse número assume ausência de automatização de browser. Com o browser ativado, 8 GB é o mínimo realista. Na Hetzner, é a diferença entre um cpx22 (5 $/mês) e um cpx42 (17 $/mês).

Falha 4: A memória partilhada em falta do Docker

Se executa o OpenClaw em Docker (comum em deployments VPS), há outra armadilha. O /dev/shm predefinido do Docker é de 64 MB. O Chromium usa memória partilhada para comunicação entre processos. Quando se esgota, os separadores crasham silenciosamente ou mostram páginas em branco.

A solução é uma linha no seu docker-compose.yml:

shm_size: '2gb'

Ou monte-a explicitamente:

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

Isto não está documentado no guia de instalação do OpenClaw. É um comportamento específico do Docker que afeta qualquer aplicação que use Chromium, mas a menos que já tenha feito deploy de browsers headless em Docker, não saberia procurar isto.

Falha 5: Colisões de portas de que ninguém avisa

O serviço de controlo do browser do OpenClaw funciona numa porta separada do gateway. Por predefinição, é a porta do gateway mais 2. Se o seu gateway está na 18789, o serviço de controlo do browser deve estar na 18791, e o relay de extensões na 18792.

Em Docker, se apenas expõe a porta 18789, o serviço de controlo do browser fica inacessível de fora do contentor. Pior ainda, o gateway regista «Browser control service ready» mesmo quando a porta 18791 nunca se liga de facto. A issue #17584 rastreou o problema até ao gateway que importava o módulo errado: um que regista a mensagem «ready» sem iniciar o servidor HTTP. O log diz que está tudo bem. A porta está morta.

Em Kubernetes, se outro contentor no mesmo pod já usa a porta 9222 (a porta CDP padrão), a função ensurePortAvailable() do OpenClaw deteta a porta como ocupada e recusa a ligação, mesmo que o ocupante seja exatamente a instância Chromium com a qual o OpenClaw deveria comunicar.

A issue do GitHub #10994 documenta um caso em que a configuração VPS do utilizador funcionava corretamente. Depois, após algumas ações automatizadas, a porta CDP ficou bloqueada. A única solução foi encontrar e matar os processos Chromium residuais que retinham a porta.

Porque é que estas falhas se acumulam

Cada um destes cinco problemas tem uma solução conhecida. Mas interagem entre si. Resolve o problema do snap e embate na predefinição headless. Corrige a configuração e o Chromium arranca. Funciona dez minutos, depois o OOM killer abate-o. Adiciona espaço swap, e agora o limite de memória partilhada do Docker causa erros de renderização silenciosos. Resolve isso e descobre que a porta 18791 não está exposta.

O ciclo de depuração é assim: pesquisar erro, encontrar correção parcial, aplicar correção, embater no erro seguinte, repetir. Um utilizador do Discord descreveu ter reinstalado o sistema operativo inteiro «pela 3.a ou 4.a vez». Outro relatou que o browser estava «instável» após o que pensava ser uma instalação completa. Um terceiro abriu uma issue intitulada simplesmente «Browser tool consistently fails on VPS».

O problema não é que cada correção individual seja difícil. O problema é que existem cinco, dependem do seu sistema operativo, gestor de pacotes, runtime de contentores e fornecedor VPS específicos, e um único erro na cadeia significa que o browser não funciona.

É justo reconhecer que a equipa do OpenClaw tem corrigido bugs relacionados de forma constante. O log «ready» enganador, a limpeza de renderers órfãos e a gestão da porta CDP melhoraram todos nas versões recentes. Mas as correções upstream tratam sintomas dentro do código do OpenClaw. Não podem instalar o binário Chromium correto no seu servidor, configurar a memória partilhada do Docker ou alocar RAM suficiente para automatização de browser. Isso continua a ser responsabilidade sua.

Como partimos o Chromium três vezes (e o que aprendemos)

Executamos cada agente do OpenClaw.rocks em Kubernetes com o nosso operador open source. O sidecar do browser levou-nos semanas a acertar. Encontrámos a nossa própria versão de todos os problemas descritos acima, mais alguns que só aparecem num contexto de orquestração de contentores.

A ideia era simples: executar o Chromium como um contentor separado ao lado do OpenClaw, ligado via CDP. Uma linha no Custom Resource e o browser simplesmente funciona.

spec:
  chromium:
    enabled: true

Eis como essa única linha se concretizou.

Crash 1: Utilizador errado, sistema de ficheiros só de leitura

A nossa primeira tentativa executava o contentor Chromium como UID 1001 com um sistema de ficheiros raiz só de leitura. Boa prática de segurança. E completamente avariado. A imagem browserless espera UID 999 (blessuser), e o Node.js chama os.userInfo() no arranque, que falha com ENOENT quando o UID não tem entrada em /etc/passwd. Mesmo após corrigir o UID, o sistema de ficheiros só de leitura impedia o Chrome de escrever ficheiros temporários. O sidecar crashava em cada arranque antes de escrever uma única linha de log. A issue #12 conta a história completa.

Crash 2: O muro de segurança WebSocket

Com o contentor finalmente a funcionar, o Chromium estava ativo, o CDP respondia na porta 9222, mas o OpenClaw recusava-se a usá-lo. O gateway ligava-se ao IP LAN do pod (necessário para o routing do Kubernetes Service), e a camada de segurança do OpenClaw bloqueava ligações ws:// em texto simples para endereços não-loopback: «SECURITY ERROR: Gateway URL uses plaintext ws:// to a non-loopback address. Both credentials and chat data would be exposed to network interception.»

Uma verificação de segurança legítima. Mas num pod Kubernetes, todos os contentores partilham um namespace de rede. O tráfego entre eles nunca sai do nó. Não podíamos alterar a verificação de segurança do OpenClaw, por isso adicionámos um sidecar reverse proxy nginx que escuta em todas as interfaces e reencaminha para o gateway em loopback. O gateway mantém-se seguro. O Service continua acessível. A issue #135 documenta a depuração.

Crash 3: Colisão na porta 3000

O Chromium estava a funcionar. O gateway tinha o seu proxy. Mas o browser continuava sem se ligar. A imagem browserless usa a porta 3000 por predefinição, que colidia com o serviço de controlo de browser interno do OpenClaw. E quando mudámos para a porta 9222, a função ensurePortAvailable() do OpenClaw detetou-a como «em uso por outra coisa» e recusou a ligação, porque num namespace de rede partilhado, a porta do sidecar parece local.

A solução foi usar o endereço IP do pod (através da Kubernetes Downward API) em vez de localhost para o URL CDP. Um endereço não-loopback indica ao OpenClaw para usar o modo remote/attach-only: ligar-se ao que já está em execução em vez de tentar lançar o seu próprio browser. O PR #183 resolveu isto.

O resultado: cinco correções, aplicadas automaticamente

Cada um destes crashes ensinou-nos algo. O operador atual codifica todo esse conhecimento:

Isolamento por sidecar. O Chromium funciona no seu próprio contentor. Sem snap. Sem Playwright. Sem flags headless. A imagem browserless trata de tudo.

Recursos dedicados. O sidecar tem os seus próprios limites de CPU e memória (250m-1000m CPU, 512Mi-2Gi RAM por predefinição, configurável). Se o Chromium exceder o seu limite de memória, o Kubernetes reinicia apenas o contentor do browser. O seu agente continua a funcionar.

Memória partilhada. O operador monta automaticamente um volume de 1 GB em memória em /dev/shm. Sem necessidade de configuração Docker shm_size.

Routing de portas. O IP do pod para o URL CDP ativa o modo remoto. O OpenClaw liga-se ao sidecar em vez de tentar reclamar a porta. O conflito ensurePortAvailable() desaparece.

Deteção anti-bot integrada. Muitos websites detetam o Chromium headless predefinido e bloqueiam automatização. O operador suporta extraArgs no sidecar Chromium, para que possa passar flags como --disable-blink-features=AutomationControlled e user agents personalizados sem construir uma imagem de contentor 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"

Segurança sem concessões. Todas as capabilities Linux removidas, escalação de privilégios desativada, seccomp RuntimeDefault, UID 999 não-root. Sem --no-sandbox como root.

O que isto significa para si

Se executa o OpenClaw num VPS e o browser funciona, parabéns. Navegou por cinco modos de falha distintos e saiu do outro lado. Mantenha a sua configuração. Faça backup.

Se o browser não funciona, ou funciona de forma intermitente, ou está farto de depurar Chromium num VPS de 5 dólares, pense no valor do seu tempo.

O OpenClaw.rocks executa cada agente em Kubernetes com o operador descrito acima. O sidecar do browser está pré-configurado. A memória está alocada. As portas estão encaminhadas. A segurança está reforçada. Não instala nada, não configura nada e não depura nada.

O seu agente recebe um browser que funciona. Sempre. Pronto a usar.

As cinco correções resumidas

Se quer manter o auto-alojamento, aqui está a lista de verificação completa:

  1. Substituir o Chromium snap pelo .deb do Google Chrome ou o binário autónomo do Playwright
  2. Ativar o modo headless: openclaw config set browser.headless true e browser.noSandbox true
  3. Alocar 8 GB+ de RAM ou adicionar 4 GB de swap para automatização de browser
  4. Montar memória partilhada no Docker: shm_size: '2gb'
  5. Expor as três portas: gateway, controlo de browser (gateway + 2) e relay de extensões (gateway + 3)

Ou salte a lista. Obtenha o seu assistente no OpenClaw.rocks e deixe a infraestrutura connosco.