SSD Nodes Learn
Guias Matt ConnorPor Matt Connor · Atualizado 2026-07-24

Como usar Gemini CLI em VPS headless

Instale o Gemini CLI em VPS sem interface gráfica usando Node atualizado, npm sem sudo e tmux para evitar interrupções de sessão SSH durante tarefas longas.

O que você está construindo

Um Gemini CLI sempre ativo em um servidor próprio, acessível via SSH, executando tarefas longas de agentes que continuam rodando após você fechar o laptop. A instalação consiste em três comandos. O desafio está em tudo o que assume o uso de uma interface gráfica: o CLI do Google tenta abrir um navegador para login, mas seu servidor não possui um. Por isso, a maior parte deste guia foca no caminho headless — uma versão atual do Node que a distro não fornece, um install global do npm que não exige root, autenticação sem browser usando uma API key mantida fora do shell history, e o tmux para que uma queda de sessão SSH não interrompa uma tarefa em execução.

O Gemini CLI é um programa Node de código aberto (Apache-2.0) (@google/gemini-cli) que se comunica com os modelos Gemini do Google e pode ler e escrever arquivos, executar comandos de shell e operar ferramentas no diretório de trabalho. Em uma VPS, ele funciona como um agente pequeno e sempre disponível que você pode deixar trabalhando — por isso, a conta que o executa e as credenciais armazenadas na máquina são mais importantes do que qualquer configuração individual aqui.

Pré-requisitos e problemas comuns

  • Um VPS Ubuntu 24.04 KVM recém-instalado com acesso root ou sudo. Qualquer plano KVM funciona; a CLI é leve, consumindo apenas alguns centenas de MB de RAM em repouso.
  • Node.js 20 ou superior. Esta é a única exigência rígida de versão; o pacote da distribuição é inferior — veja a próxima seção.
  • HTTPS de saída (porta 443) para as APIs do Google. Nenhuma porta de entrada é necessária; este é um cliente, não um servidor, portanto não é necessário abrir portas no firewall.
  • Um método de autenticação que não exija um navegador no servidor: uma chave de API do Gemini via Google AI Studio, ou um túnel SSH para um navegador em sua própria máquina. O uso de chave de API é o método recomendado para scripts e execuções automatizadas.
  • Docker ou Podman, apenas se você desejar o isolamento --sandbox. Opcional, detalhado ao final.

O problema que afeta a todos: o fluxo de login inicial gemini foi projetado para desktops. Ele tenta abrir um navegador e, em um servidor headless, falha ou fornece um link que não funciona. Escolha o método de autenticação antes de iniciar.

Node: o pacote da distro é muito antigo

O Ubuntu 24.04 fornece o Node 18.19.1 em seus repositórios oficiais, junto com o npm 9.2.0. O package.json do Gemini CLI declara o engines: { node: ">=20" }, e o npm não interrompe a instalação por padrão em caso de incompatibilidade — ele instala e exibe um aviso indicando a diferença:

npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@google/gemini-cli@0.50.0',
npm WARN EBADENGINE   required: { node: '>=20' },
npm WARN EBADENGINE   current: { node: 'v18.19.1', npm: '9.2.0' }
npm WARN EBADENGINE }

Ignorar esse aviso fará o CLI rodar em um runtime não suportado, onde ele apresentará erros ou travará ao tentar acessar uma API do Node 20+ que ele espera que exista. O Node 18 também atingiu o fim de vida (EOL) em abril de 2025, portanto é uma opção inviável. Instale uma versão LTS atual antes de instalar o CLI. As duas rotas limpas são o NodeSource (um repositório apt assinado para todo o sistema) ou o nvm (um gerenciador de versões por usuário). Escolha uma.

NodeSource, se você quiser o Node disponível para todos os usuários da máquina:

sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg
curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
sudo apt-get install -y nodejs
node --version

O node --version deve imprimir v20.x ou superior — o v24.x é o LTS ativo atual. Verifique a página do NodeSource para obter o script de configuração atual; o setup_24.x na URL é o valor que deve ser atualizado quando um novo LTS for lançado.

