Gemini CLI su VPS headless: guida a SSH e tmux
Configura Gemini CLI su un VPS senza desktop: Node aggiornato, installazione npm globale senza sudo, autenticazione con API key e tmux per sopravvivere alle disconnessioni SSH.
Cosa stai configurando
Un Gemini CLI sempre attivo su un server di tua proprietà, accessibile tramite SSH, che esegue attività lunghe dell’agente anche dopo la chiusura del laptop. L’installazione richiede tre comandi. La parte più complessa riguarda tutto ciò che presuppone un desktop: la CLI di Google tenta di aprire un browser per l’autenticazione, ma sul server non è disponibile. Per questo, gran parte della guida descrive il funzionamento headless, una versione recente di Node che la distribuzione non fornisce, un’installazione globale tramite npm che non richiede root, l’autenticazione senza browser con una chiave API che non viene salvata nella cronologia della shell e tmux, in modo che una sessione SSH interrotta non termini un’attività in esecuzione.
Gemini CLI è un programma Node open source (Apache-2.0) (@google/gemini-cli) che comunica con i modelli Gemini di Google e può leggere e scrivere file, eseguire comandi shell e utilizzare strumenti nella directory di lavoro. Su un VPS è un agente piccolo e sempre disponibile che può continuare a lavorare, quindi l’account con cui viene eseguito e le credenziali presenti sul server sono più importanti di qualsiasi singola impostazione descritta qui.
Prerequisiti e aspetti critici da conoscere
- Un VPS KVM Ubuntu 24.04 appena installato, con accesso root o sudo. Qualsiasi piano KVM è sufficiente; la CLI richiede poche risorse e usa poche centinaia di MB di RAM quando è inattiva.
- Node.js 20 o versione successiva. Questo è l'unico requisito minimo rigido per la versione; il pacchetto della distribuzione è precedente, come spiegato nella sezione successiva. Node 20 ha raggiunto il termine del supporto il 30 aprile 2026, quindi installa la versione 24.
- Accesso HTTPS in uscita (porta 443) alle API di Google. Non sono necessarie porte in ingresso; si tratta di un client, non di un server, quindi non devi aprire porte aggiuntive nel firewall.
- Un metodo di autenticazione che non richieda un browser sul server: una chiave API Gemini a pagamento di Google AI Studio oppure l'accesso con account Google. Su un server headless, quest'ultimo metodo richiede di incollare un codice nel terminale. La chiave API è il metodo più adatto per script ed esecuzioni non interattive.
- Docker o Podman, solo se vuoi usare l'isolamento
--sandbox. È facoltativo e viene trattato verso la fine.
L'aspetto critico che ora causa più problemi riguarda l'account, non il browser. Il 19 maggio 2026 Google ha annunciato che dal 18 giugno 2026 Gemini CLI avrebbe smesso di elaborare richieste per gli abbonati a Google AI Pro e Ultra e per gli utenti che lo utilizzano gratuitamente. Google indirizza questi utenti al prodotto sostitutivo, Antigravity CLI (agy). Gemini CLI continua a funzionare con chiavi API Gemini a pagamento, chiavi API Gemini Enterprise Agent Platform e una licenza Gemini Code Assist Standard o Enterprise dell'organizzazione. Scegli il metodo di autenticazione prima di iniziare.
Node: il pacchetto della distribuzione è troppo vecchio
Ubuntu 24.04 include Node 18.19.1 nei propri repository, insieme a npm 9.2.0. Il package.json di Gemini CLI dichiara engines: { node: ">=20" }. Per impostazione predefinita, npm non interrompe l'installazione quando rileva una versione non compatibile: procede comunque e stampa un avviso che indica la differenza:
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 }Se si ignora questo avviso, la CLI viene eseguita su un runtime non supportato. Può quindi funzionare in modo anomalo o arrestarsi non appena raggiunge un'API di Node 20 o superiore che si aspetta di trovare. Inoltre, Node 18 ha raggiunto il termine del ciclo di vita ad aprile 2025, quindi non è comunque una soluzione praticabile. Installare una versione LTS corrente prima di installare la CLI. Le due opzioni corrette sono NodeSource, un repository apt con firma digitale disponibile a livello di sistema, oppure nvm, un gestore delle versioni per singolo utente. Sceglierne una.
NodeSource, se si vuole rendere Node disponibile a tutti gli utenti del server:
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 restituire v20.x o una versione superiore per soddisfare i requisiti della CLI. Tuttavia, Node 20 ha raggiunto il termine del ciclo di vita il 30 aprile 2026, quindi puntare a v24.x, l'attuale versione LTS attiva. Node 26 è programmato per diventare la versione LTS attiva il 28 ottobre 2026. Consultare la pagina di NodeSource per lo script di configurazione corrente; setup_24.x nell'URL indica il valore da aggiornare quando viene rilasciata una nuova versione LTS.
nvm, se si preferisce mantenere Node nella home di un solo utente e non modificarlo mai con sudo:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
source ~/.bashrc
nvm install --lts
node --versionv0.40.1 nell'URL era la versione corrente al momento della redazione di questo testo; consultare il README di nvm per conoscere l'ultima release e sostituire la versione prima di eseguire il comando. nvm offre un vantaggio concreto in questo scenario: installa Node e i relativi pacchetti globali in ~/.nvm, quindi il problema dei permessi durante l'installazione globale descritto nella sezione successiva non si verifica. Se si sceglie nvm, si può saltare il passaggio relativo al prefisso di npm.
Installare la CLI senza sudo npm -g
Il comando più immediato è sudo npm install -g @google/gemini-cli. Non usarlo. Un prefisso globale di proprietà di root causa errori di autorizzazione a ogni installazione successiva e lascia file di proprietà di root nella cache di npm, che possono creare problemi anche mesi dopo. Eseguendo un semplice npm install -g, senza sudo, su un'installazione di Node gestita dal sistema, si verifica l'altro 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, dove il tuo utente non dispone delle autorizzazioni necessarie. La soluzione non è usare sudo, ma impostare il prefisso globale di npm nella directory home, in modo che le installazioni globali finiscano in una posizione di tua proprietà:
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 non ~/.profile, è intenzionale: tra due sezioni da questo punto, eseguirai la CLI all'interno di tmux. tmux avvia una shell non di login che legge ~/.bashrc e ignora ~/.profile. Una riga PATH inserita nel file errato rende quindi gemini invisibile esattamente nel contesto in cui ti serve. L'output di gemini --version con un numero di versione è l'unico test necessario. Se invece ottieni gemini: command not found, l'esportazione PATH non è stata applicata; consulta le modalità di errore. Con nvm, ignora completamente le righe relative al prefisso: nvm installa già i pacchetti globali nella tua home.
Se in precedenza hai eseguito sudo npm e ora visualizzi Your cache folder contains root-owned files, correggi il problema una volta sola con sudo chown -R $(id -u):$(id -g) ~/.npm.
Il problema dell'autenticazione senza interfaccia grafica e come aggirarlo
Eseguire gemini in modalità interattiva la prima volta mostra l'opzione per accedere con il proprio account Google. Su un desktop viene aperta una scheda del browser. Su un VPS Linux headless, la CLI controlla prima la presenza di un display e, se nessuna tra DISPLAY, WAYLAND_DISPLAY o MIR_SOCKET è impostata, non prova ad avviare alcun browser. Stampa un link di accesso e attende che venga incollato un codice:
Please visit the following URL to authorize the application:
https://accounts.google.com/o/oauth2/v2/auth?...
Enter the authorization code:Questo flusso funziona tramite una semplice connessione SSH, ma richiede l'accesso a un browser ogni volta. Inoltre, dal 18 giugno 2026, consente l'accesso solo se l'account Google è ancora supportato da Gemini CLI.
Esistono due modalità corrette per procedere.
La prima è una chiave API ed è l'impostazione predefinita consigliata per un server. Creare una chiave in Google AI Studio (aistudio.google.com) in un progetto con la fatturazione attiva, perché Gemini CLI non supporta più l'uso gratuito, quindi passarla alla CLI tramite una variabile d'ambiente: legge GEMINI_API_KEY e salta completamente il flusso del browser. Resta da evitare che la chiave finisca nella cronologia o in file leggibili da tutti. Non digitare export GEMINI_API_KEY=AIza... al prompt: il valore viene salvato in chiaro in ~/.bash_history. Non inserirlo neppure in un file leggibile da altri utenti. Scriverlo in un file con permessi 600 che la shell carica 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 significa che solo il proprio utente può leggere il file. Verificare che la chiave sia stata caricata nell'ambiente con printenv GEMINI_API_KEY. Se il comando non stampa nulla, la CLI torna alla selezione del metodo di autenticazione invece di usare la chiave. La CLI legge anche un file .env in ~/.gemini/, se si preferisce questa struttura. La regola è la stessa: chmod 600 ~/.gemini/.env.
La seconda modalità è l'accesso tramite Google. Su un sistema headless non richiede alcun tunnel né una porta aperta. Dal 18 giugno 2026 è utile soprattutto con una licenza Gemini Code Assist Standard o Enterprise dell'organizzazione; impostare anche GOOGLE_CLOUD_PROJECT. Gli account personali gratuiti e gli abbonamenti Google AI Pro o Ultra non sono più supportati. Avviare la CLI tramite una normale sessione SSH e scegliere Sign in with Google:
geminiCopiare l'URL stampato nel browser del laptop e autorizzare l'accesso. Google reindirizza a https://codeassist.google.com/authcode, che mostra un codice di autorizzazione. Incollarlo al prompt Enter the authorization code: sul VPS per completare l'accesso. Sul server non resta in ascolto alcun processo in attesa di una callback. Non è quindi necessario riservare una porta né configurare ssh -L. OAUTH_CALLBACK_PORT è rilevante solo per il flusso tramite loopback che la CLI usa quando rileva un display. Se ci si connette con l'inoltro X11 (ssh -X), DISPLAY viene impostata e la CLI usa invece quel flusso tramite loopback, con un reindirizzamento a http://127.0.0.1:PORT/oauth2callback sul server. Eseguire NO_BROWSER=true gemini per forzare il flusso con incollaggio del codice. Funziona, ma richiede la presenza dell'utente davanti a un browser e quindi non è adatto agli script. Per qualsiasi processo lasciato in esecuzione, usare la chiave API.
Per usare Vertex AI o un progetto Google Cloud invece di AI Studio, impostare GOOGLE_API_KEY insieme a GOOGLE_GENAI_USE_VERTEXAI=true, oppure GOOGLE_CLOUD_PROJECT per una licenza Code Assist. Applicare le stesse regole per le variabili d'ambiente e usare lo stesso file con permessi 600.
Eseguilo all’interno di tmux, così una sessione SSH interrotta non lo termina
Un processo gemini avviato direttamente dalla shell SSH è figlio di quella shell. Se perdi la connessione, chiudi il portatile, il Wi-Fi si interrompe o scade il timeout di inattività, sshd chiude il pseudo-terminale, la shell riceve SIGHUP e a sua volta interrompe la CLI. Un’attività che sta modificando file da dieci minuti termina insieme alla sessione e, alla riconnessione, non c’è alcun processo da recuperare.
tmux risolve il problema gestendo la shell, invece di lasciare che sia sshd a gestirla. È lo stesso schema usato per eseguire un agente di coding AI su un VPS remoto all’interno di tmux e qui funziona nello stesso modo:
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 collega a una sessione denominata gemini se esiste e la crea se non esiste. Per questo è il comando da eseguire subito dopo ogni accesso. La shell interna appartiene al server tmux scollegato, non alla sessione SSH. Se la connessione cade, la CLI continua a funzionare. Riconnettiti, collegati alla sessione e ritroverai lo stesso scrollback. Se finisci per eseguire più sessioni dell’agente sulla stessa macchina, una per ogni sessione tmux, in questo contesto non possono comunicare tra loro, a differenza di Claude Code, dove una sessione può passare testo a un’altra sullo stesso VPS. Mantieni quindi indipendenti i singoli processi Gemini oppure coordinateli tramite file su disco.
Per le esecuzioni non interattive avviate tramite script, Gemini CLI dispone di una modalità headless: gemini -p "summarise the failing tests in this repo" stampa una risposta e termina, mentre --output-format json produce un output leggibile dalle macchine da inoltrare altrove tramite pipe. La modalità headless con una API key è esattamente ciò che serve all’interno di una sessione tmux che esegue un lungo job batch oppure quando viene avviata da una voce cron, con una precisazione: un job cron non carica alcun file della sessione di login. Assegna quindi alla riga crontab un proprio GEMINI_API_KEY oppure fai in modo che il comando carichi ~/.gemini_env, altrimenti l’esecuzione fallisce perché mancano le credenziali.
Sandboxing e permessi su un server che esegue anche servizi di produzione
Un agente con accesso alla shell dispone di fatto di una shell. Gemini CLI può eseguire comandi e, per impostazione predefinita, chiede conferma prima di ogni comando rischioso. Tuttavia, è facile ricorrere a --yolo (approvazione automatica di ogni chiamata agli strumenti). In questo modo l'agente può eliminare file, eseguire il push su git o raggiungere servizi interni con tutti i privilegi dell'utente con cui viene eseguito. Su un server che esegue anche servizi di produzione, il raggio d'azione di un incidente è concreto, non ipotetico.
Tre controlli, in ordine di efficacia:
- Eseguirlo con un utente dedicato e senza privilegi. Non root e non appartenente a
sudo. Create un utenteagentcon la propria home, installate Node e la CLI per quell'utente: un'istruzione interpretata in modo errato resterà confinata a quell'account. Questa è la decisione con il maggiore impatto. - Tenete le credenziali di produzione fuori dal server. Nessun
~/.aws/credentialsdi produzione, nessun.envcopiato dall'ambiente di produzione e nessuna password del database con accesso in scrittura a risorse importanti. Usate una credenziale di staging o di sola lettura. - Usate il sandbox integrato. Con Docker o Podman installato,
gemini --sandbox(oGEMINI_SANDBOX=docker) esegue le chiamate dell'agente agli strumenti all'interno di un container che monta soltanto la directory del progetto corrente, non il resto del filesystem dell'host. Non sostituisce l'utente senza privilegi, ma costituisce un secondo livello di protezione efficace quando lo stesso VPS svolge attività reali.
Se eseguite Gemini CLI accanto ad altri strumenti self-hosted, ad esempio un server MCP che espone strumenti all'agente sullo stesso VPS, considerate ogni nuova funzionalità come un'ulteriore superficie raggiungibile dall'agente e limitate i token che gli assegnate a una sola attività.
Quota, costi e percorso di autenticazione scelto
Il percorso di autenticazione determina come vengono addebitati i costi e, dal 18 giugno 2026, anche se il servizio è disponibile. Da quella data, secondo l'annuncio di Google, Gemini CLI ha smesso di gestire richieste per gli abbonati a Google AI Pro e Ultra e per chiunque lo utilizzi gratuitamente. Rientrano in questo caso il livello gratuito degli account personali e le chiavi API non fatturate. Il servizio rimane disponibile tramite chiavi API Gemini a pagamento e chiavi API Gemini Enterprise Agent Platform, con addebito per token, nonché per le organizzazioni con una licenza Gemini Code Assist Standard o Enterprise o con altro accesso a Google Cloud, con fatturazione tramite Google Cloud. Ogni livello continua ad avere limiti per minuto e per giorno. Se li superi, le richieste restituiscono un errore di limitazione della frequenza finché la finestra non viene ripristinata.
Due note pratiche. Un agente non supervisionato inserito in un ciclo può consumare rapidamente la quota, quindi monitoralo le prime volte prima di affidarlo a un cron job. Se invece il motivo per eseguire un modello sul server è la privacy o l'inferenza senza limiti di utilizzo, anziché l'uso dei modelli ospitati da Google, si tratta di uno strumento diverso: ospitare autonomamente un LLM open source con Ollama su un VPS mantiene i pesi e i prompt sul tuo server, ma richiede di eseguire un modello molto più piccolo di Gemini.
Mantenerlo actualizado
Gemini CLI se actualiza con frecuencia. Como lo instalaste en un prefijo propiedad del usuario, las actualizaciones no requieren nunca sudo:
npm install -g @google/gemini-cli@latest
gemini --versionHay varios canales de lanzamiento: @latest es el estable, @preview es la versión preliminar semanal y @nightly es la versión más reciente y menos probada; fija @latest en cualquier entorno del que dependas. Con nvm, los paquetes globales se almacenan nella versione attiva di Node, por lo que después de nvm use para cambiar de versión de Node puede ser necesario reinstalar la CLI. Consulta las notas de la versión en lugar de perseguir cada parche.
Modalità di errore, con le stringhe esatte
npm WARN EBADENGINE Unsupported engine ... required: { node: '>=20' }, quindi la CLI si arresta durante l'esecuzione. Node è troppo vecchio: la distribuzione usa la versione 18.19.1, che ha inoltre superato la fine del ciclo di vita. Installare una versione LTS attuale da NodeSource o tramite nvm (Node 20 soddisfa il requisito minimo della CLI, ma ha a sua volta raggiunto la fine del ciclo di vita ad aprile 2026), verificare con node --version e, se sono installate più versioni di Node, controllare che which node punti alla nuova versione e non a /usr/bin/node.
npm error code EACCES / permission denied, mkdir '/usr/lib/node_modules/...'. È stata eseguita un'installazione globale in un prefisso di proprietà di root. Non usare sudo, impostare npm config set prefix ~/.npm-global, aggiungere ~/.npm-global/bin a PATH e reinstallare come utente normale. Se un precedente sudo npm ha lasciato file di cache di proprietà di root (Your cache folder contains root-owned files), eseguire sudo chown -R $(id -u):$(id -g) ~/.npm.
Failed to open browser oppure un redirect_uri che punta a http://127.0.0.1:PORT, non raggiungibile. La CLI ha rilevato una variabile di visualizzazione, spesso proveniente da ssh -X, e ha scelto il flusso loopback, il cui callback termina sul server. Eseguire NO_BROWSER=true gemini per ottenere il flusso con incolla del codice oppure usare il percorso con chiave API (GEMINI_API_KEY). In una normale sessione SSH dovrebbe invece comparire Enter the authorization code:; approvare l'URL nel browser del laptop e incollare il codice mostrato da Google.
Il processo è scomparso quando la sessione SSH si è interrotta. Hai eseguito gemini direttamente dalla shell SSH, quindi il processo era figlio di quella shell ed è terminato insieme allo pseudo-terminale alla disconnessione. Non c'è nulla da recuperare. Avvia ogni sessione con tmux new -A -s gemini ed esegui la CLI al suo interno.
L'autenticazione continua a non riuscire con la chiave 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. Verificare con printenv GEMINI_API_KEY; se il risultato è vuoto, il file ~/.gemini_env non è mai stato acquisito. Controllare che la riga si trovi in ~/.bashrc, che viene letto dalle shell interattive, incluso tmux, ma non da cron e dalle altre shell non interattive. Anche uno spazio o una virgoletta non prevista all'interno del valore della chiave produce API key not valid.
429 / RESOURCE_EXHAUSTED / un messaggio di limite della frequenza. È stata raggiunta la quota del livello utilizzato dall'autenticazione. Attendere il ripristino della finestra, rallentare l'agent oppure passare a una chiave API con fatturazione. Un agent bloccato in un ciclo di nuovi tentativi continua a raggiungere questo limite: arrestarlo e verificare che cosa sta facendo.
FAQ
Come autentico Gemini CLI su un server headless?
Usa una chiave API a pagamento, non l'accesso tramite browser. Crea una chiave in Google AI Studio su un progetto con fatturazione attiva, inseriscila in un file con modalità 600 che la shell carica (export GEMINI_API_KEY=...) e la CLI salta completamente il flusso OAuth tramite browser. Se invece accedi con Google, ad esempio con una licenza Code Assist Standard o Enterprise, la CLI sul server headless stampa un URL; aprilo sul laptop, approva l'accesso e incolla il codice mostrato da Google al prompt Enter the authorization code:. Non è necessario fissare alcuna porta né creare un tunnel, ma devi essere presente davanti a un browser, quindi questa procedura non è adatta agli script. Gli account personali gratuiti non sono supportati da Gemini CLI dal 18 giugno 2026.
Perché l'installazione globale di npm richiede sudo e come posso evitarlo?
Perché il prefisso globale predefinito di npm è /usr/lib/node_modules, su cui il tuo utente non ha permessi di scrittura; per questo un semplice npm install -g fallisce con EACCES. La correzione sbagliata è sudo npm -g, che lascia file di proprietà di root e causa problemi nelle installazioni successive. La soluzione corretta consiste nell'impostare il prefisso sulla tua home (npm config set prefix ~/.npm-global) e aggiungere il relativo bin a PATH, oppure usare nvm, che installa automaticamente i pacchetti globali nella tua home.
Come mantengo Gemini CLI in esecuzione dopo la disconnessione?
Eseguilo all'interno di tmux. Un processo avviato dalla shell SSH termina quando la connessione cade, perché è figlio di quella shell; tmux esegue la shell sotto un server scollegato che sopravvive alla disconnessione. Usa tmux new -A -s gemini, esegui gemini al suo interno, scollegati con Ctrl-b d e riconnettiti in seguito con tmux attach -t gemini.
È sicuro eseguire Gemini CLI su un server di produzione?
Solo con cautela, perché un agente con accesso alla shell può eseguire qualsiasi operazione consentita all'utente con cui gira. Eseguilo con un utente dedicato senza privilegi e senza sudo, non conservare le credenziali di produzione sul server, evita --yolo per l'approvazione automatica e usa --sandbox (Docker o Podman) per isolare le chiamate agli strumenti dal sistema host. L'account con cui viene eseguito conta più di qualsiasi singolo flag configurato.
Devo aprire porte del firewall per Gemini CLI?
No. È un client che effettua chiamate HTTPS in uscita alle API di Google, quindi richiede la porta 443 in uscita ma nessuna porta in ingresso. Anche l'accesso a Google da un server headless non richiede porte: incolli un codice nel terminale invece di ricevere un callback sul server. Mantieni bloccate le connessioni in ingresso.