Stop Uploading Code: Run Gemini CLI Remotely with Docker
We have all been there. You are working on a complex refactor. You need an LLM's help. So you start the ritual: select code, copy, switch tab, paste. Or worse, you zip up a folder and upload it to a chat interface, waiting for it to process.
This interaction model is broken. It treats the AI as an outsider that needs to be fed snippets of reality.
The Gemini CLI changes this. It runs locally, scanning your current directory to understand the full project structure. It essentially "lives" in your terminal.
But what if you aren't on your main machine? What if you want to leverage that deep, filesystem-level understanding from an iPad, a Chromebook, or a hotel business center computer?
The answer isn't to replicate your environment everywhere. It's to containerize it and access it via the browser.
The "Why": Unlocking Gemini CLI's True Power
Before diving into the Docker setup, we need to understand why accessing gemini-cli remotely is so much better than using a standard web chat interface. The magic lies in three native capabilities that generic web UIs simply cannot match:
- Unlimited Context Awareness: Standard chats have file limits.
gemini-clihas zero boundaries. It can recursively scan your entiresrc/directory, understand your.gitignorerules, and build a mental map of your project without you manually selecting a single file. - Active Agent vs. Passive Advisor: A web chat can only give you text.
gemini-clican take action. It can write new files, edit existing code, and even execute shell commands to run tests or builds. It doesn't just suggest the fix; it applies it. - The "Localhost" Advantage: It runs where your data lives. There is no latency in "uploading context" because the context is already there on the disk.
By Dockerizing this tool, we are not just making a terminal portable. We are making this infinite context and agency portable.
The Concept: Remote Execution, Local Context
We are going to build a Docker image that contains:
- Your Project Code: Mounted as a volume.
- The Gemini CLI: Installed globally.
- A Web Terminal: A browser-based interface (
node-pty+xterm.js) to interact with the shell.
This architecture flips the script. Instead of bringing your code to the AI (uploading), you bring the interaction layer (the browser) to the environment where both the AI and the Code coexist.
The Result: You open a URL in Chrome/Safari, and you have a fully functional terminal. You type gemini chat "Refactor the auth module", and it works immediately because it has direct, native access to ./src/auth. No uploads. No context loss.
The Build: Dockerizing the Workflow
We'll take a simple Node.js web terminal application and supercharge it.
1. The Base: Web Terminal
We use a standard express + ws (WebSocket) setup to stream a PTY (Pseudo Terminal) to the browser. This gives us a real shell, not a simulated one.
2. The Dockerfile
We modify the build to ensure the Gemini CLI is present and executable.
# Stage 1: Build the Frontend Interface
FROM node:20-slim AS builder
WORKDIR /app
COPY frontend/ ./frontend/
WORKDIR /app/frontend
RUN npm install && npm run build
# Stage 2: The Powerhouse Runtime
FROM node:20-slim
WORKDIR /app
# Install system utilities needed for a real terminal experience
RUN apt-get update && apt-get install -y python3 make g++ procps git curl --no-install-recommends
# 🚀 THE KEY STEP: Install Gemini CLI Globally
# This gives the container the ability to reason about its own filesystem
RUN npm install -g @google/gemini-cli
# Cleanup
RUN apt-get purge -y python3 make g++ && apt-get autoremove -y --purge && rm -rf /var/lib/apt/lists/*
# Setup App
COPY package.json package-lock.json* ./
RUN npm install --omit=dev
COPY server.js .
COPY --from=builder /app/frontend/dist ./public
EXPOSE 3000
CMD ["node", "server.js"]
3. The Composition: Mounting the Context
The real magic happens in docker-compose.yml. We mount our actual development directory into the container.
services:
gemini-context-engine:
build: .
ports:
- "3000:3000"
volumes:
# DIRECT CONTEXT ACCESS
# The container sees exactly what is on the host disk.
# Changes made by Gemini here are reflected instantly on your host.
- ./my-active-project:/workspace
# AUTH PERSISTENCE
# Keep your login session alive across restarts
- gemini-config:/root/.config/configstore
environment:
- PORT=3000
- HOME=/workspace
working_dir: /workspace
volumes:
gemini-config:
The Experience: Zero Latency Context
Once deployed (on your local machine or a private VPS), the workflow becomes frictionless:
- Open Browser: Navigate to
http://your-server:3000. - Authenticate: Run
gemini login(one-time setup). - Execute:
# The CLI sees the entire /workspace directory natively gemini chat "Create a unit test for the userController in src/"
Because the CLI is running inside the container, it reads the files directly from the disk. It doesn't need to "download" or "process" uploads. It just reads src/userController.js and writes tests/userController.test.js directly to the volume.
Why This Beats Chat Interfaces
- No File Limits: The CLI can grep and read anything in the volume. You aren't limited by "5 files max" upload restrictions.
- Security: Your code stays on your server/machine. You aren't uploading zips to a third-party chat history bucket (beyond the context sent to the API for inference).
- Agency: The CLI can execute shell commands, run tests, and manage git (if installed), all driven by your prompts from a tablet.
Conclusion
Stop treating AI as an external consultant you email files to. Integrate it into the environment where the work happens. By Dockerizing the Gemini CLI with a web terminal, you get the best of both worlds: the portability of the web and the raw power of local filesystem access.