nvm, se você preferir manter o Node dentro do home de um único usuário e nunca usar sudo:

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
source ~/.bashrc
nvm install --lts
node --version

O v0.40.1 na URL estava atual quando este texto foi escrito; verifique o README do nvm para a versão mais recente e substitua a versão antes de executar o comando. O nvm tem uma vantagem real para este caso: ele instala o Node e seus pacotes globais em ~/.nvm, então o problema de permissão de instalação global na próxima seção simplesmente não ocorre. Se você optar pelo nvm, pode pular a etapa do npm-prefix.

Instale a CLI sem sudo npm -g

O comando tentador é sudo npm install -g @google/gemini-cli. Não use. Um prefixo global pertencente ao root causa erros de permissão em todas as instalações futuras e deixa arquivos do root no seu cache do npm, o que causará problemas meses depois. Execute um npm install -g comum (sem sudo) contra um Node do sistema e você encontrará outro erro:

npm error code EACCES
npm error syscall mkdir
npm error path /usr/lib/node_modules/@google
npm error errno -13
npm error Error: EACCES: permission denied, mkdir '/usr/lib/node_modules/@google'

Isso ocorre porque o npm tenta escrever em /usr/lib, onde seu usuário não tem permissão. A solução não é usar sudo — é apontar o prefixo global do npm para o seu diretório home, para que as instalações globais fiquem em um local que pertence a você:

mkdir -p ~/.npm-global
npm config set prefix ~/.npm-global
echo 'export PATH="$HOME/.npm-global/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
npm install -g @google/gemini-cli
gemini --version

~/.bashrc, e não ~/.profile, é deliberado: o tmux — que você usará para rodar a CLI em duas seções de agora — inicia um shell non-login que lê ~/.bashrc e ignora ~/.profile. Assim, uma linha PATH no arquivo errado deixa o gemini invisível exatamente onde você precisa. O teste consiste apenas em rodar gemini --version para imprimir o número da versão. Se você receber gemini: command not found, seu export de PATH falhou — veja os modos de falha. No nvm, ignore as linhas de prefixo; ele já instala pacotes globais no seu home.

Se você executou sudo npm anteriormente e agora vê Your cache folder contains root-owned files, corrija uma vez com sudo chown -R $(id -u):$(id -g) ~/.npm.

O problema de autenticação headless e como resolvê-lo

Execute gemini de forma interativa pela primeira vez e ele oferecerá o login com sua conta Google. Em um desktop, isso abre uma aba no navegador. Em um VPS headless não há navegador, então o fluxo imprime uma URL localhost para você abrir ou falha com um erro como:

Failed to open browser. Please visit the following URL to authorize:
https://accounts.google.com/o/oauth2/v2/auth?...&redirect_uri=http://localhost:PORT

O problema é o redirect_uri=http://localhost:PORT. Mesmo que você abra essa URL no seu laptop e aprove, o Google redireciona para http://localhost:PORT — localhost no servidor, uma porta que seu laptop não consegue acessar. O login nunca é concluído.

Existem duas formas de resolver.

A primeira é uma API key, que é o padrão correto para servidores. Crie uma chave no Google AI Studio (aistudio.google.com) e passe para o CLI como uma variável de ambiente; ele lê GEMINI_API_KEY e pula o fluxo do navegador. Agora, sobre a segurança: não digite export GEMINI_API_KEY=AIza... no prompt — isso salva em ~/.bash_history em texto puro, e não coloque em arquivos com permissão de leitura para outros usuários. Escreva em um arquivo com permissão mode-600 que o shell carregue ao iniciar:

umask 077
printf 'export GEMINI_API_KEY=%s\n' 'AIzaSyYOUR_KEY_HERE' > ~/.gemini_env
chmod 600 ~/.gemini_env
echo '[ -f ~/.gemini_env ] && . ~/.gemini_env' >> ~/.bashrc
source ~/.bashrc

