Browser do OpenClaw no VPS: porque falha e como resolver
«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:
- Substituir o Chromium snap pelo
.debdo Google Chrome ou o binário autónomo do Playwright - Ativar o modo headless:
openclaw config set browser.headless trueebrowser.noSandbox true - Alocar 8 GB+ de RAM ou adicionar 4 GB de swap para automatização de browser
- Montar memória partilhada no Docker:
shm_size: '2gb' - 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.