Docker
ClawHalla runs inside Docker containers to provide a consistent, reproducible environment regardless of the host OS. This reference covers the image architecture, compose services, and customization options.
Image Details
The ClawHalla Docker image is built on Ubuntu 24.04 and includes:
| Component | Version | Purpose |
|---|---|---|
| Ubuntu | 24.04 LTS | Base OS |
| Node.js | 24 (via nvm) | Runtime for OpenClaw and MC |
| pnpm | Latest (via corepack) | Package manager |
| Python 3 | System default | Scripts and tools |
| Zsh | Latest | Default shell |
| Oh My Zsh | Latest | Shell framework |
| Spaceship | Latest | Prompt theme |
| Zinit | Latest | Plugin manager |
| Homebrew | Latest (Linux) | Additional package management |
| OpenClaw CLI | Latest (via pnpm) | Agent framework |
| Git | System default | Version control |
| curl, wget | System default | HTTP tools |
Dockerfile Layers Explained
The Dockerfile builds the image in logical layers:
1. Base system
FROM ubuntu:24.04ENV DEBIAN_FRONTEND=noninteractiveRUN apt-get update && apt-get upgrade -yStarts from a clean Ubuntu 24.04 image and updates all packages.
2. System packages
RUN apt-get install -y \ git curl build-essential adduser sudo \ ca-certificates procps python3 python3-pip \ python3-venv zsh wget locales \ && locale-gen en_US.UTF-8Installs essential tools for development, shell, and runtime.
3. User creation
ARG CLAWDBOT_PASSWORD=clawdbotRUN adduser --gecos '' --disabled-password clawdbot \ && echo "clawdbot:${CLAWDBOT_PASSWORD}" | chpasswdRUN echo 'clawdbot ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/clawdbotCreates the clawdbot user with sudo access. The password is configurable via build arg or .env.
4. Node.js and pnpm
RUN bash -c 'curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash' \ && bash -c '. ~/.nvm/nvm.sh && nvm install 24 && corepack enable pnpm'Installs NVM, Node 24, and enables pnpm through Corepack.
5. Homebrew
RUN bash -c 'NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"'Installs Homebrew for Linux, enabling easy installation of additional tools.
6. OpenClaw CLI
RUN bash -c '. ~/.nvm/nvm.sh && pnpm add -g openclaw'Installs the OpenClaw CLI globally. The onboarding wizard runs manually after container start.
7. Shell environment
# Oh My ZshRUN sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended
# Spaceship themeRUN git clone https://github.com/spaceship-prompt/spaceship-prompt.git \ "$HOME/.oh-my-zsh/custom/themes/spaceship-prompt" --depth=1
# Zinit plugin managerRUN mkdir -p "$HOME/.zinit" \ && git clone https://github.com/zdharma-continuum/zinit "$HOME/.zinit/bin" --depth=1Sets up a productive zsh environment with syntax highlighting, autosuggestions, and completions.
8. Entrypoint
COPY docker/entrypoint.sh /entrypoint.shCOPY docker/.zshrc /home/clawdbot/.zshrc.defaultRUN chsh -s /bin/zsh clawdbotENTRYPOINT ["/entrypoint.sh"]CMD ["sleep", "infinity"]The entrypoint script creates required directories and fixes permissions. The container runs indefinitely, waiting for interactive use.
docker-compose.yml
ClawHalla uses Docker Compose to manage two services:
version: "3.8"
services: clawhalla: build: . container_name: clawhalla hostname: clawhalla restart: unless-stopped stdin_open: true tty: true ports: - "18789:18789" # OpenClaw Gateway - "3000:3000" # Mission Control (internal) volumes: - ./volumes/openclaw:/home/clawdbot/.openclaw env_file: - .env
mission-control: build: context: ./apps/mission-control dockerfile: Dockerfile container_name: clawhalla-mc restart: unless-stopped ports: - "3333:3000" # Mission Control (external) environment: - GATEWAY_URL=http://clawhalla:18789 - GATEWAY_TOKEN=${GATEWAY_TOKEN} depends_on: - clawhallaServices
| Service | Container Name | Purpose |
|---|---|---|
clawhalla | clawhalla | Main container with OpenClaw, agents, and gateway |
mission-control | clawhalla-mc | Web dashboard (Next.js) |
Volumes and Persistence
All persistent data lives in the volumes/ directory on the host:
volumes/└── openclaw/ # Mounted at /home/clawdbot/.openclaw ├── openclaw.json # Runtime config ├── agents/ # Agent directories and sessions ├── workspace/ # Agent workspace files ├── cron/ # Cron job definitions and run history ├── skills/ # Managed skills ├── hooks/ # Managed hooks └── logs/ # Command logsVolume permissions
The entrypoint script ensures correct ownership:
sudo mkdir -p "${OPENCLAW_DIR}"sudo chown -R clawdbot:clawdbot "${OPENCLAW_DIR}"If you see permission errors, fix them manually:
sudo chown -R 1000:1000 volumes/openclawPort Mapping
| Host Port | Container Port | Service |
|---|---|---|
18789 | 18789 | OpenClaw Gateway (WebSocket + HTTP) |
3000 | 3000 | Mission Control (internal, on clawhalla container) |
3333 | 3000 | Mission Control (external, on MC container) |
Changing ports
To change the gateway port:
-
Edit
docker-compose.yml:ports:- "19000:18789" -
Update
.env:Terminal window OPENCLAW_GATEWAY_PORT=18789 # Internal port stays the same -
Rebuild:
docker compose up -d --build
Health Checks
Gateway health
# From hostcurl http://localhost:18789
# From inside containercurl -I http://localhost:18789Mission Control health
# From hostcurl http://localhost:3000/api/health# orcurl http://localhost:3333/api/health
# Response{"status":"ok","timestamp":"2026-03-26T10:00:00.000Z"}Container health
# Check container statusdocker compose ps
# Check container resource usagedocker stats clawhalla clawhalla-mc
# View container logsdocker compose logs -f clawhalladocker compose logs -f mission-controlMulti-Container Setup
For production deployments, you may want to separate services:
version: "3.8"
services: clawhalla: build: . container_name: clawhalla restart: unless-stopped stdin_open: true tty: true ports: - "18789:18789" volumes: - openclaw-data:/home/clawdbot/.openclaw env_file: - .env deploy: resources: limits: memory: 4G cpus: "2.0"
mission-control: build: context: ./apps/mission-control dockerfile: Dockerfile container_name: clawhalla-mc restart: unless-stopped ports: - "3000:3000" environment: - GATEWAY_URL=http://clawhalla:18789 - GATEWAY_TOKEN=${GATEWAY_TOKEN} - NODE_ENV=production depends_on: - clawhalla deploy: resources: limits: memory: 1G cpus: "1.0"
volumes: openclaw-data: driver: localRun with: docker compose -f docker-compose.prod.yml up -d
Building Custom Images
Extending the base image
Create a new Dockerfile that builds on top of ClawHalla:
FROM clawhalla:latest
USER clawdbot
# Install additional toolsRUN bash -c '. ~/.nvm/nvm.sh && pnpm add -g typescript tsx'
# Add custom scriptsCOPY scripts/custom-setup.sh /home/clawdbot/custom-setup.sh
# Add custom workspace filesCOPY workspace-template/ /home/clawdbot/.openclaw/workspace/Building with custom arguments
docker compose build \ --build-arg CLAWDBOT_PASSWORD=my-secure-passwordUsing a different base image
To use a different Ubuntu version or base:
FROM ubuntu:22.04# ... rest of DockerfileUseful Docker Commands
# Enter the containerdocker compose exec clawhalla zsh
# View real-time logsdocker compose logs -f clawhalla
# Restart a servicedocker compose restart clawhalla
# Rebuild and restartdocker compose up -d --build
# Stop everythingdocker compose down
# Stop and remove volumes (destructive!)docker compose down -v
# Check disk usagedocker system df
# Clean unused imagesdocker image prune -f