chmod 600 significa que apenas seu usuário pode ler o arquivo. Confirme se a chave foi carregada no ambiente com printenv GEMINI_API_KEY; se não houver saída, o CLI tentará o fluxo do navegador e falhará. O CLI também lê um arquivo .env em ~/.gemini/ se preferir esse formato — a regra é a mesma, portanto, use chmod 600 ~/.gemini/.env.

A segunda forma mantém o login da conta pessoal do Google (e seu nível gratuito) tunelando o callback do OAuth de volta para o seu laptop. O problema é que o servidor loopback do CLI usa uma porta aleatória a cada execução, então não há uma porta estável para redirecionar, a menos que você a defina primeiro com a variável de ambiente OAUTH_CALLBACK_PORT e depois redirecione exatamente essa porta:

# from your laptop, forward the callback port into the SSH session:
ssh -L 8085:localhost:8085 user@your-server
# then, on the server, pin the callback to the same port and start the CLI:
export OAUTH_CALLBACK_PORT=8085
gemini

O CLI não consegue abrir um navegador, então ele imprime a URL de autenticação; abra-a no navegador do seu laptop, aprove e, quando o Google redirecionar para http://localhost:8085/..., o redirecionamento SSH levará a requisição ao servidor loopback no VPS e o login será concluído. Se você não fixar a porta, ela será uma porta aleatória nova a cada execução, que nenhum ssh -L configurado antecipadamente conseguirá capturar. Isso funciona, mas exige que você esteja com um navegador aberto, portanto não serve para scripts. Para qualquer processo que precise rodar em segundo plano, use a API key.

Para Vertex AI ou um projeto do Google Cloud em vez do AI Studio, defina GOOGLE_API_KEY junto com GOOGLE_GENAI_USE_VERTEXAI=true, ou GOOGLE_CLOUD_PROJECT para uma licença Code Assist — a disciplina de variáveis de ambiente e o arquivo mode-600 permanecem os mesmos.

Execute dentro do tmux para que uma queda de sessão SSH não o interrompa

Um processo gemini iniciado diretamente pelo seu shell SSH é um processo filho desse shell. Se a conexão cair — notebook fechado, Wi-Fi desconectado ou timeout por inatividade — o sshd encerra o pseudo-terminal, o shell recebe um SIGHUP e a CLI é encerrada. Uma tarefa em execução há dez minutos durante a edição de arquivos morre junto com a sessão, e não haverá processo para recuperar após a reconexão.

O tmux resolve isso ao assumir o controle do shell em vez de o sshd assumir o controle. Este é o mesmo padrão de executar um agente de codificação de IA em um VPS remoto dentro do tmux, e funciona de forma idêntica aqui:

sudo apt install -y tmux
tmux new -A -s gemini
# inside the session:
gemini
# detach with Ctrl-b then d — the task keeps running
# reconnect later from any machine:
tmux attach -t gemini

O tmux new -A -s gemini anexa-se a uma sessão chamada gemini se ela existir, ou a cria caso contrário; este é o único comando para executar logo após cada login. O shell interno pertence ao servidor tmux em segundo plano, não à sua sessão SSH, portanto, a queda da conexão mantém a CLI funcionando. Reconecte, anexe-se e você estará de volta ao mesmo histórico de rolagem.

Para execuções via script (não interativas), o Gemini CLI possui um modo headless: o gemini -p "summarise the failing tests in this repo" imprime uma resposta e encerra, e o --output-format json fornece saída legível por máquina para ser enviada via pipe. O modo headless com uma API key é o ideal para sessões tmux executando jobs em lote longos ou disparados via cron — com uma ressalva: um job do cron não carrega seus arquivos de login, portanto, forneça à linha do crontab seu próprio GEMINI_API_KEY (ou faça o comando carregar o ~/.gemini_env), caso contrário o CLI tentará o fluxo de navegador e falhará.

Sandboxing e permissões em um servidor que também roda produção

Um agente com acesso ao shell é um shell. O Gemini CLI pode executar comandos e, por padrão, solicita confirmação antes de cada comando arriscado — mas usuários utilizam o --yolo (aprovação automática de cada chamada de ferramenta), e então ele pode deletar arquivos, fazer push no git ou acessar serviços internos com a autoridade total do usuário que o executa. Em um servidor que também roda produção, isso representa um blast radius real, não hipotético.

