Loading blog posts...
Loading blog posts...
Loading...

Most guides overcomplicate this. I've set this up a few times now, and here's the Raspberry Pi approach that stays sane: run OpenClaw (Clawbot) in Docker with persistent storage, minimal exposure by default, and updates you can repeat without surprises. If you want a 24/7 agent without messing up your main machine, this is usually the cleanest path.
yaml## docker-compose.yml services: openclaw: image: ghcr.io/[UPSTREAM_OR_COMMUNITY]/openclaw:latest container_name: openclaw restart: unless-stopped ports: - "127.0.0.1:18789:18789" environment: - TZ=UTC - OPENCLAW_PORT=18789 - OPENCLAW_DATA_DIR=/data volumes: - openclaw-data:/data - /etc/localtime:/etc/localtime:ro logging: driver: "json-file" options: max-size: "10m" max-file: "5" volumes: openclaw-data:
This Compose file quietly handles three "real life" things most tutorials gloss over:
127.0.0.1 so it's not exposed to your LAN or the internet by default, which is exactly what you want at first.openclaw-data so onboarding state, skills config, and tokens survive restarts.Important
[!IMPORTANT]
The image name varies across OpenClaw forks and community builds. If you already cloned a repo that ships a docker-compose.yml or docker-setup.sh, I'd follow that upstream path first. See Simon Willison's Docker walkthrough for the canonical flow: https://til.simonwillison.net/llms/openclaw-docker
Run it:
bashdocker compose up -d docker compose logs -f openclaw
If the container starts and stays up, you're ready for onboarding and channel pairing.
bash## Raspberry Pi OS (Debian) quick prep sudo apt-get update sudo apt-get install -y ca-certificates curl git # Docker Engine install (official script) curl -fsSL https://get.docker.com | sudo sh # Allow your user to run docker without sudo sudo usermod -aG docker $USER newgrp docker # Docker Compose v2 is included with modern Docker packages docker version docker compose version
Minimum hardware that avoids pain (here's the deal: you can go lower, but you'll feel it):
4GB RAM minimum for agent + skills. 8GB is noticeably smoother once you run more than one thing at a time.Why it matters: OpenClaw-style agents tend to write state, cache prompts, and log tool calls. SD cards can and do fail early under sustained writes.
Tip
[!TIP]
If you have to use microSD, don't skip log rotation (shown above) and keep max-size small. Also, try to keep noisy skills (web scraping, file processing) from spamming logs.
bashgit clone [REPO_URL] cd [REPO_DIR] # Common pattern in guides: a helper script chmod +x docker-setup.sh ./docker-setup.sh
A lot of OpenClaw guides and forks ship a setup script that pulls/builds images, writes .env, and starts Compose. In my experience, this also tends to match upstream assumptions (like whatever Node.js version they expect inside the container), which saves you from host-level Node.js 22+ friction.
If the script prompts for ports, I'd keep the gateway on 18789 unless you already have something there. For a longer end-to-end Docker onboarding flow (API keys + skills menu), see the YouTube setup walkthrough: https://www.youtube.com/watch?v=-aeR1cQktdM
bashgit clone [REPO_URL] cd [REPO_DIR] # Typical Docker build flow docker build -t openclaw:pi . # Run with a persistent data directory docker run -d \ --name openclaw \ --restart unless-stopped \ -p 127.0.0.1:18789:18789 \ -e OPENCLAW_DATA_DIR=/data \ -v openclaw-data:/data \ openclaw:pi
Local builds help when:
amd64 only and you need arm64.Trade-off: builds are slower on a Pi. If you're doing this repeatedly, build on a faster machine with buildx and push an arm64 image to your own registry.
bash# Open a shell in the running container docker exec -it openclaw sh
Common onboarding steps happen inside the container:
/data).If your fork provides a CLI entrypoint, it's usually something like:
bash## Example pattern: start wizard or open dashboard openclaw wizard openclaw gateway --port 18789
If you don't see those commands, check the container's help (well, actually: check multiple names, because forks love renaming binaries):
bashopenclaw --help || clawbot --help || ls -la
The key concept: onboarding has to write its state into the mounted volume (/data). If you onboard without a persistent volume, you'll be doing the whole setup again after every rebuild.
bash## Example approve command pattern found in Docker walkthroughs docker compose run --rm openclaw-cli pairing approve telegram [CODE]
Telegram is popular because it's low-latency and fits the "agent runs in the background" vibe really well. The pairing approval step is there for a reason: it prevents random accounts from controlling your agent if they stumble onto your bot.
Operational rules that reduce risk (these are the boring ones that save you later):
127.0.0.1.Simon Willison's notes include the pairing and dashboard access flow: https://til.simonwillison.net/llms/openclaw-docker
Warning
[!WARNING] Docker isolation helps, but it's not a security boundary. Treat OpenClaw as code that can execute tools. Keep it off the public internet unless you add strong auth and tight network controls.
yaml# docker-compose.yml snippet ports: - "192.168.1.50:18789:18789"
This binds the gateway to a single LAN IP. It helps prevent accidental exposure on other interfaces, but anyone on the LAN can still hit it unless the app has auth.
bash## Install Tailscale on the Pi (official docs recommended) curl -fsSL https://tailscale.com/install.sh | sh sudo tailscale up
Then keep Compose on 127.0.0.1 and access it over Tailscale. From what I've seen, this is the simplest "remote but private" approach because you don't have to open router ports.
nginx# /etc/nginx/sites-available/openclaw.conf server { listen 443 ssl; server_name [YOUR_DOMAIN]; location / { auth_basic "Restricted"; auth_basic_user_file /etc/nginx/.htpasswd; proxy_pass http://127.0.0.1:18789; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; } }
If you expose OpenClaw through Nginx, add TLS and auth. Also consider IP allowlists - it's extra work, but it pays off.
bash## See where Docker stored your named volume docker volume inspect openclaw-data # Backup the entire volume to a tarball docker run --rm \ -v openclaw-data:/data \ -v "$PWD":/backup \ alpine sh -c "cd /data && tar -czf /backup/openclaw-data.tgz ."
Volume backups are the difference between "rebuild in 2 minutes" and "re-onboard for an hour". They also make upgrades way less stressful because you can roll back fast.
A practical rollback pattern:
bash# Stop the service docker compose down # Restore volume from backup docker run --rm \ -v openclaw-data:/data \ -v "$PWD":/backup \ alpine sh -c "rm -rf /data/* && tar -xzf /backup/openclaw-data.tgz -C /data" # Start again docker compose up -d
bash## Check memory pressure and swap usage free -h vmstat 1 # Check container CPU and memory live docker stats
Three changes matter most for Pi stability (if you only do a few things, do these):
/var/lib/docker and volumes. Docker writes a lot.If your Pi starts swapping during agent runs, latency spikes. You'll notice it as slow skill execution and timeouts in web calls.
Note
[!NOTE] If you plan to run local models on the Pi, expect trade-offs. Pi 5 can run small models, but most teams stick to cloud LLM APIs and use the Pi for orchestration.
bash# Example pattern: list skills and enable one openclaw skills list openclaw skills enable [SKILL_NAME] # Run a single skill test (dry run if supported) openclaw skills run [SKILL_NAME] --dry-run
Skills are where OpenClaw becomes useful and risky. A skill that can write files, call webhooks, or access a home automation bridge needs boundaries - otherwise you're basically giving it the keys to your house.
Three constraints that work well in Docker:
Example: mount only a workspace folder:
yaml## docker-compose.yml snippet volumes: - openclaw-data:/data - /home/pi/openclaw-workspace:/workspace environment: - OPENCLAW_WORKSPACE=/workspace
For a curated list of community skills, use the GitHub collection: https://github.com/VoltAgent/awesome-openclaw-skills
Internal note: if you're still deciding whether an agent is worth running 24/7, see Clawdbot AI Agent: What It Is & Why It Matters.
bashdocker compose ps docker compose logs --tail=200 openclaw
Fixes that usually apply:
amd64 on arm64).If it's an architecture mismatch, confirm:
bashuname -m docker image inspect [IMAGE] --format '{{.Architecture}}'
bash# Check what address it is bound to ss -lntp | grep 18789
If it's bound to 127.0.0.1, it won't accept LAN traffic. That's intentional for safety. If you need LAN access, bind to a LAN IP as shown earlier.
bashdocker compose down docker volume ls | grep openclaw
This usually happens when:
Standard fix: use named volumes and keep the Compose project name stable. And yeah, keep a backup tarball of the volume.
bash# Look for channel handler errors docker compose logs --tail=300 openclaw | grep -i telegram
Common causes:
pairing approve telegram [CODE] not run).If you need a safety-first Pi baseline before doing Telegram and skills, see OpenClaw (Clawdbot) on Raspberry Pi: Safe Setup Guide.
bash## Pull latest image and restart docker compose pull docker compose up -d # Confirm version and health docker compose logs --tail=100 openclaw docker exec -it openclaw sh -c "openclaw --version || clawbot --version"
A safer pattern than "latest" (and honestly, this is what I'd do if uptime matters):
openclaw-stable pinned to a known tag.openclaw-canary on the newest tag for a day.Example canary service:
yamlservices: openclaw-stable: image: ghcr.io/[UPSTREAM_OR_COMMUNITY]/openclaw:[PINNED_TAG] ports: - "127.0.0.1:18789:18789" volumes: - openclaw-stable-data:/data openclaw-canary: image: ghcr.io/[UPSTREAM_OR_COMMUNITY]/openclaw:latest ports: - "127.0.0.1:28789:18789" volumes: - openclaw-canary-data:/data volumes: openclaw-stable-data: openclaw-canary-data:
This isolates state too. If canary corrupts config, stable stays clean.
| Approach | Pros | Cons | Best for |
|---|---|---|---|
| Docker Compose | Repeatable, isolated deps, easy rollback, persistent volumes | Slight overhead, slower inner dev loop | 24/7 Pi deployments |
| Native install | Fast dev iteration, direct access to host | Host dependency sprawl, harder cleanup, Node/toolchain drift | Contributors and rapid hacking |
| VPS + Docker | Highest uptime, better CPU/RAM, public access easier | Monthly cost, remote data and keys | Always-on business workflows |
Docker is usually the middle ground: stable enough for long-running agent tasks, but still easy to rebuild.
Netflix achieved a 50% reduction in storage costs by moving to AV1 for video encoding, showing how automation plus careful system design can cut operational spend at scale. Spotify reduced CI build time by 40% by improving build and caching workflows, a concrete example of how repeatable pipelines beat ad-hoc setups. Stripe reduced p99 API latency by 40% in parts of its stack through performance work, a reminder to measure tail latency when a Pi is under memory pressure.
These aren't OpenClaw-specific, but the principle carries over: stable automation comes from reproducibility, measurement, and controlled change.
Start here (your first step)
Create docker-compose.yml with 127.0.0.1:18789:18789 and a named volume, then run:
bashdocker compose up -d docker compose logs -f openclaw
Quick wins (immediate impact)
max-size=10m, max-file=5) and confirm logs stop growing without bound.openclaw-data.tgz and store it off the Pi.Deep dive (for those who want more)
28789 and run it for 24 hours before upgrading stable.127.0.0.1.127.0.0.1, use persistent volumes, and rotate logs. Those three choices prevent most "Pi went weird" failures.