Gemini CLI sur un VPS sans interface
Installez Gemini CLI sur un VPS sans interface : Node récent, install globale sans sudo, auth par clé API sans navigateur, tmux contre les coupures SSH.
Ce que vous construisez
Un Gemini CLI toujours actif sur un serveur qui vous appartient, accessible par SSH, qui exécute de longues tâches d'agent continuant à travailler après que vous avez fermé votre ordinateur portable. L'installation tient en trois commandes. Ce qui demande du travail, c'est tout ce qui suppose un bureau graphique : la CLI de Google veut ouvrir un navigateur pour vous connecter, et votre serveur n'en a pas. La majeure partie de ce guide couvre donc le parcours sans interface : un Node récent que la distribution ne vous fournira pas, une installation globale npm qui n'a pas besoin de root, une authentification sans navigateur avec une clé API que vous gardez hors de l'historique de votre shell, et tmux pour qu'une session SSH interrompue n'emporte pas avec elle une tâche en cours.
Gemini CLI est un programme Node open source (Apache-2.0) (@google/gemini-cli) qui dialogue avec les modèles Gemini de Google et peut lire et écrire des fichiers, exécuter des commandes shell et piloter des outils dans le répertoire de travail. Sur un VPS, c'est un petit agent toujours disponible que vous pouvez laisser travailler, ce qui explique pourquoi le compte sous lequel il s'exécute, et les identifiants présents sur la machine, comptent plus que n'importe quel réglage isolé ici.
Prérequis et les pièges à connaître
- Un VPS KVM Ubuntu 24.04 tout neuf avec root ou sudo. N'importe quel forfait KVM convient ; la CLI elle-même est légère, quelques centaines de Mo de RAM au repos.
- Node.js 20 ou plus récent. C'est le seul seuil de version strict, et le paquet de la distribution est en dessous ; voir la section suivante.
- Du HTTPS sortant (port 443) vers les API de Google. Aucun port entrant n'est nécessaire ; c'est un client, pas un serveur, vous n'ouvrez donc aucune brèche dans le pare-feu pour lui.
- Un moyen de vous authentifier sans navigateur sur le serveur : soit une clé API Gemini depuis Google AI Studio, soit un tunnel SSH vers un navigateur sur votre propre machine. Le parcours par clé API est celui qui passe à l'échelle pour les scripts et les exécutions sans surveillance.
- Docker ou Podman, uniquement si vous voulez l'isolation
--sandbox. Optionnel, traité vers la fin.
Le piège qui attrape tout le monde : le sympathique flux de connexion au premier lancement de gemini est conçu pour un poste de bureau. Il tente d'ouvrir un navigateur et, sur une machine sans interface, soit échoue, soit vous donne un lien qui ne fonctionne pas. Choisissez votre parcours d'authentification avant de commencer.
Node : le paquet de la distribution est trop ancien
Ubuntu 24.04 fournit Node 18.19.1 dans ses propres dépôts, associé à npm 9.2.0. Le package.json de Gemini CLI déclare engines: { node: ">=20" }, et npm ne bloque pas une incompatibilité par défaut : il installe quand même et affiche un avertissement qui nomme l'écart :
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 }Passez outre cet avertissement et la CLI s'exécute sur un runtime non pris en charge, où elle se comporte mal ou plante dès qu'elle atteint une API Node 20+ dont elle attend l'existence. Node 18 a également atteint sa fin de vie en avril 2025, c'est donc une impasse dans tous les cas. Installez une LTS récente avant d'installer la CLI. Les deux voies propres sont NodeSource (un dépôt apt signé pour tout le système) ou nvm (un gestionnaire de versions par utilisateur). Choisissez-en une.
NodeSource, si vous voulez que Node soit disponible pour chaque utilisateur de la machine :
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 doit afficher v20.x ou plus ; v24.x est la LTS active actuelle. Consultez la page NodeSource pour le script setup à jour ; le setup_24.x dans l'URL est la ligne à mettre à jour quand une LTS plus récente sort.
nvm, si vous préférez garder Node dans le répertoire personnel d'un seul utilisateur et ne jamais y toucher avec sudo :
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
source ~/.bashrc
nvm install --lts
node --versionLe v0.40.1 dans cette URL était à jour au moment de l'écriture ; consultez le README de nvm pour la dernière version et remplacez le numéro avant de lancer la commande. nvm a un vrai avantage pour cette tâche : il installe Node et ses paquets globaux sous ~/.nvm, si bien que le problème de permission d'installation globale de la section suivante ne se produit tout simplement jamais. Si vous choisissez la voie nvm, vous pouvez sauter l'étape du prefix npm.
Installer la CLI sans sudo npm -g
La commande tentante est sudo npm install -g @google/gemini-cli. Ne le faites pas. Un prefix global détenu par root produit des erreurs de permission à chaque installation ultérieure et laisse dans votre cache npm des fichiers détenus par root qui vous mordront des mois plus tard. Lancez un simple npm install -g (sans sudo) sur un Node système et vous obtenez l'autre échec :
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'C'est npm qui tente d'écrire dans /usr/lib, ce que votre utilisateur ne peut pas faire. La solution n'est pas sudo : il s'agit de pointer le prefix global de npm vers votre répertoire personnel pour que les installations globales atterrissent quelque part qui vous appartient :
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, et non ~/.profile, est un choix délibéré : tmux, dans lequel vous lancerez la CLI deux sections plus loin, démarre un shell non-login qui lit ~/.bashrc et ignore ~/.profile, si bien qu'une ligne PATH dans le mauvais fichier laisse gemini invisible exactement là où vous en avez besoin. Le test complet, c'est gemini --version qui affiche un numéro de version. Si vous obtenez plutôt gemini: command not found, votre export PATH n'a pas été pris en compte ; voir les modes de défaillance. Sous nvm, sautez entièrement les lignes de prefix : il installe déjà les paquets globaux sous votre répertoire personnel.
Si vous avez lancé sudo npm à un moment donné et voyez maintenant Your cache folder contains root-owned files, réparez-le une fois avec sudo chown -R $(id -u):$(id -g) ~/.npm.
Le problème d'authentification sans interface, et comment le contourner
Lancez gemini de manière interactive la première fois et il propose de vous connecter avec votre compte Google. Sur un poste de bureau, cela ouvre un onglet de navigateur. Sur un VPS sans interface, il n'y a pas de navigateur, donc le flux affiche soit une URL localhost qu'il s'attend à ce que vous ouvriez, soit échoue carrément avec quelque chose comme :
Failed to open browser. Please visit the following URL to authorize:
https://accounts.google.com/o/oauth2/v2/auth?...&redirect_uri=http://localhost:PORTLe piège, c'est le redirect_uri=http://localhost:PORT. Même si vous ouvrez cette URL sur votre ordinateur portable et l'approuvez, Google redirige vers http://localhost:PORT, c'est-à-dire localhost sur le serveur, un port que rien sur votre ordinateur portable ne peut atteindre. La connexion ne se termine jamais.
Il y a deux moyens honnêtes de s'en sortir.
Le premier est une clé API, et c'est le bon choix par défaut pour un serveur. Créez une clé dans Google AI Studio (aistudio.google.com) et fournissez-la à la CLI sous forme de variable d'environnement ; elle lit GEMINI_API_KEY et saute entièrement le flux du navigateur. Passons maintenant à la partie "la garder hors de l'historique et des fichiers lisibles par tous". Ne tapez pas export GEMINI_API_KEY=AIza... à l'invite : elle finit dans ~/.bash_history en clair, et ne la mettez pas dans un fichier que d'autres peuvent lire. Écrivez-la dans un fichier en mode 600 que le shell source au démarrage :
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 signifie que seul votre utilisateur peut lire le fichier. Confirmez que la clé est bien arrivée dans l'environnement avec printenv GEMINI_API_KEY ; si cela n'affiche rien, la CLI revient au flux du navigateur et échoue. Elle lit aussi un fichier .env dans ~/.gemini/ si vous préférez cette organisation ; même règle, donc chmod 600 ~/.gemini/.env.
Le deuxième moyen conserve la connexion par compte Google personnel (et son offre gratuite) en faisant transiter le callback OAuth par un tunnel vers votre ordinateur portable. Le hic, c'est que le serveur loopback de la CLI se lie à un port aléatoire à chaque exécution, il n'y a donc rien de stable à transférer à moins de le fixer d'abord avec la variable d'environnement OAUTH_CALLBACK_PORT, puis de transférer exactement ce port :
# 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 ne peut pas ouvrir de navigateur, elle affiche donc l'URL d'authentification ; ouvrez-la dans le navigateur de votre ordinateur portable, approuvez, et quand Google redirige vers http://localhost:8085/..., le transfert SSH l'achemine vers le serveur loopback du VPS et la connexion se termine. Laissez le port non fixé et il atterrit sur un nouveau port aléatoire à chaque exécution, qu'aucun ssh -L configuré à l'avance ne peut attraper. Cela fonctionne, mais il faut que vous soyez devant un navigateur, ce qui ne convient pas aux scripts. Pour tout ce que vous laissez tourner, utilisez la clé API.
Pour Vertex AI ou un projet Google Cloud plutôt qu'AI Studio, définissez GOOGLE_API_KEY avec GOOGLE_GENAI_USE_VERTEXAI=true, ou GOOGLE_CLOUD_PROJECT pour une licence Code Assist ; même discipline de variables d'environnement, même fichier en mode 600.
Lancez-le dans tmux pour qu'une session SSH interrompue ne le tue pas
Un processus gemini que vous lancez directement depuis votre shell SSH est un enfant de ce shell. Perdez la connexion (ordinateur portable fermé, Wi-Fi coupé, délai d'inactivité) et sshd démonte le pseudo-terminal, le shell reçoit SIGHUP et raccroche à son tour sur la CLI. Une tâche à dix minutes de l'édition de fichiers meurt avec elle, et à la reconnexion il n'y a aucun processus à récupérer.
tmux corrige cela en possédant le shell à la place de sshd. C'est le même schéma que faire tourner un agent de codage IA sur un VPS distant dans tmux, et il fonctionne de manière identique ici :
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 s'attache à une session nommée gemini si elle existe et la crée sinon, c'est donc la seule commande à lancer juste après chaque connexion. Le shell à l'intérieur appartient au serveur tmux détaché, pas à votre session SSH, donc couper la connexion laisse la CLI au travail. Reconnectez-vous, attachez-vous, et vous retrouvez le même historique de défilement.
Pour les exécutions scriptées et non interactives, Gemini CLI dispose d'un mode sans interface : gemini -p "summarise the failing tests in this repo" affiche une réponse et se termine, et --output-format json fournit une sortie lisible par une machine à rediriger ailleurs. Le mode sans interface avec une clé API est exactement ce que vous voulez dans une session tmux qui exécute un long traitement par lots, ou déclenché depuis une entrée cron ; avec une réserve : un job cron ne source aucun de vos fichiers de connexion, donnez donc à la ligne du crontab sa propre GEMINI_API_KEY (ou faites en sorte que la commande source ~/.gemini_env), sinon la CLI revient au flux du navigateur et échoue.
Sandboxing et permissions sur une machine qui fait aussi tourner la production
Un agent avec accès au shell est un shell. Gemini CLI peut exécuter des commandes, et par défaut il demande confirmation avant chaque commande risquée ; mais les gens se rabattent sur --yolo (approuver automatiquement chaque appel d'outil), et il peut alors supprimer des fichiers, pousser vers git ou solliciter des services internes avec toute l'autorité de l'utilisateur sous lequel il s'exécute. Sur une machine qui fait aussi tourner la production, c'est un vrai rayon d'impact, pas une hypothèse.
Trois garde-fous, par ordre de ce qu'ils vous apportent :
- Exécutez-le sous un utilisateur dédié et non privilégié. Pas root, pas membre de
sudo. Créez un utilisateuragentavec son propre répertoire personnel, installez-y Node et la CLI, et une instruction mal interprétée reste confinée à ce compte. C'est la décision qui a le plus de valeur à elle seule. - Gardez les identifiants de production hors de la machine. Pas de
~/.aws/credentialsde prod, pas de.envrecopié depuis la production, pas de mot de passe de base de données avec accès en écriture à quoi que ce soit d'important. Donnez-lui un identifiant de préproduction ou en lecture seule. - Utilisez le bac à sable intégré. Avec Docker ou Podman installé,
gemini --sandbox(ouGEMINI_SANDBOX=docker) exécute les appels d'outils de l'agent dans un conteneur isolé du système de fichiers et du réseau de l'hôte. Ce n'est pas un substitut à l'utilisateur non privilégié, mais c'est une solide seconde couche quand le même VPS fait du vrai travail.
Si vous faites tourner Gemini CLI à côté d'autres outils auto-hébergés (un serveur MCP exposant des outils à l'agent sur le même VPS, par exemple), considérez chaque capacité ajoutée comme une surface supplémentaire que l'agent peut atteindre, et limitez la portée des jetons qu'on lui confie à une seule tâche.
Quota, coût et le parcours d'authentification que vous avez choisi
Le parcours d'authentification décide de la façon dont vous êtes facturé. Un compte Google personnel (le parcours OAuth) utilise l'offre gratuite Gemini Code Assist, avec de vraies limites par minute et par jour ; dépassez-les et les requêtes renvoient une erreur de limite de débit jusqu'à la réinitialisation de la fenêtre. Une clé API d'AI Studio peut relever de l'offre gratuite ou être facturée selon le projet ; une clé facturée relève les limites et facture au jeton. L'authentification Vertex et par projet Cloud est facturée via Google Cloud.
Deux notes pratiques. Un agent sans surveillance dans une boucle peut brûler du quota rapidement, alors surveillez-le les premières fois avant de le confier à un job cron. Et si votre raison d'un modèle côté serveur est la confidentialité ou une inférence non facturée à l'usage plutôt que les modèles hébergés de Google, c'est un autre outil ; auto-héberger un LLM ouvert avec Ollama sur un VPS garde les poids et les prompts sur votre propre machine, au prix de faire tourner un modèle bien plus petit que Gemini.
Le maintenir à jour
Gemini CLI publie souvent. Comme vous l'avez installé dans un prefix détenu par l'utilisateur, les mises à jour n'ont jamais besoin de sudo :
npm install -g @google/gemini-cli@latest
gemini --versionIl existe des canaux de publication : @latest est stable, @preview est la préversion hebdomadaire, @nightly est la version de pointe ; épinglez @latest sur tout ce dont vous dépendez. Sous nvm, les paquets globaux vivent sous la version Node active, donc après un nvm use pour changer de Node vous devrez peut-être réinstaller la CLI. Lisez les notes de version plutôt que de courir après chaque correctif.
Modes de défaillance, avec les chaînes exactes
npm WARN EBADENGINE Unsupported engine ... required: { node: '>=20' }, puis la CLI qui plante à l'exécution. Node est trop ancien : le 18.19.1 de la distribution, qui est aussi en fin de vie. Installez Node 20+ depuis NodeSource ou nvm, confirmez avec node --version, et si vous avez plusieurs Node installés, vérifiez que which node pointe vers le nouveau et non vers /usr/bin/node.
npm error code EACCES / permission denied, mkdir '/usr/lib/node_modules/...'. Une installation globale dans un prefix détenu par root. Ne le sudoyez pas : définissez npm config set prefix ~/.npm-global, mettez ~/.npm-global/bin sur le PATH, et réinstallez sous votre utilisateur normal. Si un sudo npm antérieur a laissé des fichiers de cache détenus par root (Your cache folder contains root-owned files), lancez sudo chown -R $(id -u):$(id -g) ~/.npm.
Failed to open browser, une connexion qui reste bloquée, ou un redirect_uri=http://localhost:PORT que vous ne pouvez pas atteindre. Le flux OAuth veut un navigateur que le serveur n'a pas, et son callback localhost pointe vers le serveur, pas vers votre ordinateur portable. Utilisez le parcours par clé API (GEMINI_API_KEY), ou fixez OAUTH_CALLBACK_PORT, transférez-le par SSH avec ssh -L, et ouvrez l'URL en local.
Le processus a disparu quand SSH a coupé. Vous avez lancé gemini directement depuis le shell SSH, c'était donc un enfant de ce shell qui est mort avec le pty à la déconnexion. Rien à récupérer. Démarrez chaque session avec tmux new -A -s gemini et lancez la CLI à l'intérieur.
L'authentification échoue toujours alors que la clé est définie : la CLI revient à son sélecteur d'authentification, ou une requête renvoie API key not valid avec un HTTP 400. La clé n'est pas dans l'environnement que voit la CLI. Confirmez avec printenv GEMINI_API_KEY ; si c'est vide, votre ~/.gemini_env n'a jamais été sourcé : vérifiez que la ligne est dans ~/.bashrc, que les shells interactifs (tmux compris) lisent mais que cron et les autres shells non interactifs ne lisent pas. Un espace ou un guillemet parasite dans la valeur de la clé produit aussi API key not valid.
429 / RESOURCE_EXHAUSTED / un message de limite de débit. Vous avez atteint le quota de l'offre qu'utilise votre authentification. Attendez la réinitialisation de la fenêtre, ralentissez l'agent, ou passez à une clé API facturée. Un agent coincé dans une boucle de réessais continue de le heurter ; arrêtez-le et vérifiez ce qu'il fait.
FAQ
Comment authentifier Gemini CLI sur un serveur sans interface ?
Utilisez une clé API, pas la connexion par navigateur. Créez une clé dans Google AI Studio, mettez-la dans un fichier en mode 600 que votre shell source (export GEMINI_API_KEY=...), et la CLI saute entièrement le flux OAuth du navigateur. Si vous voulez spécifiquement l'offre gratuite du compte personnel, fixez le port loopback avec OAUTH_CALLBACK_PORT=8085, transférez-le vers votre ordinateur portable avec ssh -L 8085:localhost:8085 user@server, et ouvrez l'URL affichée en local ; mais cela exige votre présence devant un navigateur, ce qui ne convient pas aux scripts.
Pourquoi l'installation globale npm réclame-t-elle sudo, et comment l'éviter ?
Parce que le prefix global par défaut de npm est /usr/lib/node_modules, où votre utilisateur ne peut pas écrire, donc un simple npm install -g échoue avec EACCES. La mauvaise solution est sudo npm -g, qui laisse des fichiers détenus par root qui cassent les installations ultérieures. La bonne solution est de pointer le prefix vers votre répertoire personnel (npm config set prefix ~/.npm-global) et d'ajouter son bin au PATH, ou d'utiliser nvm, qui installe automatiquement les paquets globaux sous votre répertoire personnel.
Comment maintenir Gemini CLI en marche après ma déconnexion ?
Lancez-le dans tmux. Un processus démarré depuis votre shell SSH meurt quand la connexion coupe parce qu'il est un enfant de ce shell ; tmux fait tourner le shell sous un serveur détaché qui survit à la déconnexion. Utilisez tmux new -A -s gemini, lancez gemini à l'intérieur, détachez-vous avec Ctrl-b d, et rattachez-vous plus tard avec tmux attach -t gemini.
Est-il sûr de faire tourner Gemini CLI sur une machine de production ?
Seulement avec précaution, car un agent avec accès au shell peut faire tout ce que peut faire l'utilisateur sous lequel il s'exécute. Faites-le tourner sous un utilisateur dédié non privilégié sans sudo, gardez les identifiants de production hors de la machine, évitez l'auto-approbation --yolo, et utilisez --sandbox (Docker ou Podman) pour isoler les appels d'outils de l'hôte. Le compte sous lequel il s'exécute compte plus que n'importe quel drapeau isolé que vous positionnez.
Dois-je ouvrir des ports du pare-feu pour Gemini CLI ?
Non. C'est un client qui fait des appels HTTPS sortants vers les API de Google, il a donc besoin du port 443 sortant mais d'aucun port entrant. Si vous utilisez le tunnel OAuth, le port de callback fixé (disons 8085) vit sur localhost et est atteint via votre transfert SSH, pas via un port entrant ouvert. Gardez l'entrant verrouillé.