Três controles, em ordem de eficácia:

  • Execute como um usuário dedicado e sem privilégios. Não use root, nem um membro do sudo. Crie um usuário agent com seu próprio home, instale o Node e o CLI lá, e uma instrução mal interpretada ficará confinada a essa conta. Esta é a decisão de maior valor.
  • Mantenha credenciais de produção fora do servidor. Sem ~/.aws/credentials de produção, sem .env copiados da produção, sem senhas de banco de dados com acesso de escrita para qualquer recurso crítico. Forneça credenciais de staging ou apenas de leitura.
  • Use o sandbox nativo. Com Docker ou Podman instalados, o gemini --sandbox (ou GEMINI_SANDBOX=docker) executa as chamadas de ferramenta do agente dentro de um container isolado do filesystem e da rede do host. Não substitui o uso de um usuário sem privilégios, mas é uma segunda camada forte quando o mesmo VPS realiza tarefas reais.

Se você estiver executando o Gemini CLI junto a outras ferramentas self-hosted — um servidor MCP expondo ferramentas ao agente no mesmo VPS, por exemplo — trate cada capacidade adicionada como mais superfície de ataque para o agente, e limite o escopo dos tokens fornecidos a exatamente uma tarefa.

Cota, custo e o caminho de autenticação escolhido

O caminho de autenticação define como você será cobrado. Uma conta pessoal do Google (caminho OAuth) utiliza o nível gratuito do Gemini Code Assist, com limites reais por minuto e por dia; se excedidos, as requisições retornarão um erro de rate-limit até que o intervalo seja resetado. Uma API key do AI Studio pode ser do nível gratuito ou faturada, dependendo do projeto — uma chave faturada aumenta os limites e cobra por token. A autenticação via Vertex e Cloud-project é cobrada através do Google Cloud.

Duas notas práticas. Um agente automatizado em loop pode consumir a cota rapidamente; monitore-o nas primeiras vezes antes de configurá-lo em um cron job. E se o seu motivo para usar um modelo no lado do servidor for privacidade ou inferência sem medição, em vez dos modelos hospedados pelo Google, essa é uma ferramenta diferente — hospedar um LLM open source com Ollama em um VPS mantém os pesos e os prompts em sua própria máquina, ao custo de rodar um modelo muito menor que o Gemini.

Mantendo atualizado

O Gemini CLI recebe atualizações frequentes. Como você o instalou em um prefixo de usuário, as atualizações não exigem sudo:

npm install -g @google/gemini-cli@latest
gemini --version

Existem canais de lançamento: @latest é a versão estável, @preview é a prévia semanal, @nightly é a versão bleeding edge — use a versão @latest para qualquer ambiente de produção. No nvm, pacotes globais ficam sob a versão ativa do Node; portanto, após usar nvm use para trocar a versão do Node, você pode precisar reinstalar o CLI. Leia as notas de lançamento em vez de buscar cada patch individualmente.

Modos de falha, com as strings exatas

npm WARN EBADENGINE Unsupported engine ... required: { node: '>=20' }, seguido pelo crash da CLI em runtime. O Node é muito antigo — a distro está na versão 18.19.1, que já atingiu o fim de vida (end-of-life). Instale o Node 20+ via NodeSource ou nvm, confirme com node --version, e se você tiver vários Nodes instalados, verifique se which node aponta para o novo e não para o /usr/bin/node.

npm error code EACCES / permission denied, mkdir '/usr/lib/node_modules/...'. Uma instalação global em um prefixo de propriedade do root. Não use sudo — defina npm config set prefix ~/.npm-global, coloque ~/.npm-global/bin em PATH, e reinstale como seu usuário comum. Se uma sudo npm anterior deixou arquivos de cache pertencentes ao root (Your cache folder contains root-owned files), execute sudo chown -R $(id -u):$(id -g) ~/.npm.

