A Docker image for running the Google Gemini CLI in an isolated and reproducible environment, with native-like terminal usage as default and an optional browser mode via ttyd (for example at http://localhost:7681).
Current image/runtime versions in this repository:
ENTRYPOINTS_VERSION=2.1.0(base helper image:ghcr.io/coolcow/entrypoints)NODE_VERSION=22(base image:node:22)DOCKER_CLI_VERSION=27.5.1(Docker CLI binary inside container)TTYD_VERSION=1.7.7(ttydweb terminal binary)- Gemini CLI: started via
npx -y @google/gemini-cli(latest available package at runtime, not pinned in this image)
Add this function to your shell config (~/.bashrc or ~/.zshrc) so you can use gemini like a local command:
gemini() {
docker volume create gemini-home &> /dev/null
local tty_args=""
if [ -t 0 ]; then
tty_args="--tty"
fi
docker run -i ${tty_args} --rm \
-v "$(pwd)":"$(pwd)" \
-w "$(pwd)" \
-v gemini-home:/home/gemini \
-v /var/run/docker.sock:/var/run/docker.sock \
-e GEMINI_UID=$(id -u) \
-e GEMINI_GID=$(id -g) \
-e GEMINI_API_KEY="YOUR_API_KEY" \
-e NODE_OPTIONS=--no-deprecation \
ghcr.io/coolcow/gemini:latest "$@"
}Reload your shell:
source ~/.bashrcgemini
gemini --help
gemini -p "summarize this repository"The included compose.yml starts the ttyd service.
docker compose up -dThen open in your browser: http://localhost:7681
Key parts of compose.yml:
RUN_MODE=ttydstarts web terminal mode.volumes:./workspace:/workspaceis your working directory.home:/home/geminipersists settings and caches.
environmentincludesGEMINI_API_KEY,GEMINI_UID,GEMINI_GID,NODE_OPTIONS, etc.ports: 7681:7681publishes web access.
docker build -t ghcr.io/coolcow/gemini:local-build ./builddocker volume create gemini-homedocker run -it --rm \
-v "$(pwd)":"$(pwd)" \
-w "$(pwd)" \
-v gemini-home:/home/gemini \
-v /var/run/docker.sock:/var/run/docker.sock \
-e GEMINI_UID=$(id -u) \
-e GEMINI_GID=$(id -g) \
-e GEMINI_API_KEY="$GEMINI_API_KEY" \
-e NODE_OPTIONS=--no-deprecation \
ghcr.io/coolcow/gemini:local-builddocker run -it --rm \
-p 7681:7681 \
-v "$(pwd)":"$(pwd)" \
-w "$(pwd)" \
-v gemini-home:/home/gemini \
-v /var/run/docker.sock:/var/run/docker.sock \
-e RUN_MODE=ttyd \
-e GEMINI_UID=$(id -u) \
-e GEMINI_GID=$(id -g) \
-e GEMINI_API_KEY="$GEMINI_API_KEY" \
-e NODE_OPTIONS=--no-deprecation \
ghcr.io/coolcow/gemini:local-buildThen open in your browser: http://localhost:7681
-v "$(pwd)":"$(pwd)": bind-mounts the current project so Gemini can work directly on your files.-w "$(pwd)": sets the container working directory to your current project.-v gemini-home:/home/gemini: persistent home directory (config, caches, and potentially credentials).-v /var/run/docker.sock:/var/run/docker.sock: allows using Docker commands inside the container (talks to the host's Docker daemon). On startup, the runtime user is automatically added to the group that matches the socket GID.-e GEMINI_API_KEY=...: Gemini API key (required).-e GEMINI_UID/-e GEMINI_GID: ensures proper file ownership when writing to mounted project files.-e RUN_MODE=ttyd: optional, starts browser-basedttydmode (default withoutRUN_MODEis CLI).-e NODE_OPTIONS=--no-deprecation: optional, suppresses non-critical Node warnings.-e DOCKER_SOCK_PATH/-e DOCKER_GROUP_NAME: optional overrides for socket path and preferred docker group name.-p 7681:7681: forttydonly, maps the web port to the host.
Note: The image includes a recent Docker CLI binary, so Docker API version negotiation works with modern host daemons when /var/run/docker.sock is mounted.
The smoke tests verify, among other things, required binaries (ttyd, gosu), entrypoint syntax, and expected startup options.
-
Build the app image locally:
docker build -t ghcr.io/coolcow/gemini:local-test-build -f build/Dockerfile build
-
Run smoke tests via the test Dockerfile:
docker build --build-arg APP_IMAGE=ghcr.io/coolcow/gemini:local-test-build -f build/Dockerfile.test build
If the second build completes successfully, the smoke test passes.
- Heavily inspired by: https://github.com/tgagor/docker-gemini-cli
- This project was created with the help of Gemini CLI and reviewed by a human.