Docker / Home Server Guide

May 2, 2026 · View on GitHub

Run CheetahClaws in a container as a long-running home-server service: Web UI in the browser, Telegram bridge for your phone, all backed by an Ollama instance on the host.

This guide targets a Linux host (Ubuntu / DGX-Spark) running Docker 20.10+ and a local Ollama install. The same compose file works on macOS or Windows with minor tweaks called out inline.

CheetahClaws also runs perfectly well as a normal pip install. Use Docker when you want a long-running service, network-accessible UI, or process isolation. For local CLI use against your own files, native install is usually smoother.

Prerequisites

  • Docker Engine 20.10 or newer (docker --version)
  • Docker Compose v2 (docker compose version)
  • Ollama running on the host with at least one model pulled:
    ollama serve &
    ollama pull qwen2.5:7b   # or whichever model you plan to use
    
  • Optional: a Telegram bot token (@BotFather) and your numeric chat id

1. Get the source

git clone https://github.com/SafeRL-Lab/cheetahclaws.git
cd cheetahclaws

2. Configure the environment

cp .env.example .env
$EDITOR .env

Set:

  • UID / GID — match your host user (id -u, id -g) so files written into ./workspace are owned by you, not by root or some random container UID.
  • WEB_PORT — public port on the host. Default 8080.
  • ANTHROPIC_API_KEY / OPENAI_API_KEY — only if you plan to use the cloud providers. Leave blank for an Ollama-only setup.

3. Create the host directories

mkdir -p ./workspace ./data
  • ./workspace — the agent's working directory. Mount whatever you want it to read/edit. Share this folder over Samba to access it from your phone or other PCs.
  • ./data — persists ~/.cheetahclaws (config, session history, snapshots).

4. Bring the stack up

docker compose up -d --build
docker compose logs -f cheetahclaws

You should see:

CheetahClaws Web Terminal
────────────────────────────────────────
Terminal: http://localhost:8080
Chat UI:  http://localhost:8080/chat
Host:     0.0.0.0 (network accessible)
Terminal pwd: <auto-generated>

Open http://<host-ip>:8080/chat from any device on your LAN.

5. First-run configuration (inside the container)

The first time you visit the Chat UI it'll prompt to create an account. After login:

  • Pick a model: open settings → choose custom provider, set the base URL to http://host.docker.internal:11434/v1, and set the model to ollama/qwen2.5:7b (or whatever you pulled). Save.
  • Telegram bridge (optional): in the agent prompt, type /config telegram_token <your-bot-token> and /config telegram_chat_id <your-chat-id>. Restart the container (docker compose restart) — the bridge auto-starts on next boot.

Config persists to ./data/config.json on the host.

Reaching Ollama on the host

The compose file adds:

extra_hosts:
  - "host.docker.internal:host-gateway"

Inside the container, host.docker.internal resolves to the host's Docker gateway IP. Use http://host.docker.internal:11434/v1 as the OpenAI-compatible base URL.

If your Ollama is bound only to 127.0.0.1 on the host, you'll need to either:

  • Set OLLAMA_HOST=0.0.0.0:11434 before ollama serve, or
  • Add network_mode: host to the service in compose (and remove the ports: block, since host networking takes them as-is).

Sharing the workspace over SMB (Linux host)

sudo apt install samba
sudo tee -a /etc/samba/smb.conf <<'EOF'
[cheetahclaws]
   path = /home/<you>/cheetahclaws/workspace
   browseable = yes
   writable = yes
   guest ok = no
   valid users = <you>
EOF
sudo smbpasswd -a <you>
sudo systemctl restart smbd

From your other PC / phone, connect to smb://<host-ip>/cheetahclaws. Files you drop in show up at /workspace inside the container immediately.

Common operations

TaskCommand
Tail logsdocker compose logs -f cheetahclaws
Restartdocker compose restart
Update to latest sourcegit pull && docker compose up -d --build
Shell into the containerdocker compose exec cheetahclaws bash
Run the CLI directlydocker compose exec cheetahclaws cheetahclaws
Reset configrm -rf ./data && docker compose restart

Troubleshooting

"Cannot connect to Ollama" — the container can't reach host.docker.internal:11434. Verify:

docker compose exec cheetahclaws curl -s http://host.docker.internal:11434/api/tags

If this fails, your Ollama is bound to localhost only. Set OLLAMA_HOST=0.0.0.0:11434 and restart it.

Files in /workspace show up as root-owned on the hostUID/GID in .env don't match the host user. Run id -u/id -g, update .env, docker compose up -d.

Web UI not reachable from phone — check the host firewall (sudo ufw allow 8080/tcp) and confirm --host 0.0.0.0 is in the logs.

Telegram bridge not responding — check docker compose logs cheetahclaws | grep -i telegram. Token/chat-id are loaded from ~/.cheetahclaws/config.json (i.e., ./data/config.json on the host). Validate they're set, then restart the container.

Chat UI loads but every JS/CSS asset is 404 (/marked.min.js, /static/js/chat.js, …) — the running server is reading static files from a web/ directory that doesn't actually contain them. This almost always means a custom Dockerfile used a non-editable install (pip install .[all]) without bundling package data, so web/ in site-packages/ is missing the static/js/ subtree. Two ways out:

  • Easiest: use this repo's Dockerfile + docker-compose.yml unchanged. It uses pip install -e '.[web]', which keeps web/ pointed at the source tree.
  • Or, in your custom Dockerfile, switch to editable install:
    RUN pip install --no-cache-dir -e '.[all]'
    
    Editable install leaves web/server.py next to its static/ directory, so the asset paths resolve correctly regardless of how setuptools handled package-data.

If you must do a non-editable install, make sure your build is using setuptools >= 62 and that pyproject.toml's [tool.setuptools.package-data] for web includes static/**/* (it does, on main). Older setuptools or stale build caches can silently drop subdirectory data.

Custom Dockerfile pitfalls

If you're rolling your own image instead of the one in this repo, keep these in mind:

  • Use editable install (pip install -e '.[web]'). The chat UI's static files (web/static/js/*.js) are package data, not Python code. Editable install removes any dependency on package-data correctly making it into the wheel — web/server.py is read directly from the source tree.
  • Don't WORKDIR away before pip install. The install must run with the project's pyproject.toml at the build context root so setuptools can resolve [tool.setuptools.package-data].
  • COPY the full source tree, not just pyproject.toml + a few .py files. The chat UI ships HTML/JS/CSS that lives outside the Python source — leaving them out is the most common reason /chat loads but assets 404.
  • Match Python ≥ 3.10. The server uses Path.is_relative_to, match/case, and other 3.10+ features.
  • Run cheetahclaws --web --host 0.0.0.0. Without --host 0.0.0.0 the server only binds to 127.0.0.1 inside the container, which Docker's port mapping cannot reach from the host.

Security notes

  • The Web UI ships with first-visit-creates-admin auth. Don't run with --no-auth outside 127.0.0.1.
  • Restrict WEB_PORT to the LAN with your router/firewall — it is not designed to be exposed to the public internet without extra hardening (reverse proxy + TLS + IP allowlist at minimum).
  • The agent has full read/write inside /workspace. Mount only directories you're comfortable letting it edit.