Failed to open browser, um login travado, ou um redirect_uri=http://localhost:PORT inacessível. O fluxo OAuth exige um browser que o servidor não possui, e o callback de localhost aponta para o servidor, não para o seu laptop. Use o caminho de API-key (GEMINI_API_KEY), ou faça o pin de OAUTH_CALLBACK_PORT, encaminhe via SSH com ssh -L, e abra a URL localmente.

O processo sumiu quando o SSH caiu. Você executou gemini diretamente no shell SSH, então ele era um processo filho desse shell e morreu junto com o pty na desconexão. Não há o que recuperar. Inicie toda sessão com tmux new -A -s gemini e execute a CLI dentro dela.

A autenticação ainda falha com a chave definida — a CLI volta para o seletor de autenticação, ou uma requisição retorna API key not valid com HTTP 400. A chave não está no ambiente que a CLI enxerga. Confirme com printenv GEMINI_API_KEY; se estiver vazia, seu ~/.gemini_env nunca foi carregado — verifique se a linha está em ~/.bashrc, que shells interativos (incluindo tmux) leem, mas cron e outros shells não interativos não. Um espaço ou aspa extra dentro do valor da chave também produz API key not valid.

429 / RESOURCE_EXHAUSTED / uma mensagem de rate-limit. Você atingiu a cota do tier que sua autenticação utiliza. Aguarde o reset da janela, diminua a velocidade do agente ou mude para uma API key paga. Um agente preso em um loop de retry continuará atingindo isso — interrompa-o e verifique o que ele está fazendo.

FAQ

Como autenticar o Gemini CLI em um servidor headless?

Use uma API key em vez do login pelo navegador. Crie uma chave no Google AI Studio, salve-a em um arquivo com permissão mode-600 que seu shell carregue (export GEMINI_API_KEY=...) e o CLI ignorará o fluxo de OAuth via browser. Se você precisar especificamente do nível gratuito da conta pessoal, fixe a porta loopback com OAUTH_CALLBACK_PORT=8085, faça o encaminhamento para o seu laptop com ssh -L 8085:localhost:8085 user@server e abra a URL gerada localmente — mas isso exige interação manual no browser, portanto não é adequado para scripts.

Por que o npm global pede sudo e como evitar isso?

Porque o prefixo global padrão do npm é /usr/lib/node_modules, onde seu usuário não tem permissão de escrita; assim, um comando npm install -g comum falha com EACCES. A solução incorreta é usar sudo npm -g, pois isso deixa arquivos pertencentes ao root que causam erros em instalações futuras. A solução correta é apontar o prefixo para sua home (npm config set prefix ~/.npm-global) e adicionar o bin ao PATH, ou usar o nvm, que instala pacotes globais na sua home automaticamente.

Como manter o Gemini CLI rodando após eu desconectar?

Execute-o dentro do tmux. Um processo iniciado via SSH morre quando a conexão cai porque é um processo filho do shell; o tmux executa o shell sob um servidor desvinculado que sobrevive à desconexão. Use tmux new -A -s gemini, execute gemini dentro dele, desvincule com Ctrl-b d e reconecte depois com tmux attach -t gemini.

É seguro rodar o Gemini CLI em um servidor de produção?

Apenas com cautela, pois um agente com acesso ao shell pode executar qualquer comando que o usuário que o executa pode fazer. Execute-o como um usuário dedicado sem privilégios e sem sudo, mantenha credenciais de produção fora da máquina, evite a aprovação automática de --yolo e use --sandbox (Docker ou Podman) para isolar as chamadas de ferramentas do host. A conta utilizada é mais importante do que qualquer flag configurada.

Preciso abrir portas no firewall para o Gemini CLI?

Não. Ele é um cliente que faz chamadas HTTPS de saída para as APIs do Google, portanto precisa da porta 443 de saída, mas não de portas de entrada. Se você usar o túnel OAuth, a porta de callback fixada (ex: 8085) reside no localhost e é acessada via encaminhamento SSH, não por uma porta de entrada aberta. Mantenha as portas de entrada bloqueadas.

#gemini-cli#node#tmux#headless#ai#vps