Skip to content

Run Gemini CLI on a remote server

Google's terminal agent on a VM of its own, with the API key kept off it.

Deploy on exe.dev

Shelley handles the setup. About 10 minutes.

Prefer a terminal?
curl -fsSL https://exe-staging.dev/deploy/gemini-cli/prompt.txt | ssh exe.dev new --prompt=/dev/stdin

Gemini CLI is Google's open-source coding agent for the terminal. On an exe.dev VM it gets a computer of its own: it keeps working when you close your laptop, and it can install, run and break things you can throw away.

Gemini CLI needs Google's Gemini models, so bring a Gemini API key. You give the key to exe.dev rather than the VM: a Gemini integration adds it to each request on the way out, so nothing on the VM, Gemini CLI included, can read it. Since June 2026 Google serves Gemini CLI only to API keys, Vertex AI and organizations with a Gemini Code Assist license; free and Google AI Pro accounts can no longer sign in to it.

What you get#

  • Gemini CLI on Node.js 24, answering a headless gemini -p prompt
  • A Gemini API key stored in an exe.dev integration, never on the VM
  • A Git repository at ~/project on persistent disk
  • A gemini tmux session that survives disconnects
What's running, and where
Private ssh my-gemini-cli.exe.xyz your terminal
Private https://gemini.int.exe.xyz/ the Gemini API, from this VM only, with your key added by exe.dev
my-gemini-cli.exe.xyz exe.dev VM
Gemini CLI @google/gemini-cli from npm, on Node.js 24 ~/.gemini
Gemini integration exe.dev holds your Gemini API key and adds it to each request
Your project a Git repository ~/project
tmux keeps your terminal session running when you disconnect

Deploy with Shelley#

Click Deploy and Shelley will set up Gemini CLI on a new VM, then check that it works. No config-file wrangling required.

Prefer a terminal?
curl -fsSL \
  https://exe-staging.dev/deploy/gemini-cli/prompt.txt \
  | ssh exe.dev new --prompt=/dev/stdin
What Shelley is told
Set up Gemini CLI on this VM by following the exe.dev recipe at https://exe-staging.dev/deploy/gemini-cli.md from top to bottom.

The recipe's example VM name is my-gemini-cli. This VM's name is the output of `hostname`: use it wherever the recipe writes my-gemini-cli. Skip the step that creates the VM; you are on it.

You are done when all of these are true. Check each one yourself:
- Gemini CLI on Node.js 24, answering a headless `gemini -p` prompt
- A Gemini API key stored in an exe.dev integration, never on the VM
- A Git repository at `~/project` on persistent disk
- A `gemini` tmux session that survives disconnects

Run the VM-side commands in "Install Gemini CLI" and "Connect it to
Gemini". Only the owner can create the Gemini integration, in their
browser, and the API key must never be on this VM: give them the
integration link from "Connect it to Gemini" with this VM's name in it,
and wait until they say it's done. Never ask for the key. If
`~/.gemini/settings.json` already exists, set `security.auth.selectedType`
in it instead of replacing the file. Create tmux detached
(`tmux new -d -s gemini -c ~/project`) rather than attaching, and reuse
the session if it exists. Do not launch interactive Gemini CLI; leave the
folder-trust question to the owner. Verify with
`curl -fsS https://gemini.int.exe.xyz/v1beta/models >/dev/null` and, from
~/project, `gemini --skip-trust -m flash-lite -p "Reply with exactly: OK"`, and
check `tmux has-session -t gemini`. Skip the later optional sections and
FAQ. Finish with the SSH command from "Take a break", using this VM's
name, and tell the owner to run `gemini` inside it.

Finish with the URLs I should open.

Also at /deploy/gemini-cli/prompt.txt. The recipe it follows is /deploy/gemini-cli.md.

Install Gemini CLI#

On your computer, create a VM and connect. Pick any free name; if you've already clicked Deploy or have a VM, skip the first command and use its name:

ssh exe.dev new --name=my-gemini-cli
ssh my-gemini-cli.exe.xyz

