Gemini CLI installeren op een headless VPS
Leer Gemini CLI installeren op een VPS zonder browser. Gebruik Node, API-key authenticatie en tmux om langdurige taken veilig te laten draaien via SSH.
Wat u bouwt
Een altijd actieve Gemini CLI op een eigen server, bereikbaar via SSH. De CLI voert langdurige agent-taken uit die doorgaan nadat u uw laptop heeft afgesloten. De installatie bestaat uit drie commando's. De uitdaging ligt bij de onderdelen die een desktop vereisen: de CLI van Google wil een browser openen voor de login, maar uw server heeft geen browser. Daarom richt deze handleiding zich op de headless-methode. Dit omvat: een Node-versie die niet standaard in de distributie zit, een globale npm-installatie zonder root-rechten, browserloze authenticatie met een API-key die niet in uw shell-geschiedenis verschijnt, en tmux zodat een verbroken SSH-sessie een lopende taak niet stopt.
Gemini CLI is een open-source (Apache-2.0) Node-programma (@google/gemini-cli) dat communiceert met de Gemini-modellen van Google. Het kan bestanden lezen en schrijven, shell-commando's uitvoeren en tools in de werkmap aansturen. Op een VPS fungeert het als een kleine, altijd beschikbare agent die u kunt laten doorwerken. Daarom zijn het gebruikersaccount en de credentials op de server belangrijker dan de individuele instellingen in deze handleiding.
Vereisten en belangrijke aandachtspunten
- Een schone Ubuntu 24.04 KVM VPS met root- of sudo-rechten. Elk KVM-abonnement is geschikt; de CLI is lichtgewicht en verbruikt in rusttoestand slechts enkele honderden MB aan RAM.
- Node.js 20 of nieuwer. Dit is de minimale vereiste versie; het distributiepakket is een oudere versie — zie de volgende sectie.
- Uitgaande HTTPS-verbinding (poort 443) naar de API's van Google. Er zijn geen inkomende poorten nodig; dit is een client en geen server, dus u hoeft geen firewall-poort te openen.
- Een authenticatiemethode die geen browser op de server vereist: een Gemini API-key van Google AI Studio, of een SSH-tunnel naar een browser op uw eigen machine. De API-key methode is geschikt voor scripts en unattended runs.
- Docker of Podman, uitsluitend als u
--sandboxisolatie wilt gebruiken. Optioneel, wordt aan het einde behandeld.
Het probleem waar iedereen tegenaan loopt: de gemini login-flow bij de eerste uitvoering is ontworpen voor een desktopomgeving. De flow probeert een browser te openen. Op een headless systeem mislukt dit of krijgt u een link die niet werkt. Kies de juiste authenticatiemethode voordat u begint.
Node: het distro-pakket is te oud
Ubuntu 24.04 levert Node 18.19.1 via de eigen repositories, samen met npm 9.2.0. De package.json van Gemini CLI vereist engines: { node: ">=20" }. npm blokkeert een mismatch niet standaard; het installeert de pakketten en geeft een waarschuwing die het verschil aangeeft:
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 }Als u de waarschuwing negeert, draait de CLI op een niet-ondersteunde runtime. De CLI vertoont foutief gedrag of crasht zodra een Node 20+ API wordt aangeroepen. Node 18 is bovendien de einddatum (end-of-life) in april 2025 gepasseerd. Installeer een actuele LTS voordat u de CLI installeert. De twee betrouwbare methoden zijn NodeSource (een systeembrede signed apt-repo) of nvm (een versiebeheerder per gebruiker). Kies één methode.
NodeSource, als u Node beschikbaar wilt maken voor elke gebruiker op het systeem:
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 moet v20.x of hoger zijn — v24.x is de huidige actieve LTS. Controleer de NodeSource-pagina voor het actuele installatiescript; de setup_24.x in de URL moet worden aangepast wanneer er een nieuwe LTS beschikbaar komt.
nvm, als u Node liever in de home-directory van één gebruiker houdt zonder sudo te gebruiken:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
source ~/.bashrc
nvm install --lts
node --versionDe v0.40.1 in die URL was actueel tijdens het schrijven van deze tekst; controleer de README van nvm voor de nieuwste release en pas de versie aan voordat u het script uitvoert. nvm heeft een voordeel voor deze taak: het installeert Node en de globale pakketten onder ~/.nvm. Hierdoor ontstaat het probleem met globale installatie-rechten uit de volgende sectie niet. Als u voor nvm kiest, kunt u de stap met de npm-prefix overslaan.
Installeer de CLI zonder sudo npm -g
Het verleidelijke commando is sudo npm install -g @google/gemini-cli. Doe dit niet. Een globale prefix die eigendom is van root veroorzaakt permissiefouten bij elke volgende installatie. Bovendien blijven er root-bestanden achter in uw npm cache, wat maanden later problemen geeft. Voer een gewone (zonder sudo) npm install -g uit tegen een systeem Node en u krijgt de volgende fout:
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 probeert naar /usr/lib te schrijven, waar uw gebruiker geen rechten voor heeft. De oplossing is niet sudo — u moet de globale prefix van npm naar uw home directory wijzen. Zo worden globale installaties uitgevoerd op een locatie waar u eigenaar van bent:
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, en niet ~/.profile, is opzettelijk: tmux — wat u over twee secties gebruikt voor de CLI — start een non-login shell die ~/.bashrc leest en ~/.profile overslaat. Een PATH regel in het verkeerde bestand zorgt ervoor dat gemini onzichtbaar blijft op de plek waar u dit nodig heeft. gemini --version die een versienummer printen is de volledige test. Krijgt u in plaats daarvan gemini: command not found? Dan is uw PATH export niet geactiveerd — zie de foutmodi. Gebruik u nvm? Sla de prefix-regels volledig over: nvm installeert globals standaard in uw home.
Heeft u eerder sudo npm uitgevoerd en ziet u nu Your cache folder contains root-owned files? Herstel dit eenmalig met sudo chown -R $(id -u):$(id -g) ~/.npm.
Het headless authenticatieprobleem en hoe u dit oplost
Voer gemini de eerste keer interactief uit. De CLI biedt aan om in te loggen met uw Google-account. Op een desktop wordt hiervoor een browser-tabblad geopend. Op een headless VPS is er geen browser aanwezig. De workflow printt dan een localhost URL die u moet openen, of de actie mislukt direct met een foutmelding zoals:
Failed to open browser. Please visit the following URL to authorize:
https://accounts.google.com/o/oauth2/v2/auth?...&redirect_uri=http://localhost:PORTDe oorzaak is de redirect_uri=http://localhost:PORT. Zelfs als u de URL op uw laptop opent en goedkeurt, redirect Google naar http://localhost:PORT — localhost op de server. Dit is een poort die niet bereikbaar is vanaf uw laptop. De login wordt nooit voltooid.
Er zijn twee betrouwbare methoden.
De eerste methode is een API-key. Dit is de juiste standaardinstelling voor een server. Maak een sleutel aan in Google AI Studio (aistudio.google.com) en stel deze in als een omgevingsvariabele voor de CLI; de CLI leest GEMINI_API_KEY en slaat de browser-workflow volledig over. Let op de veiligheid: voorkom dat de sleutel in de geschiedenis of in leesbare bestanden terechtkomt. Typ export GEMINI_API_KEY=AIza... niet direct in de prompt — de sleutel wordt dan in cleartext opgeslagen in ~/.bash_history. Plaats de sleutel ook niet in een bestand dat voor anderen leesbaar is. Schrijf de sleutel naar een bestand met mode-600 dat de shell bij het opstarten inlaadt:
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 betekent dat alleen uw gebruiker het bestand kan lezen. Controleer of de sleutel correct in de omgevingsvariabelen staat met printenv GEMINI_API_KEY; als dit geen output geeft, valt de CLI terug op de browser-workflow en mislukt de actie. De CLI leest ook een .env bestand in ~/.gemini/ als u die structuur verkiest — hanteer dezelfde regels, dus gebruik chmod 600 ~/.gemini/.env.
De tweede methode maakt gebruik van de persoonlijke Google-account (en het gratis tarief) door de OAuth-callback via een tunnel naar uw laptop te sturen. Het probleem is dat de loopback-server van de CLI bij elke sessie een willekeurig poortnummer gebruikt. Er is dus geen stabiel poortnummer om door te sturen, tenzij u dit eerst vastzet met de OAUTH_CALLBACK_PORT omgevingsvariabele en vervolgens exact die poort doorstuurt:
# 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
geminiDe CLI kan geen browser openen en printt daarom de authenticatie-URL. Open deze URL in de browser op uw laptop en keur de aanvraag goed. Wanneer Google redirect naar http://localhost:8085/..., wordt de aanvraag via de SSH-tunnel naar de loopback-server op de VPS gestuurd en wordt de login voltooid. Als u de poort niet vastzet, krijgt u bij elke sessie een nieuw willekeurig poortnummer, wat niet te vangen is met een vooraf ingestelde ssh -L. Deze methode werkt, maar vereist dat u actief een browser gebruikt; het is daarom niet geschikt voor scripts. Gebruik voor processen die op de achtergrond draaien altijd de API-key.
Gebruik voor Vertex AI of een Google Cloud-project in plaats van AI Studio GOOGLE_API_KEY samen met GOOGLE_GENAI_USE_VERTEXAI=true, of GOOGLE_CLOUD_PROJECT voor een Code Assist-licentie — hanteer dezelfde discipline voor omgevingsvariabelen en dezelfde mode-600 bestanden.
Voer het uit in tmux zodat een verbroken SSH-sessie het proces niet beëindigt
Een gemini proces dat u direct vanuit uw SSH-shell start, is een child-proces van die shell. Verliest u de verbinding — door een dichtgeklapte laptop, wegvallende Wi-Fi of een idle timeout — dan breekt sshd de pseudo-terminal af. De shell ontvangt een SIGHUP en wordt vervolgens afgesloten. Een taak die tien minuten lang bestanden aan het bewerken was, stopt hiermee. Bij een nieuwe verbinding is het proces niet meer te herstellen.
tmux lost dit op door de shell te beheren in plaats van sshd. Dit is hetzelfde principe als het draaien van een AI coding agent op een remote VPS in tmux, en het werkt hier identiek:
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 maakt verbinding met een sessie genaamd gemini als deze bestaat, of maakt deze aan als deze niet bestaat. Dit is de enige opdracht die u direct na elke login moet uitvoeren. De shell binnenin behoort toe aan de detached tmux server en niet aan uw SSH-sessie. Hierdoor blijft de CLI actief als de verbinding wegvalt. Verbind opnieuw, attach de sessie, en u heeft direct weer toegang tot dezelfde scrollback.
Voor niet-interactieve, gescripte runs heeft Gemini CLI een headless mode: gemini -p "summarise the failing tests in this repo" printt een antwoord en stopt, en --output-format json geeft machine-readable output die naar een andere locatie gepiped kan worden. Headless mode met een API key is noodzakelijk binnen een tmux sessie die een langdurige batch job uitvoert, of wanneer de opdracht wordt uitgevoerd via een cron-entry. Er is één voorwaarde: een cron job laadt geen van uw login-bestanden. Geef de crontab-regel daarom een eigen GEMINI_API_KEY (of laat het commando ~/.gemini_env laden), anders valt de CLI terug op de browser-flow en mislukt de uitvoering.
Sandboxing en permissies op een systeem dat ook productie draait
Een agent met shell-toegang is een shell. Gemini CLI kan commando's uitvoeren. Standaard vraagt de CLI om toestemming voor elk risicovol commando. Gebruikers kiezen echter vaak voor --yolo (elke tool-aanroep automatisch goedkeuren). Hierdoor kan de agent bestanden verwijderen, commits naar git pushen of interne services aanroepen met de volledige autoriteit van de huidige gebruiker. Op een systeem dat ook productie draait, is dit een reëel risico en geen hypothetisch scenario.
Drie beheersmaatregelen, gerangschikt op effectiviteit:
- Voer het uit als een dedicated, beperkte gebruiker. Gebruik geen root en geen lid van
sudo. Maak eenagentgebruiker aan met een eigen home-directory. Installeer Node en de CLI in die directory. Een foutieve instructie blijft dan beperkt tot dat account. Dit is de belangrijkste maatregel. - Houd productie-credentials gescheiden van het systeem. Gebruik geen productie
~/.aws/credentials, kopieer geen.envvan de productieomgeving en gebruik geen database-wachtwoorden met schrijfrechten voor kritieke systemen. Gebruik een staging- of read-only credential. - Gebruik de ingebouwde sandbox. Wanneer Docker of Podman is geïnstalleerd, voert
gemini --sandbox(ofGEMINI_SANDBOX=docker) de tool-aanroepen van de agent uit in een container. Deze container is geïsoleerd van het host-filesystem en het netwerk. Dit vervangt de beperkte gebruiker niet, maar het is een sterke tweede beveiligingslaag wanneer dezelfde VPS ook andere taken uitvoert.
Als u Gemini CLI gebruikt naast andere zelfgehoste tools — zoals een MCP server die tools beschikbaar stelt aan de agent op dezelfde VPS — beschouw elke toegevoegde functie dan als een groter aanvalsoppervlak. Beperk de tokens die de agent ontvangt strikt tot één specifieke taak.
Quota, kosten en de gekozen authenticatiepad
Het authenticatiepad bepaalt de facturatie. Een persoonlijk Google-account (het OAuth-pad) maakt gebruik van de gratis Gemini Code Assist-tier met limieten per minuut en per dag. Als u deze limieten overschrijdt, ontvangt u een rate-limit error totdat het venster is gereset. Een API-key van AI Studio kan gratis zijn of in rekening worden gebracht, afhankelijk van het project. Een betaalde key verhoogt de limieten en brengt kosten in rekening per token. Authenticatie via Vertex en Cloud-projecten verloopt via Google Cloud.
Twee praktische opmerkingen. Een agent die in een loop draait zonder toezicht kan het quota snel verbruiken. Houd de uitvoering de eerste keren nauwlettend in de gaten voordat u deze automatiseert met een cron job. En als u een model aan de serverzijde gebruikt vanwege privacy of onbeperkte inferentie in plaats van de gehoste modellen van Google, dan is dat een andere tool. het zelf hosten van een open LLM met Ollama op een VPS houdt de weights en de prompts op uw eigen machine, maar dit gaat ten koste van het draaien van een veel kleiner model dan Gemini.
Het up-to-date houden
Gemini CLI krijgt regelmatig updates. Omdat u het heeft geïnstalleerd in een door de gebruiker beheerde prefix, zijn updates nooit met sudo nodig:
npm install -g @google/gemini-cli@latest
gemini --versionEr zijn verschillende releasekanalen: @latest is de stabiele versie, @preview is de wekelijkse preview en @nightly is de bleeding edge — gebruik @latest voor systemen waar u op vertrouwt. Bij gebruik van nvm staan globale packages onder de actieve Node-versie. Als u met nvm use naar een andere Node-versie wisselt, moet u de CLI mogelijk opnieuw installeren. Lees de release notes in plaats van elke patch handmatig te volgen.
Foutmodi, met de exacte strings
npm WARN EBADENGINE Unsupported engine ... required: { node: '>=20' }, gevolgd door het crashen van de CLI tijdens runtime. Node is te oud — de distro gebruikt versie 18.19.1, wat ook end-of-life is. Installeer Node 20+ via NodeSource of nvm, controleer dit met node --version, en als u meerdere versies van Node heeft geïnstalleerd, controleer dan of which node naar de nieuwe versie wijst en niet naar /usr/bin/node.
npm error code EACCES / permission denied, mkdir '/usr/lib/node_modules/...'. Een globale installatie in een prefix die eigendom is van root. Gebruik geen sudo — stel npm config set prefix ~/.npm-global in, plaats ~/.npm-global/bin op PATH, en installeer opnieuw als uw normale gebruiker. Als een eerdere sudo npm cachebestanden heeft achtergelaten die eigendom zijn van root (Your cache folder contains root-owned files), voer dan sudo chown -R $(id -u):$(id -g) ~/.npm uit.
Failed to open browser, een login die blijft hangen, of een redirect_uri=http://localhost:PORT die onbereikbaar is. De OAuth-flow vereist een browser die niet op de server aanwezig is, en de localhost callback wijst naar de server in plaats van naar uw laptop. Gebruik het API-key pad (GEMINI_API_KEY), of pin OAUTH_CALLBACK_PORT, stuur deze door via SSH met ssh -L, en open de URL lokaal.
Het proces is verdwenen toen de SSH-verbinding werd verbroken. U heeft gemini direct vanuit de SSH-shell uitgevoerd, waardoor het een child-proces van die shell was en stierf toen de pty werd verbroken bij disconnect. Er is niets te herstellen. Start elke sessie met tmux new -A -s gemini en voer de CLI daarbinnen uit.
Authenticatie mislukt nog steeds met de ingestelde key — de CLI keert terug naar de auth picker, of een verzoek geeft API key not valid met HTTP 400. De key staat niet in de omgeving die de CLI ziet. Controleer dit met printenv GEMINI_API_KEY; als deze leeg is, is uw ~/.gemini_env nooit geladen — controleer of de regel in ~/.bashrc staat, welke interactieve shells (inclusief tmux) lezen, maar cron en andere non-interactieve shells niet. Een extra spatie of aanhalingsteken in de key-waarde veroorzaakt ook API key not valid.
429 / RESOURCE_EXHAUSTED / een rate-limit bericht. U heeft het quotum bereikt van het niveau dat uw authenticatie gebruikt. Wacht tot de periode is gereset, vertraag de agent, of stap over naar een betaalde API-key. Een agent die vastzit in een retry-loop blijft dit oproepen — stop de agent en controleer de acties.
FAQ
Hoe authenticeer ik Gemini CLI op een headless server?
Gebruik een API-key in plaats van de browser-login. Maak een sleutel aan in Google AI Studio, plaats deze in een mode-600 bestand dat uw shell laadt (export GEMINI_API_KEY=...), en de CLI slaat de OAuth browser-flow volledig over. Als u specifiek de gratis laag van een persoonlijk account wilt gebruiken, verbind dan de loopback-poort met OAUTH_CALLBACK_PORT=8085, stuur deze door naar uw laptop met ssh -L 8085:localhost:8085 user@server, en open de weergegeven URL lokaal — maar dit vereist een browser, dus dit is niet geschikt voor scripts.
Waarom vraagt de npm global install om sudo en hoe voorkom ik dit?
Omdat de standaard globale prefix van npm /usr/lib/node_modules is, waar uw gebruiker geen schrijfrechten heeft. Een gewone npm install -g mislukt daarom met EACCES. De onjuiste oplossing is sudo npm -g, omdat dit bestanden met root-rechten achterlaat die latere installaties verstoren. De juiste oplossing is om de prefix naar uw home-directory (npm config set prefix ~/.npm-global) te wijzen en de bin toe te voegen aan PATH, of gebruik nvm, wat globale pakketten automatisch onder uw home-directory installeert.
Hoe houd ik Gemini CLI actief nadat ik de verbinding verbreek?
Voer het uit binnen tmux. Een proces dat is gestart vanuit uw SSH-shell stopt wanneer de verbinding wegvalt, omdat het een child-proces van die shell is; tmux draait de shell onder een detached server die de disconnect overleeft. Gebruik tmux new -A -s gemini, voer gemini uit binnen de sessie, ontkoppel met Ctrl-b d, en koppel later weer aan met tmux attach -t gemini.
Is het veilig om Gemini CLI op een productie-server uit te voeren?
Alleen met voorzichtigheid, omdat een agent met shell-toegang alles kan doen wat de gebruiker waarvoor deze draait ook kan doen. Voer het uit als een dedicated onbevoegde gebruiker zonder sudo-rechten, houd productie-credentials gescheiden van de machine, vermijd --yolo auto-approval, en gebruik --sandbox (Docker of Podman) om tool-aanroepen te isoleren van de host. Het account waaronder het draait is belangrijker dan enige individuele flag die u instelt.
Moet ik firewall-poorten openen voor Gemini CLI?
Nee. Het is een client die uitgaande HTTPS-aanroepen maakt naar de API's van Google, dus het heeft uitgaande poort 443 nodig maar geen inkomende poorten. Als u de OAuth-tunnel gebruikt, bevindt de gekoppelde callback-poort (bijvoorbeeld 8085) zich op localhost en is deze bereikbaar via uw SSH-forwarding, niet via een open inkomende poort. Houd inkomende poorten gesloten.