Cómo ejecutar Gemini CLI en un VPS sin interfaz gráfica
Ejecute Gemini CLI de Google en un VPS sin navegador: use Node actual, instalación global de npm sin sudo, autenticación por API key y tmux ante cortes SSH.
Qué está construyendo
Un Gemini CLI siempre activo en un servidor que usted administra, accesible mediante SSH y capaz de ejecutar tareas largas del agente que siguen funcionando después de cerrar el portátil. La instalación requiere tres comandos. El trabajo está en todo lo que presupone un entorno de escritorio: la CLI de Google intenta abrir un navegador para iniciar sesión, pero el servidor no tiene ninguno. Por eso, la mayor parte de esta guía cubre el procedimiento sin interfaz gráfica, una versión actual de Node que la distribución no proporciona, una instalación global de npm que no requiere root, autenticación sin navegador mediante una clave de API que se mantiene fuera del historial del shell y tmux, para que una sesión SSH interrumpida no detenga la tarea en ejecución.
Gemini CLI es un programa de Node de código abierto (Apache-2.0) (@google/gemini-cli) que se comunica con los modelos Gemini de Google y puede leer y escribir archivos, ejecutar comandos de shell y utilizar herramientas en el directorio de trabajo. En un VPS, es un agente pequeño y siempre disponible que puede dejar ejecutándose. Por eso, la cuenta con la que se ejecuta y las credenciales almacenadas en el servidor son más importantes que cualquier ajuste concreto de esta guía.
Requisitos previos y problemas importantes
- Un VPS KVM nuevo con Ubuntu 24.04 y acceso como root o mediante sudo. Cualquier plan KVM sirve; la CLI consume pocos recursos, unos cientos de MB de RAM en reposo.
- Node.js 20 o posterior. Este es el único requisito mínimo estricto de versión y el paquete de la distribución es anterior; consulte la sección siguiente.
- HTTPS saliente (puerto 443) hacia las API de Google. No se necesitan puertos entrantes; es un cliente, no un servidor, por lo que no debe abrir ninguna excepción en el firewall.
- Un método de autenticación que no requiera un navegador en el servidor: una clave de API de Gemini de Google AI Studio o un túnel SSH hacia un navegador de su propio equipo. El método con clave de API es el que permite ejecutar scripts y procesos sin supervisión.
- Docker o Podman, sólo si desea el aislamiento de
--sandbox. Es opcional y se explica cerca del final.
El problema que afecta a todos: el flujo de inicio de sesión inicial de gemini está diseñado para un equipo de escritorio. Intenta abrir un navegador y, en un servidor sin interfaz gráfica, falla o muestra un enlace que no funciona. Decida el método de autenticación antes de empezar.
Node: el paquete de la distribución es demasiado antiguo
Ubuntu 24.04 incluye Node 18.19.1 en sus propios repositorios, junto con npm 9.2.0. package.json de Gemini CLI declara engines: { node: ">=20" }, y npm no detiene la instalación por una incompatibilidad de forma predeterminada: continúa, instala el paquete y muestra una advertencia que indica la diferencia:
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 }Si ignora esa advertencia, la CLI se ejecuta con un runtime no compatible. Puede comportarse de forma incorrecta o bloquearse en cuanto use una API de Node 20 o posterior que espera encontrar. Además, Node 18 llegó al final de su vida útil en abril de 2025, por lo que no es una opción viable. Instale una versión LTS actual antes de instalar la CLI. Hay dos opciones adecuadas: NodeSource, un repositorio apt firmado y disponible para todo el sistema, o nvm, un gestor de versiones por usuario. Elija una.
NodeSource, si quiere que Node esté disponible para todos los usuarios 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 debe mostrar v20.x o una versión posterior. v24.x es la versión LTS activa actual. Consulte la página de NodeSource para obtener el script de configuración actual. El setup_24.x de la URL es el valor que debe actualizar cuando se publique una nueva versión LTS.
nvm, si prefiere mantener Node en el directorio personal de un usuario y no modificarlo nunca con sudo:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
source ~/.bashrc
nvm install --lts
node --versionEl v0.40.1 de esa URL era el actual cuando se redactó este texto. Consulte el README de nvm para comprobar cuál es la versión más reciente y sustituya la versión de la URL antes de ejecutar el comando. nvm ofrece una ventaja importante en este caso: instala Node y sus paquetes globales en ~/.nvm, por lo que el problema de permisos de las instalaciones globales de la sección siguiente no se produce. Si elige nvm, puede omitir el paso de configuración de npm-prefix.
Instale la CLI sin sudo npm -g
El comando tentador es sudo npm install -g @google/gemini-cli. No lo use. Un prefijo global propiedad de root provoca errores de permisos en cada instalación posterior y deja archivos propiedad de root en la caché de npm que causarán problemas meses después. Si ejecuta un npm install -g normal, sin sudo, contra un Node del sistema, aparecerá el otro error:
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 intenta escribir en /usr/lib, pero su usuario no tiene permisos. La solución no es usar sudo. Debe indicar a npm que use su directorio personal como prefijo global, para que las instalaciones globales se guarden en una ubicación de su propiedad:
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, y no ~/.profile, es intencionado: tmux, que ejecutará la CLI dentro de dos secciones, inicia un shell que no es de inicio de sesión. Ese shell lee ~/.bashrc y omite ~/.profile. Por eso, una línea PATH en el archivo incorrecto deja gemini invisible exactamente donde lo necesita. Que gemini --version muestre un número de versión es la prueba completa. Si obtiene gemini: command not found, la exportación de PATH no se aplicó. Consulte las causas de error. Con nvm, omita por completo las líneas del prefijo: nvm ya instala los paquetes globales en su directorio personal.
Si ejecutó sudo npm anteriormente y ahora ve Your cache folder contains root-owned files, corríjalo una vez con sudo chown -R $(id -u):$(id -g) ~/.npm.
El problema de autenticación sin interfaz y cómo resolverlo
Ejecute gemini de forma interactiva la primera vez. El comando le ofrecerá iniciar sesión con su cuenta de Google. En un equipo de escritorio, se abre una pestaña del navegador. En un VPS sin interfaz gráfica no hay ningún navegador. Por eso, el flujo imprime una URL de localhost que espera que abra o falla directamente con un mensaje similar a este:
Failed to open browser. Please visit the following URL to authorize:
https://accounts.google.com/o/oauth2/v2/auth?...&redirect_uri=http://localhost:PORTEl problema está en redirect_uri=http://localhost:PORT. Aunque abra esa URL en su portátil y la apruebe, Google redirige a http://localhost:PORT, es decir, a localhost en el servidor, en un puerto al que el portátil no puede acceder. El inicio de sesión no se completa.
Hay dos formas correctas de resolverlo.
La primera es usar una clave de API. Es la opción predeterminada adecuada para un servidor. Cree una clave en Google AI Studio (aistudio.google.com) y pásela a la CLI mediante una variable de entorno. La CLI lee GEMINI_API_KEY y omite por completo el flujo del navegador. Ahora debe evitar que la clave quede en el historial o en archivos legibles por todos. No escriba export GEMINI_API_KEY=AIza... en el indicador de comandos: quedará almacenado en ~/.bash_history en texto sin cifrar. Tampoco la guarde en un archivo que otros usuarios puedan leer. Escríbala en un archivo con permisos 600 que el shell cargue al 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 ~/.bashrcchmod 600 significa que sólo su usuario puede leer el archivo. Confirme que la clave llegó al entorno con printenv GEMINI_API_KEY. Si no muestra nada, la CLI vuelve al flujo del navegador y falla. También lee un archivo .env en ~/.gemini/ si prefiere esa estructura. Se aplica la misma regla: chmod 600 ~/.gemini/.env.
La segunda opción mantiene el inicio de sesión con una cuenta personal de Google y su nivel gratuito mediante un túnel que devuelve la llamada OAuth a su portátil. El problema es que el servidor de loopback de la CLI se enlaza a un puerto aleatorio en cada ejecución. No hay ningún puerto estable que reenviar, a menos que lo fije primero con la variable de entorno OAUTH_CALLBACK_PORT y reenvíe exactamente ese puerto:
# 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 no puede abrir un navegador, así que imprime la URL de autenticación. Ábrala en el navegador de su portátil y apruebe el acceso. Cuando Google redirija a http://localhost:8085/..., el reenvío SSH llevará la solicitud al servidor de loopback del VPS y el inicio de sesión se completará. Si no fija el puerto, cada ejecución usará un puerto aleatorio nuevo. Ningún ssh -L configurado de antemano podrá interceptarlo. Este método funciona, pero requiere que haya alguien delante de un navegador. Por eso no sirve para scripts. Para cualquier proceso que deba quedar en ejecución, use la clave de API.
Para usar Vertex AI o un proyecto de Google Cloud en lugar de AI Studio, configure GOOGLE_API_KEY junto con GOOGLE_GENAI_USE_VERTEXAI=true, o GOOGLE_CLOUD_PROJECT si dispone de una licencia de Code Assist. Aplique las mismas reglas para las variables de entorno y use el mismo archivo con permisos 600.
Ejecute el proceso dentro de tmux para que una sesión SSH interrumpida no lo termine
Un proceso gemini que inicia directamente desde el shell de SSH es hijo de ese shell. Si pierde la conexión, cierra el portátil, se interrumpe la Wi-Fi o se alcanza un tiempo de espera por inactividad, sshd desmonta el pseudo-terminal, el shell recibe SIGHUP y, a su vez, termina el proceso de la CLI. Una tarea que lleva diez minutos editando archivos termina con él y, al volver a conectarse, no hay ningún proceso que recuperar.
tmux soluciona este problema porque se adueña del shell, en lugar de que sshd sea su propietario. Este es el mismo patrón que ejecutar un agente de programación con IA en un VPS remoto dentro de tmux, y aquí funciona de la misma manera:
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 se conecta a una sesión llamada gemini si existe y la crea si no existe. Por eso es el único comando que debe ejecutar justo después de cada inicio de sesión. El shell interno pertenece al servidor tmux separado, no a la sesión SSH. Por tanto, si la conexión se interrumpe, la CLI sigue funcionando. Vuelva a conectarse, adjúntese a la sesión y recuperará el mismo historial desplazable. Si termina ejecutando varias sesiones de agentes en un mismo equipo, use una sesión de tmux para cada una. Aquí no pueden comunicarse entre sí, a diferencia de Claude Code, donde una sesión puede enviar texto a otra en el mismo VPS. Mantenga cada tarea de Gemini independiente o coordínelas mediante archivos en disco.
Para ejecuciones no interactivas y mediante scripts, Gemini CLI tiene un modo sin interfaz: gemini -p "summarise the failing tests in this repo" muestra una respuesta y termina, y --output-format json genera una salida legible por máquinas para canalizarla a otro proceso. El modo sin interfaz con una clave de API es justo lo que necesita dentro de una sesión tmux que ejecute una tarea por lotes de larga duración, o si la inicia desde una entrada de cron. Hay una salvedad: un trabajo de cron no carga ninguno de sus archivos de inicio de sesión. Por tanto, asigne a la línea de crontab su propio GEMINI_API_KEY o haga que el comando cargue ~/.gemini_env. De lo contrario, la CLI recurrirá al flujo del navegador y fallará.
Aislamiento y permisos en un servidor que también ejecuta producción
Un agente con acceso al shell tiene acceso al shell. Gemini CLI puede ejecutar comandos y, de forma predeterminada, solicita confirmación antes de cada operación de riesgo. Sin embargo, es habitual usar --yolo (aprobación automática de todas las llamadas a herramientas). En ese caso, puede eliminar archivos, hacer push a git o acceder a servicios internos con todos los permisos del usuario con el que se ejecuta. En un servidor que también ejecuta producción, esto supone un radio de impacto real, no un riesgo hipotético.
Tres controles, en orden de importancia:
- Ejecútelo con un usuario dedicado y sin privilegios. No use root ni un miembro de
sudo. Cree un usuarioagentcon su propio directorio personal e instale allí Node y la CLI. Así, una instrucción interpretada incorrectamente queda confinada a esa cuenta. Esta es la decisión con mayor impacto positivo. - Mantenga las credenciales de producción fuera del servidor. No incluya
~/.aws/credentialsde producción, no copie.envdesde producción y no use una contraseña de base de datos con permisos de escritura sobre recursos importantes. Proporcione una credencial de staging o de sólo lectura. - Use el sandbox integrado. Con Docker o Podman instalado,
gemini --sandbox(oGEMINI_SANDBOX=docker) ejecuta las llamadas a herramientas del agente dentro de un contenedor aislado del sistema de archivos y de la red del host. No sustituye al usuario sin privilegios, pero proporciona una segunda capa sólida cuando el mismo VPS ejecuta servicios reales.
Si ejecuta Gemini CLI junto con otras herramientas autoalojadas, por ejemplo un servidor MCP que expone herramientas al agente en el mismo VPS, trate cada capacidad añadida como una superficie adicional a la que el agente puede acceder y limite los tokens que recibe a una única tarea.
Cuota, coste y la ruta de autenticación elegida
La ruta de autenticación determina cómo se factura el servicio. Una cuenta personal de Google (la ruta OAuth) utiliza el nivel gratuito de Gemini Code Assist, con límites reales por minuto y por día. Si los supera, las solicitudes devuelven un error de límite de velocidad hasta que se restablece la ventana. Una clave de API de AI Studio puede usar el nivel gratuito o generar cargos, según el proyecto. Una clave asociada a facturación aumenta los límites y cobra por token. La autenticación mediante Vertex y proyectos de Cloud se factura a través de Google Cloud.
Hay dos aspectos prácticos. Un agente desatendido ejecutándose en un bucle puede consumir la cuota rápidamente. Supervíselo las primeras veces antes de confiarle una tarea de cron. Además, si el motivo para usar un modelo en el servidor es la privacidad o la inferencia sin medición de uso, y no los modelos alojados de Google, se trata de una herramienta diferente: alojar un LLM abierto con Ollama en un VPS mantiene los pesos y las solicitudes en su propio servidor, pero obliga a ejecutar un modelo mucho más pequeño que Gemini.
Mantenerlo actualizado
Gemini CLI publica versiones con frecuencia. Como lo instaló en un prefijo propiedad del usuario, las actualizaciones no necesitan sudo:
npm install -g @google/gemini-cli@latest
gemini --versionHay varios canales de publicación: @latest es el estable, @preview es la versión preliminar semanal y @nightly es la versión más reciente en desarrollo. Fije la versión en @latest para cualquier entorno del que dependa. Con nvm, los paquetes globales se almacenan en la versión activa de Node. Por eso, después de nvm use para cambiar de versión de Node, es posible que deba volver a instalar la CLI. Lea las notas de la versión en lugar de instalar cada parche inmediatamente.
Modos de fallo, con las cadenas exactas
npm WARN EBADENGINE Unsupported engine ... required: { node: '>=20' } y después el fallo de la CLI durante la ejecución. Node es demasiado antiguo; la distribución incluye la versión 18.19.1, que también está fuera de soporte. Instale Node 20+ desde NodeSource o nvm y confirme la versión con node --version. Si tiene varias versiones de Node instaladas, compruebe que which node apunte a la nueva y no a /usr/bin/node.
npm error code EACCES / permission denied, mkdir '/usr/lib/node_modules/...'. Se realizó una instalación global en un prefijo cuyo propietario es root. No use sudo. Configure npm config set prefix ~/.npm-global, añada ~/.npm-global/bin a PATH y vuelva a instalar como su usuario normal. Si un sudo npm anterior dejó archivos de caché propiedad de root (Your cache folder contains root-owned files), ejecute sudo chown -R $(id -u):$(id -g) ~/.npm.
Failed to open browser, un inicio de sesión que se bloquea o un redirect_uri=http://localhost:PORT al que no puede acceder. El flujo OAuth necesita un navegador que el servidor no tiene y su callback de localhost apunta al servidor, no a su portátil. Use la ruta de clave de API (GEMINI_API_KEY) o fije OAUTH_CALLBACK_PORT, reenvíelo mediante SSH con ssh -L y abra la URL localmente.
El proceso desapareció al cerrarse la conexión SSH. Ejecutó gemini directamente desde el shell SSH, por lo que era un proceso hijo de ese shell y terminó cuando se desconectó el pty. No hay nada que recuperar. Inicie todas las sesiones con tmux new -A -s gemini y ejecute la CLI dentro de ella.
La autenticación sigue fallando con la clave configurada, la CLI vuelve a mostrar su selector de autenticación o una solicitud devuelve API key not valid con HTTP 400. La clave no está disponible en el entorno que ve la CLI. Confírmelo con printenv GEMINI_API_KEY. Si está vacío, nunca se cargó su ~/.gemini_env. Compruebe que la línea esté en ~/.bashrc, que leen los shells interactivos, incluido tmux, pero no cron ni otros shells no interactivos. Un espacio o unas comillas sobrantes dentro del valor de la clave también producen API key not valid.
429 / RESOURCE_EXHAUSTED / un mensaje de límite de tasa. Ha alcanzado la cuota del nivel que utiliza su autenticación. Espere a que se restablezca la ventana, reduzca la velocidad del agente o cambie a una clave de API con facturación. Si un agente queda atrapado en un bucle de reintentos, seguirá alcanzando este límite. Deténgalo y compruebe qué está haciendo.
FAQ
¿Cómo autentico Gemini CLI en un servidor sin interfaz gráfica?
Use una clave de API, no el inicio de sesión mediante el navegador. Cree una clave en Google AI Studio, guárdela en un archivo con permisos 600 que cargue el shell (export GEMINI_API_KEY=...) y la CLI omitirá por completo el flujo OAuth del navegador. Si necesita específicamente el nivel gratuito de la cuenta personal, fije el puerto de loopback con OAUTH_CALLBACK_PORT=8085, reenvíelo a su portátil con ssh -L 8085:localhost:8085 user@server y abra localmente la URL mostrada. Sin embargo, debe estar presente ante un navegador, por lo que no sirve para scripts.
¿Por qué la instalación global de npm solicita sudo y cómo puedo evitarlo?
Porque el prefijo global predeterminado de npm es /usr/lib/node_modules y su usuario no puede escribir en él, por lo que un npm install -g simple falla con EACCES. La solución incorrecta es sudo npm -g, ya que deja archivos propiedad de root que provocan fallos en instalaciones posteriores. La solución correcta es apuntar el prefijo a su directorio personal (npm config set prefix ~/.npm-global) y añadir su bin a PATH, o usar nvm, que instala automáticamente los paquetes globales en su directorio personal.
¿Cómo mantengo Gemini CLI en ejecución después de desconectarme?
Ejecútelo dentro de tmux. Un proceso iniciado desde el shell de SSH termina cuando se interrumpe la conexión porque es hijo de ese shell; tmux ejecuta el shell bajo un servidor separado que sobrevive a la desconexión. Use tmux new -A -s gemini, ejecute gemini dentro, sepárese con Ctrl-b d y vuelva a conectarse después con tmux attach -t gemini.
¿Es seguro ejecutar Gemini CLI en un servidor de producción?
Sólo si lo hace con cuidado, porque un agente con acceso al shell puede hacer cualquier cosa que pueda hacer el usuario con el que se ejecuta. Ejecútelo con un usuario dedicado sin privilegios y sin sudo, no almacene credenciales de producción en el equipo, evite --yolo de aprobación automática y use --sandbox (Docker o Podman) para aislar las llamadas a herramientas del host. La cuenta con la que se ejecuta importa más que cualquier indicador individual que configure.
¿Necesito abrir puertos del firewall para Gemini CLI?
No. Es un cliente que realiza llamadas HTTPS salientes a las API de Google, por lo que necesita el puerto saliente 443, pero no puertos entrantes. Si usa el túnel OAuth, el puerto de callback fijado (por ejemplo, 8085) reside en localhost y se alcanza mediante el reenvío de SSH, no mediante un puerto entrante abierto. Mantenga bloqueadas las conexiones entrantes.