On the VM, install Node.js 24 from NodeSource (Gemini CLI needs Node.js 20 or newer) and Gemini CLI from npm:

curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
sudo apt-get install -y nodejs
sudo npm install -g @google/gemini-cli@latest
gemini --version

It prints a version such as 0.66.0.

Connect it to Gemini#

Open this link on your computer to add a Gemini integration attached to the VM. Keep the name gemini, paste your Gemini API key, and save:

https://exe.dev/integrations/add?service=gemini&attach=vm:my-gemini-cli

The VM can now reach the Gemini API at https://gemini.int.exe.xyz, with your key added by exe.dev. On the VM, check it:

curl -fsS https://gemini.int.exe.xyz/v1beta/models | jq -r '.models[0].name'

It prints a model name, such as models/gemini-2.5-flash. A 403 saying integration not found or not attached to this VM means the integration has another name or isn't attached to this VM yet.

Point Gemini CLI at that address. Gemini CLI insists on an API key value, so it gets a placeholder; the integration replaces it with yours:

mkdir -p ~/.gemini
cat > ~/.gemini/.env <<'EOF'
GOOGLE_GEMINI_BASE_URL=https://gemini.int.exe.xyz
GEMINI_API_KEY=added-by-exe-dev
EOF
chmod 600 ~/.gemini/.env
cat > ~/.gemini/settings.json <<'EOF'
{
  "security": { "auth": { "selectedType": "gemini-api-key" } }
}
EOF

Make a project folder, a Git repository so you can review and undo what Gemini changes, and ask it something without opening the interactive screen:

git init ~/project
cd ~/project
gemini --skip-trust -m flash-lite -p "Reply with exactly: OK"

It prints OK. --skip-trust answers the folder-trust question you'll see in the next step, for this run only, and -m flash-lite picks Google's smallest current model, which free keys can use too.

Start coding#

Open a tmux session in the project:

tmux new -A -s gemini -c ~/project

Inside that session, start Gemini CLI:

gemini

The first time, it asks whether you trust the files in this folder. Choose Trust folder: Gemini CLI only reads ~/.gemini/.env and project settings in folders you trust. Then give it a small task. For example:

Build a tiny website for a lighthouse keeper who reviews passing ships.

Note

Gemini CLI's default model setting, Auto, sends harder prompts to a Pro model. Keys on Google's free tier can't use Pro, so Gemini CLI retries and then falls back to Flash, which can take minutes. With a free key, start it as gemini -m flash (or -m flash-lite), or pick a model with /model.

Gemini CLI asks before it edits a file or runs a command. Press Shift+Tab to let it accept edits on its own; type /help for the rest.

Take a break#

Press Ctrl-b, then d to detach. Gemini CLI keeps working on the VM when you disconnect. On your computer, use this command to hop back in:

ssh -t my-gemini-cli.exe.xyz 'tmux new -A -s gemini -c ~/project'

A VM restart ends the running session, but not your saved work. Reconnect and run gemini --resume latest from your project's folder on the VM to pick up its last conversation.

Tip

Before a big unattended job, take a copy of the VM with ssh exe.dev cp my-gemini-cli my-gemini-cli-backup on your computer. If the job goes sideways, carry on from the copy.

Run it headless#

gemini -p runs one prompt and exits, which makes Gemini CLI a tool for scripts, cron jobs and other agents. It reads anything piped into it:

cd ~/project
git diff | gemini -p "Write a commit message for these changes"

Without a screen to ask on, Gemini CLI refuses anything that needs your approval. Say what it may do instead: --approval-mode=auto_edit lets it edit files, and --approval-mode=yolo lets it run any command too, which is what a throwaway VM is for. -o json returns one JSON object with the answer in response:

gemini --approval-mode=auto_edit -o json \
  -p "Add a README.md that explains this project" | jq -r .response

A scheduled run is one cron line. Run crontab -e and add, for example, a nightly review at 06:00 UTC:

0 6 * * * cd ~/project && gemini --skip-trust -p "List the TODOs in this repo, most urgent first" >> ~/gemini-todos.log 2>&1

