Installare Gemini CLI su VPS headless
Guida all'installazione di Gemini CLI su VPS senza interfaccia grafica. Usa Node, installazione npm senza sudo e tmux per gestire i task tramite SSH.
Cosa stai costruendo
Un Gemini CLI sempre attivo su un server di tua proprietà, raggiungibile tramite SSH, in grado di eseguire task lunghi tramite agenti che continuano a lavorare anche dopo la chiusura del laptop. L'installazione richiede solo tre comandi. La parte complessa riguarda tutto ciò che richiede un'interfaccia desktop: la CLI di Google richiede l'apertura di un browser per l'autenticazione, ma il server non ne dispone. Per questo motivo, la maggior parte di questa guida segue il percorso headless: utilizzeremo una versione recente di Node non disponibile nei repository della distro, un'installazione npm globale che non richiede privilegi di root, un'autenticazione senza browser tramite una API key da mantenere fuori dalla cronologia della shell, e tmux per evitare che la chiusura di una sessione SSH interrompa un task in esecuzione.
Gemini CLI è un programma Node open-source (Apache-2.0) (@google/gemini-cli) che comunica con i modelli Gemini di Google. Può leggere e scrivere file, eseguire comandi shell e gestire strumenti nella directory di lavoro. Su un VPS, è un agente leggero sempre disponibile che può lavorare in autonomia; per questo motivo, l'account utilizzato per l'esecuzione e le credenziali salvate sul sistema sono più importanti di qualsiasi singola impostazione qui descritta.
Prerequisiti e potenziali problemi
- Un VPS Ubuntu 24.04 KVM appena installato con privilegi root o sudo. Qualsiasi piano KVM è compatibile; la CLI è leggera e occupa pochi centinaia di MB di RAM a riposo.
- Node.js 20 o versioni successive. Questa è l'unica versione minima richiesta; il pacchetto della distribuzione è inferiore — consultare la sezione successiva.
- Connessione HTTPS in uscita (porta 443) verso le API di Google. Non sono necessarie porte in entrata; il software agisce come client e non come server, quindi non è necessario aprire porte nel firewall.
- Un metodo di autenticazione che non richieda un browser sul server: una Gemini API key da Google AI Studio, oppure un tunnel SSH verso un browser sulla propria macchina locale. L'uso della API-key è consigliato per script ed esecuzioni non interattive.
- Docker o Podman, solo se si desidera l'isolamento
--sandbox. Opzionale, trattato alla fine della guida.
Il problema comune che blocca tutti: il flusso di login gemini alla prima esecuzione è progettato per sistemi desktop. Tenta di aprire un browser e, su un sistema headless, fallisce o fornisce un link non funzionante. Scegliere il metodo di autenticazione prima di iniziare.
Node: il pacchetto della distro è troppo vecchio
Ubuntu 24.04 include Node 18.19.1 nei propri repository, con npm 9.2.0. Il package.json di Gemini CLI dichiara engines: { node: ">=20" }, e npm non blocca l'installazione in caso di mismatch di default — procede comunque e stampa un warning che indica la discrepanza:
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 }Ignorando il warning, la CLI viene eseguita su un runtime non supportato; il software si comporta in modo errato o crasha non appena tenta di utilizzare una API di Node 20+ che dovrebbe essere presente. Node 18 ha raggiunto la fine del ciclo di vita (end-of-life) nell'aprile 2025, quindi è comunque una soluzione non valida. Installa una versione LTS attuale prima di installare la CLI. Le due opzioni valide sono NodeSource (un repository apt firmato a livello di sistema) o nvm (un gestore di versioni per singolo utente). Scegline una.
NodeSource, se si desidera Node disponibile per ogni utente del sistema:
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 --versionnode --version deve stampare v20.x o superiore — v24.x è l'attuale LTS attiva. Controlla la pagina di NodeSource per lo script di configurazione attuale; il setup_24.x nell'URL è il valore da aggiornare quando viene rilasciata una nuova LTS.
nvm, se si preferisce mantenere Node nella home di un singolo utente senza usare sudo:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
source ~/.bashrc
nvm install --lts
node --versionIl v0.40.1 in quell'URL era attuale al momento della scrittura; controlla il README di nvm per l'ultima release e sostituisci la versione prima di eseguire il comando. nvm offre un vantaggio specifico per questo compito: installa Node e i suoi pacchetti globali sotto ~/.nvm, quindi il problema dei permessi di installazione globale descritto nella sezione successiva non si presenta. Se si utilizza nvm, è possibile saltare il passaggio relativo all'npm-prefix.
Install the CLI senza sudo npm -g
Il comando sudo npm install -g @google/gemini-cli sembra una soluzione valida, ma non usarlo. Un prefix globale di proprietà di root causa errori di permessi in ogni installazione successiva. Inoltre, lascia file di proprietà di root nella cache di npm che causeranno problemi tra mesi. Eseguendo un npm install -g standard (senza sudo) contro un Node di sistema, si ottiene questo errore:
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'npm sta tentando di scrivere in /usr/lib, ma l'utente non ha i permessi necessari. La soluzione non è usare sudo. Bisogna impostare il prefix globale di npm nella propria home directory, in modo che le installazioni globali finiscano in una cartella di proprietà dell'utente:
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 --versionL'uso di ~/.bashrc invece di ~/.profile è intenzionale: tmux — che userai per eseguire la CLI tra due sezioni — avvia una shell non-login che legge ~/.bashrc e ignora ~/.profile. Di conseguenza, una riga PATH in un file errato renderà gemini invisibile proprio dove serve. Il test consiste nel verificare che gemini --version stampi il numero di versione. Se ricevi invece gemini: command not found, l'export di PATH non è andato a buon fine; consulta le modalità di errore. Se utilizzi nvm, ignora completamente le righe relative al prefix: nvm installa già i pacchetti globali nella home.
Se hai eseguito sudo npm in precedenza e ora vedi Your cache folder contains root-owned files, ripara la configurazione con sudo chown -R $(id -u):$(id -g) ~/.npm.
Il problema dell'autenticazione headless e come risolverlo
Esegui gemini in modalità interattiva la prima volta; il comando proporrà l'accesso tramite il tuo account Google. Su un desktop, questo aprirà una scheda nel browser. Su un VPS headless non è presente un browser, quindi il processo stamperà un URL localhost da aprire manualmente, oppure fallirà con un errore simile a:
Failed to open browser. Please visit the following URL to authorize:
https://accounts.google.com/o/oauth2/v2/auth?...&redirect_uri=http://localhost:PORTIl problema è il redirect_uri=http://localhost:PORT. Anche se apri l'URL sul tuo laptop e approvi l'accesso, Google reindirizza a http://localhost:PORT — ovvero localhost sul server, una porta che il tuo laptop non può raggiungere. L'autenticazione non può completarsi.
Esistono due soluzioni valide.
La prima consiste nell'usare una API key, che è l'opzione predefinita corretta per un server. Crea una chiave in Google AI Studio (aistudio.google.com) e passala alla CLI come variabile d'ambiente; la CLI leggerà GEMINI_API_KEY e salterà completamente il processo tramite browser. Per quanto riguarda la sicurezza: non inserire la chiave in file leggibili da altri. Non digitare export GEMINI_API_KEY=AIza... nel prompt — la chiave verrebbe salvata in chiaro in ~/.bash_history. Non salvarla in file con permessi di lettura per altri utenti. Scrivila in un file con permessi 600 che la shell caricherà all'avvio:
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 ~/.bashrcchmod 600 garantisce che solo il tuo utente possa leggere il file. Verifica che la chiave sia stata caricata nell'ambiente con printenv GEMINI_API_KEY; se il comando non restituisce nulla, la CLI tenterà l'autenticazione tramite browser e fallirà. La CLI legge anche un file .env in ~/.gemini/ se preferisci questa configurazione — applica la stessa regola, quindi usa chmod 600 ~/.gemini/.env.
La seconda soluzione mantiene l'accesso con account Google personale (e il relativo piano gratuito) tramite il tunneling del callback OAuth verso il tuo laptop. Il limite è che il server loopback della CLI utilizza una porta casuale ad ogni esecuzione; non c'è quindi un indirizzo stabile da inoltrare, a meno di non fissarlo preventivamente con la variabile d'ambiente OAUTH_CALLBACK_PORT e inoltrare esattamente quella 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
geminiLa CLI non può aprire un browser, quindi stamperà l'URL di autenticazione; aprilo nel browser del tuo laptop, approva l'accesso e, quando Google reindirizzerà a http://localhost:8085/..., il tunnel SSH porterà la richiesta al server loopback sul VPS completando l'autenticazione. Se non fissi la porta, questa cambierà ad ogni esecuzione, rendendo impossibile l'intercettazione tramite un ssh -L configurato in precedenza. Questo metodo funziona, ma richiede l'intervento manuale su un browser, quindi non è adatto agli script. Per processi in background, usa la API key.
Per Vertex AI o un progetto Google Cloud invece di AI Studio, imposta GOOGLE_API_KEY insieme a GOOGLE_GENAI_USE_VERTEXAI=true, oppure GOOGLE_CLOUD_PROJECT per una licenza Code Assist — applica la stessa disciplina per le variabili d'ambiente e lo stesso metodo del file con permessi 600.
Eseguilo all'interno di tmux per evitare che la chiusura della sessione SSH interrompa il processo
Un processo gemini lanciato direttamente dalla shell SSH è un figlio di quella shell. Se la connessione cade — per un laptop chiuso, un Wi-Fi disconnesso o un timeout di inattività — sshd chiude il pseudo-terminale, la shell riceve un segnale SIGHUP e la CLI si interrompe. Un task avviato da dieci minuti per l'editing di file termina insieme alla sessione e, al riconnettersi, il processo non è più recuperabile.
tmux risolve il problema gestendo la shell al posto di sshd. Questo approccio è identico a quello utilizzato per eseguire un AI coding agent su un VPS remoto all'interno di tmux e funziona nello stesso modo anche qui:
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 geminitmux new -A -s gemini si connette a una sessione denominata gemini se esistente, oppure la crea se non presente; è il comando da eseguire subito dopo ogni login. La shell interna appartiene al server tmux in modalità detached, non alla sessione SSH, quindi la perdita della connessione non interrompe la CLI. Riconnettiti, esegui l'attach e ritroverai lo stesso scrollback.
Per esecuzioni scriptate non interattive, Gemini CLI dispone di una modalità headless: gemini -p "summarise the failing tests in this repo" stampa la risposta ed esce, mentre --output-format json fornisce un output leggibile dalle macchine per essere inviato tramite pipe. La modalità headless con una API key è ideale all'interno di una sessione tmux che esegue un job batch prolungato, o se avviata tramite cron — con un'eccezione: un job cron non carica i file di login. Per questo motivo, fornisci alla riga del crontab il proprio GEMINI_API_KEY (oppure fai in modo che il comando carichi ~/.gemini_env), altrimenti la CLI utilizzerà il flusso del browser e fallirà.
Sandboxing e permessi su un sistema che esegue anche produzione
Un agent con accesso alla shell è una shell. Gemini CLI può eseguire comandi e, per impostazione predefinita, richiede conferma prima di ogni operazione rischiosa. Tuttavia, gli utenti possono attivare --yolo (auto-approvazione di ogni chiamata di tool); in questo modo l'agent può eliminare file, fare push su git o interpellare servizi interni con i pieni privilegi dell'utente che lo esegue. Su un sistema che ospita anche la produzione, l'impatto non è ipotetico, ma rappresenta un reale blast radius.
Tre controlli, in ordine di efficacia:
- Eseguire l'agent come utente dedicato e senza privilegi. Non utilizzare root né utenti appartenenti a
sudo. Crea un utenteagentcon la propria home, installa Node e la CLI in quella directory; in questo modo un comando errato rimarrà confinato a quel solo account. Questa è la decisione con il valore più alto. - Non conservare le credenziali di produzione sul sistema. Niente
~/.aws/credentialsdi produzione, niente.envcopiati dall'ambiente di produzione e nessuna password di database con permessi di scrittura su risorse critiche. Fornisci credenziali di staging o in sola lettura. - Utilizzare il sandbox integrato. Con Docker o Podman installati,
gemini --sandbox(oGEMINI_SANDBOX=docker) esegue le chiamate di tool dell'agent all'interno di un container isolato dal filesystem e dalla rete dell'host. Non sostituisce l'uso di un utente senza privilegi, ma rappresenta un secondo livello di sicurezza efficace quando lo stesso VPS esegue carichi di lavoro reali.
Se Gemini CLI viene eseguito insieme ad altri strumenti self-hosted — ad esempio un MCP server che espone tool all'agent sullo stesso VPS — considera ogni nuova funzionalità come una superficie di attacco aggiuntiva raggiungibile dall'agent; limita i token forniti all'agent a un unico compito specifico.
Quota, costi e percorso di autenticazione scelto
Il percorso di autenticazione determina la modalità di fatturazione. Un account Google personale (percorso OAuth) utilizza il tier gratuito di Gemini Code Assist, con limiti reali per minuto e per giorno; il superamento di tali limiti causa errori di rate-limit fino al reset della finestra temporale. Una API key di AI Studio può essere gratuita o a pagamento a seconda del progetto: una chiave a pagamento aumenta i limiti e addebita il costo per token. L'autenticazione tramite Vertex e Cloud-project avviene tramite Google Cloud.
Due note pratiche. Un agent non supervisionato in un loop può consumare rapidamente la quota; monitoralo durante le prime esecuzioni prima di affidarlo a un cron job. Se la scelta di un modello server-side è dettata dalla privacy o dalla necessità di inferenza illimitata rispetto ai modelli ospitati da Google, è necessario uno strumento differente: l'auto-hosting di un open LLM con Ollama su un VPS mantiene i pesi e i prompt sulla propria macchina, a costo di eseguire un modello molto più piccolo rispetto a Gemini.
Mantenimento degli aggiornamenti
Gemini CLI riceve aggiornamenti frequenti. Poiché è stato installato in un prefix di proprietà dell'utente, gli aggiornamenti non richiedono l'uso di sudo:
npm install -g @google/gemini-cli@latest
gemini --versionEsistono diversi canali di rilascio: @latest è la versione stable, @preview è la preview settimanale, @nightly è la versione bleeding edge. Si consiglia di utilizzare @latest per sistemi di produzione. Con nvm, i pacchetti globali risiedono sotto la versione Node attiva; pertanto, dopo eseguire nvm use per cambiare versione di Node, potrebbe essere necessario reinstallare la CLI. Si consiglia di consultare le release notes invece di installare ogni singola patch.
Modalità di errore, con le stringhe esatte
npm WARN EBADENGINE Unsupported engine ... required: { node: '>=20' }, con conseguente crash della CLI durante l'esecuzione. Node è troppo vecchio — la distro utilizza la versione 18.19.1, che è fuori dal periodo di supporto (end-of-life). Installa Node 20+ tramite NodeSource o nvm, verifica con node --version; se sono installate più versioni di Node, verifica che which node punti alla nuova versione e non a /usr/bin/node.
npm error code EACCES / permission denied, mkdir '/usr/lib/node_modules/...'. Installazione globale in un prefix di proprietà root. Non usare sudo — imposta npm config set prefix ~/.npm-global, posiziona ~/.npm-global/bin su PATH e reinstalla con l'utente standard. Se un precedente sudo npm ha lasciato file di cache di proprietà root (Your cache folder contains root-owned files), esegui sudo chown -R $(id -u):$(id -g) ~/.npm.
Failed to open browser, un login bloccato, o un redirect_uri=http://localhost:PORT irraggiungibile. Il flusso OAuth richiede un browser non presente sul server, e il callback localhost punta al server invece che al laptop. Usa il metodo API-key (GEMINI_API_KEY), oppure fissa OAUTH_CALLBACK_PORT, inoltralo tramite SSH con ssh -L e apri l'URL localmente.
Il processo è terminato alla chiusura della sessione SSH. Hai eseguito gemini direttamente dalla shell SSH; il processo era un figlio di quella shell ed è terminato con la pty alla disconnessione. Non è possibile recuperarlo. Avvia ogni sessione con tmux new -A -s gemini ed esegui la CLI al suo interno.
L'autenticazione fallisce nonostante la chiave sia impostata — la CLI torna al selettore di autenticazione, oppure una richiesta restituisce API key not valid con HTTP 400. La chiave non è presente nell'ambiente rilevato dalla CLI. Verifica con printenv GEMINI_API_KEY; se è vuota, la variabile ~/.gemini_env non è stata caricata — verifica che la riga sia presente in ~/.bashrc, che le shell interattive (incluso tmux) leggono, ma non cron e altre shell non interattive. Anche uno spazio o una virgoletta errata nel valore della chiave produce API key not valid.
429 / RESOURCE_EXHAUSTED / un messaggio di rate-limit. Hai raggiunto la quota del tier utilizzato per l'autenticazione. Attendi il reset della finestra temporale, riduci la frequenza dell'agent o passa a una API key a pagamento. Un agent bloccato in un ciclo di retry continua a generare questo errore — interrompilo e verifica l'attività.
FAQ
Come autentico Gemini CLI su un server headless?
Usa una API key invece del login tramite browser. Crea una chiave in Google AI Studio, inseriscila in un file mode-600 che la tua shell carica (export GEMINI_API_KEY=...) e la CLI salterà completamente il flusso OAuth via browser. Se desideri specificamente il piano gratuito per account personali, blocca la porta loopback con OAUTH_CALLBACK_PORT=8085, inoltrala al tuo laptop con ssh -L 8085:localhost:8085 user@server e apri l'URL stampato localmente; tuttavia, questa procedura richiede la presenza di un browser, quindi non è adatta agli script.
Perché l'installazione globale tramite npm richiede sudo e come posso evitarlo?
Perché il prefix globale predefinito di npm è /usr/lib/node_modules, dove il tuo utente non ha permessi di scrittura; pertanto, un comando npm install -g fallisce con EACCES. La soluzione errata è sudo npm -g, che lascia file di proprietà di root che causano errori nelle installazioni successive. La soluzione corretta è puntare il prefix alla tua home (npm config set prefix ~/.npm-global) e aggiungere il suo bin a PATH, oppure usare nvm, che installa automaticamente i pacchetti globali sotto la tua home.
Come posso mantenere Gemini CLI in esecuzione dopo la disconnessione?
Eseguilo all'interno di tmux. Un processo avviato dalla shell SSH termina quando la connessione cade perché è un processo figlio di quella shell; tmux esegue la shell sotto un server detached che sopravvive alla disconnessione. Usa tmux new -A -s gemini, esegui gemini all'interno, scollega con Ctrl-b d e ricollega in seguito con tmux attach -t gemini.
È sicuro eseguire Gemini CLI su un server di produzione?
Solo con cautela, poiché un agente con accesso alla shell può eseguire qualsiasi operazione consentita all'utente che lo esegue. Eseguilo come utente dedicato non privilegiato senza permessi sudo, non conservare credenziali di produzione sulla macchina, evita l'auto-approvazione di --yolo e usa --sandbox (Docker o Podman) per isolare le chiamate degli strumenti dall'host. L'account sotto cui viene eseguito è più importante di qualsiasi singolo flag impostato.
Devo aprire porte sul firewall per Gemini CLI?
No. È un client che effettua chiamate HTTPS in uscita verso le API di Google, quindi richiede la porta 443 in uscita ma nessuna porta in entrata. Se utilizzi il tunnel OAuth, la porta di callback bloccata (ad esempio 8085) risiede su localhost ed è raggiungibile tramite il forwarding SSH, non tramite una porta in entrata aperta. Mantieni le connessioni in entrata bloccate.