instalar gemini cli en un vps headless
Guía para usar Gemini CLI en VPS sin interfaz gráfica. Incluye uso de API key, Node.js actualizado, npm sin sudo y tmux para evitar cortes de SSH.
Lo que vas a construir
Un Gemini CLI siempre activo en un servidor propio, accesible mediante SSH, que ejecuta tareas de agentes prolongadas que continúan funcionando tras cerrar la laptop. La instalación consta de tres comandos. La dificultad reside en los requisitos de entorno de escritorio: la CLI de Google requiere abrir un navegador para el inicio de sesión, pero tu servidor no tiene uno. Por ello, la mayor parte de esta guía se enfoca en el método headless: una versión de Node actual que la distribución no incluye, una instalación global de npm que no requiere root, autenticación sin navegador mediante una API key que se mantiene fuera del historial de la shell, y tmux para evitar que una desconexión de SSH interrumpa una tarea en ejecución.
Gemini CLI es un programa Node de código abierto (Apache-2.0) (@google/gemini-cli) que se comunica con los modelos Gemini de Google. Puede leer y escribir archivos, ejecutar comandos de shell y utilizar herramientas en el directorio de trabajo. En un VPS, funciona como un agente ligero y siempre disponible que puedes dejar trabajando; por esto, la cuenta con la que se ejecuta y las credenciales almacenadas en el equipo son más importantes que cualquier configuración individual.
Requisitos previos y problemas comunes
- Un VPS KVM con Ubuntu 24.04 recién instalado y acceso root o sudo. Cualquier plan KVM es válido; la CLI es ligera y consume unos pocos cientos de MB de RAM en reposo.
- Node.js 20 o superior. Esta es la única versión mínima obligatoria; el paquete de la distribución es inferior — consulte la siguiente sección.
- Conexión HTTPS saliente (puerto 443) hacia las APIs de Google. No se requieren puertos de entrada; este es un cliente, no un servidor, por lo que no es necesario abrir ningún puerto en el firewall.
- Un método de autenticación que no requiera un navegador en el servidor: una API key de Gemini desde Google AI Studio, o un túnel SSH hacia un navegador en su propia máquina. El método de la API key es el recomendado para scripts y ejecuciones automatizadas.
- Docker o Podman, solo si desea el aislamiento
--sandbox. Opcional, se detalla al final.
El problema que afecta a todos: el flujo de inicio de sesión gemini está diseñado para entornos de escritorio. Intenta abrir un navegador y, en un servidor sin interfaz gráfica (headless), falla o proporciona un enlace que no funciona. Elija el método de autenticación antes de comenzar.
Node: el paquete de la distro es demasiado antiguo
Ubuntu 24.04 incluye Node 18.19.1 en sus propios repositorios, junto con npm 9.2.0. El package.json de Gemini CLI declara engines: { node: ">=20" }, y npm no detiene la instalación por defecto ante una discrepancia; la instala de todos modos y muestra una advertencia indicando 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 ejecutará en un entorno no compatible. Esto causará errores o fallos en cuanto el software intente usar una API de Node 20+ que no existe. Node 18 también alcanzó el fin de su vida útil (EOL) en abril de 2025, por lo que no es una opción viable. Instale una versión LTS actual antes de instalar la CLI. Las dos rutas recomendadas son NodeSource (un repositorio apt firmado para todo el sistema) o nvm (un gestor de versiones por usuario). Elija una.
NodeSource, si desea 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 superior; v24.x es la LTS activa actual. Consulte la página de NodeSource para obtener el script de configuración actual; el setup_24.x en la URL es el valor que debe actualizar cuando se publique una nueva LTS.
nvm, si prefiere mantener Node dentro del home de un solo usuario y evitar el uso de 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 en esa URL era la versión actual al escribir este texto; consulte el README de nvm para obtener la última versión y actualice la versión antes de ejecutarlo. nvm tiene una ventaja clara para este caso: instala Node y sus paquetes globales bajo ~/.nvm, por lo que el problema de permisos de instalación global de la siguiente sección no ocurrirá. Si utiliza nvm, puede omitir el paso de npm-prefix.
Instalar 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 genera errores de permisos en cada instalación posterior y deja archivos de root en su cache de npm que causarán problemas meses después. Ejecute un npm install -g simple (sin sudo) contra un Node del sistema y obtendrá este 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; consiste en apuntar el prefijo global de npm a su directorio home 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 --versionEl uso de ~/.bashrc en lugar de ~/.profile es deliberado: tmux —que ejecutará la CLI dentro de dos secciones —inicia un shell de no-login que lee ~/.bashrc y omite ~/.profile, por lo que una línea PATH en el archivo incorrecto dejará a gemini invisible justo donde lo necesita. La prueba consiste en que gemini --version imprima el número de versión. Si recibe gemini: command not found, su exportación de PATH falló; revise los modos de error. Si usa nvm, ignore las líneas del prefijo: este ya instala los paquetes globales en su home.
Si ejecutó sudo npm anteriormente y ahora ve Your cache folder contains root-owned files, repárelo una vez con sudo chown -R $(id -u):$(id -g) ~/.npm.
El problema de la autenticación headless y cómo solucionarlo
Ejecute gemini de forma interactiva la primera vez y se le ofrecerá iniciar sesión con su cuenta de Google. En un escritorio, esto abre una pestaña en el navegador. En un VPS headless no hay navegador, por lo que el flujo imprime una URL de localhost que debe abrir o falla directamente con un error como 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 es el redirect_uri=http://localhost:PORT. Aunque abra esa URL en su portátil y la apruebe, Google redirige a http://localhost:PORT —localhost en el servidor, un puerto al que nada en su portátil puede acceder. El inicio de sesión nunca se completa.
Existen dos métodos válidos.
El primero es una API key, que es la opción predeterminada correcta para un servidor. Cree una clave en Google AI Studio (aistudio.google.com) y pásela a la CLI como una variable de entorno; esta lee GEMINI_API_KEY y omite el flujo del navegador por completo. Ahora, la parte de "mantenerla fuera del historial y de archivos legibles por otros". No escriba export GEMINI_API_KEY=AIza... en el prompt —se guarda en ~/.bash_history en texto plano, y no la guarde en un archivo que otros puedan leer. Escríbala en un archivo con permisos 600 que el shell cargue al inicio:
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 solo su usuario puede leer el archivo. Confirme que la clave se cargó en el entorno con printenv GEMINI_API_KEY; si no imprime nada, la CLI intentará el flujo del navegador y fallará. También lee un archivo .env en ~/.gemini/ si prefiere esa estructura —la misma regla se aplica aquí, así que use chmod 600 ~/.gemini/.env.
El segundo método mantiene el inicio de sesión con cuenta personal de Google (y su nivel gratuito) mediante un túnel del callback de OAuth hacia su portátil. El inconveniente es que el servidor loopback de la CLI usa un puerto aleatorio en cada ejecución, por lo que no hay un puerto estable para reenviar a menos que lo fije primero con la variable de entorno OAUTH_CALLBACK_PORT y luego 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, por lo que imprime la URL de autenticación; ábrala en el navegador de su portátil, apruebe el acceso y, cuando Google redirija a http://localhost:8085/..., el reenvío de SSH llevará la petición al servidor loopback en el VPS y el inicio de sesión se completará. Si deja el puerto sin fijar, este cambiará en cada ejecución, y ninguna configuración de ssh -L previa podrá capturarlo. Este método funciona, pero requiere que usted esté frente a un navegador, por lo que no es apto para scripts. Para cualquier proceso que deba ejecutarse en segundo plano, use la API key.
Para 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 para una licencia de Code Assist —aplique la misma disciplina de variables de entorno y el mismo archivo con permisos 600.
Ejecútelo dentro de tmux para que una sesión SSH interrumpida no lo finalice
Un proceso gemini lanzado directamente desde su shell de SSH es un proceso hijo de esa shell. Si pierde la conexión —ya sea por cerrar la laptop, pérdida de Wi-Fi o un tiempo de espera por inactividad—, sshd destruye la pseudo-terminal, la shell recibe SIGHUP y la CLI se cierra. Una tarea que lleve diez minutos editando archivos morirá con ella, y al reconectar no habrá proceso que recuperar.
tmux soluciona esto al ser el dueño de la shell en lugar de que sshd sea el dueño. Este es el mismo patrón que ejecutar un agente de IA para codificación en un VPS remoto dentro de tmux, y funciona de la misma manera aquí:
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 esta existe, o la crea si no existe; es el único comando que debe ejecutar justo después de cada inicio de sesión. La shell interna pertenece al servidor tmux desvinculado, no a su sesión SSH, por lo que si la conexión se pierde, la CLI sigue funcionando. Al reconectar y usar attach, recuperará el mismo historial de scrollback.
Para ejecuciones mediante scripts no interactivos, Gemini CLI tiene un modo headless: gemini -p "summarise the failing tests in this repo" imprime una respuesta y finaliza, y --output-format json genera una salida legible por máquina para usar con pipes. El modo headless con una API key es ideal para una sesión de tmux ejecutando un trabajo por lotes largo, o para tareas programadas mediante cron; con una advertencia: un trabajo cron no carga sus archivos de inicio de sesión, por lo que debe proporcionar a la línea del crontab su propio GEMINI_API_KEY (o hacer que el comando cargue ~/.gemini_env), de lo contrario la CLI intentará usar el flujo del navegador y fallará.
Sandboxing y permisos en un equipo que también ejecuta producción
Un agente con acceso a la shell es una shell. Gemini CLI puede ejecutar comandos y, por defecto, pregunta antes de cada acción de riesgo; sin embargo, los usuarios suelen usar --yolo (auto-aprobar cada llamada a herramienta). Esto permite que el agente borre archivos, realice pushes en git o acceda a servicios internos con la autoridad total del usuario que lo ejecuta. En un equipo que también ejecuta producción, esto representa un radio de explosión real, no hipotético.
Tres controles, ordenados según su nivel de seguridad:
- Ejecutarlo como un usuario dedicado y sin privilegios. No usar root ni un miembro de
sudo. Cree un usuarioagentcon su propio home, instale Node y la CLI allí; así, cualquier instrucción errónea se limitará a esa cuenta. Esta es la decisión de mayor valor. - Mantener las credenciales de producción fuera del equipo. Sin
~/.aws/credentialsde producción, sin.envcopiados desde producción y sin contraseñas de base de datos con acceso de escritura a recursos críticos. Proporcione credenciales de staging o de solo lectura. - Usar el sandbox integrado. Con Docker o Podman instalados,
gemini --sandbox(oGEMINI_SANDBOX=docker) ejecuta las llamadas a herramientas del agente dentro de un contenedor aislado del sistema de archivos y la red del host. No sustituye al uso de un usuario sin privilegios, pero es una segunda capa sólida cuando el mismo VPS realiza tareas críticas.
Si ejecuta Gemini CLI junto a otras herramientas auto-alojadas —por ejemplo, un servidor MCP que expone herramientas al agente en el mismo VPS— trate cada capacidad añadida como una superficie de ataque adicional para el agente, y limite los tokens que recibe a una única tarea.
Cuota, coste y el método de autenticación elegido
El método de autenticación determina la forma de facturación. Una cuenta personal de Google (vía OAuth) utiliza el nivel gratuito de Gemini Code Assist con límites reales por minuto y por día; si se exceden, las peticiones devolverán un error de límite de tasa (rate-limit) hasta que se reinicie el intervalo. Una API key de AI Studio puede ser de nivel gratuito o de pago según el proyecto; una clave de pago aumenta los límites y factura por token. La autenticación de Vertex y Cloud-project se factura a través de Google Cloud.
Dos notas prácticas. Un agente sin supervisión en un bucle puede agotar la cuota rápidamente; monitorízalo las primeras veces antes de programarlo en un cron job. Si el motivo para usar un modelo en el servidor es la privacidad o la inferencia sin límites en lugar de los modelos alojados de Google, se requiere una herramienta distinta: alojar por cuenta propia un LLM abierto con Ollama en un VPS mantiene los pesos y los prompts en su propio equipo, a cambio de ejecutar un modelo mucho más pequeño que Gemini.
Mantenerlo actualizado
Gemini CLI se actualiza con frecuencia. Debido a que se instaló en un prefijo de usuario, las actualizaciones no requieren sudo:
npm install -g @google/gemini-cli@latest
gemini --versionExisten canales de lanzamiento: @latest es la versión estable, @preview es la vista previa semanal y @nightly es la versión de desarrollo extremo; use @latest para cualquier entorno de producción. En nvm, los paquetes globales residen bajo la versión de Node activa, por lo que tras ejecutar nvm use para cambiar de versión de Node, es posible que deba reinstalar la CLI. Consulte las notas de lanzamiento en lugar de buscar cada parche individual.
Modos de fallo, con las cadenas exactas
npm WARN EBADENGINE Unsupported engine ... required: { node: '>=20' }, y luego el cierre inesperado de la CLI en tiempo de ejecución. Node es demasiado antiguo; la distro tiene la versión 18.19.1, que ya alcanzó el fin de su vida útil (end-of-life). Instale Node 20+ desde NodeSource o nvm, confirme con node --version, y si tiene varias versiones de Node instaladas, verifique que which node apunte a la nueva y no a /usr/bin/node.
npm error code EACCES / permission denied, mkdir '/usr/lib/node_modules/...'. Una instalación global en un prefijo propiedad de root. No use sudo; configure npm config set prefix ~/.npm-global, coloque ~/.npm-global/bin en PATH y reinstale con su usuario normal. Si una 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 bloqueado, o un redirect_uri=http://localhost:PORT inaccesible. El flujo OAuth requiere un navegador que el servidor no tiene, y su callback de localhost apunta al servidor y no a su laptop. Use la ruta de API-key (GEMINI_API_KEY), o fije OAUTH_CALLBACK_PORT, rediríjalo por SSH con ssh -L y abra la URL localmente.
El proceso desapareció cuando se cayó la conexión SSH. Ejecutó gemini directamente desde la shell de SSH, por lo que era un proceso hijo de esa shell y murió con el pty al desconectarse. No hay nada que recuperar. Inicie cada sesión 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 al selector de autenticación, o una petición devuelve API key not valid con HTTP 400. La clave no está en el entorno que la CLI puede ver. Confirme con printenv GEMINI_API_KEY; si está vacía, su ~/.gemini_env nunca se cargó (sourced); verifique que la línea esté en ~/.bashrc, que las shells interactivas (incluyendo tmux) leen, pero cron y otras shells no interactivas no. Un espacio o una comilla mal colocados dentro del valor de la clave también producen API key not valid.
429 / RESOURCE_EXHAUSTED / un mensaje de límite de tasa (rate-limit). Ha alcanzado la cuota del nivel de autenticación que esté usando. Espere a que se reinicie el intervalo, reduzca la velocidad del agente o cambie a una API-key de pago. Un agente atrapado en un bucle de reintentos seguirá provocando esto; deténgalo y verifique su actividad.
FAQ
¿Cómo autentico Gemini CLI en un servidor headless?
Use una API key en lugar del inicio de sesión por navegador. Cree una clave en Google AI Studio, guárdela en un archivo con permisos mode-600 que su shell cargue (export GEMINI_API_KEY=...) y la CLI omitirá el flujo de OAuth por navegador. Si requiere específicamente el nivel gratuito de cuenta personal, fije el puerto loopback con OAUTH_CALLBACK_PORT=8085, rediríja el puerto a su laptop con ssh -L 8085:localhost:8085 user@server y abra la URL generada localmente; sin embargo, esto requiere presencia en un navegador y no es apto para scripts.
¿Por qué la instalación global de npm requiere sudo y cómo evitarlo?
El prefijo global por defecto de npm es /usr/lib/node_modules, donde su usuario no tiene permisos de escritura; por tanto, un comando npm install -g fallará con EACCES. La solución incorrecta es sudo npm -g, ya que deja archivos propiedad de root que causan errores en instalaciones posteriores. La solución correcta es apuntar el prefijo a su home (npm config set prefix ~/.npm-global) y añadir su bin a PATH, o usar nvm, que instala los paquetes globales en su home automáticamente.
¿Cómo mantengo Gemini CLI ejecutándose tras desconectarme?
Ejecútelo dentro de tmux. Un proceso iniciado desde una sesión SSH muere cuando la conexión se pierde porque es un proceso hijo de esa shell; tmux ejecuta la shell bajo un servidor independiente que sobrevive a la desconexión. Use tmux new -A -s gemini, ejecute gemini dentro, desvincule con Ctrl-b d y vuelva a vincular más tarde con tmux attach -t gemini.
¿Es seguro ejecutar Gemini CLI en un servidor de producción?
Solo con precaución, ya que un agente con acceso a la shell puede realizar cualquier acción que el usuario que lo ejecuta permita. Ejecútelo como un usuario sin privilegios dedicado y sin sudo, mantenga las credenciales de producción fuera de la máquina, evite la aprobación automática de --yolo y use --sandbox (Docker o Podman) para aislar las llamadas de las herramientas del host. La cuenta bajo la que se ejecuta es más importante que cualquier flag configurado.
¿Debo abrir puertos en el firewall para Gemini CLI?
No. Es un cliente que realiza llamadas HTTPS salientes a las APIs de Google, por lo que requiere el puerto de salida 443 pero no requiere puertos de entrada. Si usa el túnel OAuth, el puerto de callback fijado (por ejemplo, 8085) reside en localhost y se accede mediante el reenvío de SSH, no mediante un puerto de entrada abierto. Mantenga bloqueadas las conexiones de entrada.