The exit code is 0 on success, 1 on an error, 42 for bad input and 53 when the run hits its turn limit. Google's headless mode reference has the stream-json event format.

Add MCP servers#

Gemini CLI loads MCP servers from ~/.gemini/settings.json, or from .gemini/settings.json in a project. gemini mcp add writes the entry for you: pass --scope user for every project, as its default is the current project only.

For example, connect exe.dev's MCP server so Gemini can create VMs of its own: to try something risky on a copy, or to host what it builds. It runs unattended here, so give it a token that can only touch VMs tagged agent and expires in 30 days rather than your whole account. On your computer:

ssh exe.dev ssh-key generate-api-key --label=gemini --tag=agent --exp=30d \
  '--cmds="help,whoami,ls,new,rm,ssh,cp,stat,comment,share show,share port"'

It prints a token that starts with exe1.. On the VM, add it to ~/.gemini/.env (replace exe1.… with the token) and register the server. The single quotes keep ${EXE_TOKEN} as written, so Gemini CLI reads the token from .env each time it starts instead of saving it in settings.json:

echo 'EXE_TOKEN=exe1.…' >> ~/.gemini/.env
gemini mcp add --scope user --transport http \
  --header 'Authorization: Bearer ${EXE_TOKEN}' exe https://exe.dev/mcp
cd ~/project && gemini mcp list

gemini mcp list shows exe as Connected. In Gemini CLI, /mcp lists each server's tools. Limit what the agent can touch explains the token's options.

A local server that runs as a command works the same way, without --transport: gemini mcp add --scope user <name> <command> [args...]. See Google's MCP guide for per-tool filters and OAuth servers.

Work on a GitHub repository#

The GitHub integration lets the VM clone and push a repository without a GitHub token on it. Connect your GitHub account on the Integrations page once, then, on your computer, add the repository (replace you/your-repo):

ssh exe.dev integrations add github --name your-repo \
  --repository you/your-repo --attach vm:my-gemini-cli

On the VM, clone it, tell Git who you are, and start Gemini CLI in it:

git clone https://github.int.exe.xyz/you/your-repo.git ~/your-repo
git config --global user.name "Your Name"
git config --global user.email you@example.com
tmux new -A -s your-repo -c ~/your-repo
gemini

Ask for a change on a branch, then let Gemini push it and open a pull request with the preinstalled gh, which goes through the same integration when GH_HOST points at it:

Fix the flaky date test on a new branch, commit it, push the branch, and open a pull request with GH_HOST=github.int.exe.xyz gh pr create.

Pushes show up as the exe.dev GitHub App; add --act-as-user to the integrations add command to push as yourself. Put project instructions for Gemini in a GEMINI.md at the top of the repository; it reads that file at the start of every session.

Other ways to sign in#

An API key on the VM, a Code Assist license, or Vertex AI

A Gemini API key on the VM#

If you'd rather not use an integration, put the key itself in ~/.gemini/.env, which only you can read, and drop the GOOGLE_GEMINI_BASE_URL line:

cat > ~/.gemini/.env <<'EOF'
GEMINI_API_KEY=paste-your-key-here
EOF
chmod 600 ~/.gemini/.env

Anything running on the VM as exedev, Gemini CLI included, can then read the key.

Sign in with Google (Gemini Code Assist license)#

If your organization gives you a Gemini Code Assist Standard or Enterprise license, sign in with that Google account. Set the Google Cloud project the license belongs to and switch the sign-in method:

cat > ~/.gemini/.env <<'EOF'
GOOGLE_CLOUD_PROJECT=your-project-id
EOF
cat > ~/.gemini/settings.json <<'EOF'
{
  "security": { "auth": { "selectedType": "oauth-personal" } }
}
EOF

Start gemini in the tmux session. With no browser on the VM, it prints a https://accounts.google.com/... link and waits at Enter the authorization code:. Open the link on your computer, sign in, and paste the code it shows back into the terminal. Gemini CLI keeps the sign-in in ~/.gemini/oauth_creds.json, which headless runs use too.

Vertex AI#

To bill a Google Cloud project instead, Gemini CLI can use Vertex AI. Set GOOGLE_GENAI_USE_VERTEXAI=true, GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION in ~/.gemini/.env, and "selectedType": "vertex-ai" in settings.json. For credentials, exe.dev's GCP Workload Identity Federation lets the VM act as a service account with the Vertex AI User role and no key file: follow that guide, then add the GOOGLE_APPLICATION_CREDENTIALS line it creates to ~/.gemini/.env. Google's authentication guide covers the other Vertex AI options.

Troubleshooting#

  • When using Gemini API, you must specify the GEMINI_API_KEY environment variable: Gemini CLI didn't read ~/.gemini/.env. It reads only the first .env it finds, starting in the current folder, so a project with its own .env hides yours. Copy the two lines into the project's .gemini/.env (and keep that out of Git), or run set -a; . ~/.gemini/.env; set +a before gemini. It also skips .env files in folders you haven't trusted; trust the folder, or pass --skip-trust to headless runs.
  • Gemini CLI is not running in a trusted directory: a headless run in a new folder. Add --skip-trust, or open gemini there once and trust it.
  • 403 and integration not found or not attached to this VM: the Gemini integration isn't attached to this VM, or isn't called gemini. Check on the Integrations page, and use its name in GOOGLE_GEMINI_BASE_URL.
  • 429 and You have exhausted your daily quota on this model: the key's project hit Google's limit for that model; free-tier keys get little or none (limit: 0 means none). Switch model with /model or -m flash-lite, or link billing to the project in Google AI Studio.
  • 503 and This model is currently experiencing high demand: Google is busy. Gemini CLI retries on its own; if it gives up, try again or use another model.
  • 404 and no longer available to new users: an older model name, such as gemini-2.5-flash, that Google has retired for new keys. Use a current one from /model.
  • API key not valid: the key was refused. Check it in Google AI Studio.
  • Invalid auth method selected: ~/.gemini/settings.json has no selectedType; write it as in "Connect it to Gemini".
  • Anything else: Gemini CLI saves the full error report under /tmp and names the file in the message. Run gemini --debug for more, or see Google's troubleshooting guide.

Frequently asked questions#

Does Gemini CLI work with exe.dev's LLM gateway, without a key?

No. Gemini CLI only speaks Google's Gemini API, and the LLM gateway serves Claude, GPT and open models, not Gemini. So you need your own Gemini API key (or a Code Assist license, or Vertex AI). For an agent that needs no key at all, use Codex, Claude Code or OpenCode.

Can I sign in with my Google account or my Google AI Pro plan?

Only with an organization's Gemini Code Assist Standard or Enterprise license; see Other ways to sign in. On June 18, 2026 Google stopped serving Gemini CLI to free personal accounts and Google AI Pro and Ultra subscribers and moved them to Antigravity CLI. A Gemini API key from Google AI Studio still works.

How much does it cost?

Google bills Gemini API use to the project that owns your key, at its Gemini API prices; exe.dev doesn't charge for it. The VM is part of your exe.dev plan. A key on Google's free tier works for a quick try, but in October 2026 it got 20 requests a day on the main Flash model and none on Pro; one coding task can take dozens. Link a billing account to the key's project in Google AI Studio for real work.

How do I update Gemini CLI?

On the VM, run sudo npm install -g @google/gemini-cli@latest. Google releases a new version every week. Gemini CLI's own automatic update can't write to the system-wide install, so it may say it failed; the command above is the fix.

How do I back up my work?

Commit and push your code. For a copy of the whole VM, run ssh exe.dev cp my-gemini-cli my-gemini-cli-backup on your computer (choose a free backup name). Your files, ~/.gemini and chat history are in the copy. Attach the Gemini integration to the copy too, with ssh exe.dev integrations attach gemini vm:my-gemini-cli-backup.

Updated Oct 28, 2026 · tested end to end Oct 28, 2026 · Markdown · manifest.json · Something wrong? Tell us