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

You've probably hit the same Raspberry Pi wall I have: containers that won't start after a reboot, mystery ARM image issues, and a "gateway" you accidentally exposed to the internet. This guide sets up OpenClaw (formerly Clawdbot/MoltBot) on Raspberry Pi with Docker Compose so it survives reboots, upgrades cleanly, and stays private by default.
sudoOPENAI_API_KEY or ANTHROPIC_API_KEYImportant
[!IMPORTANT] OpenClaw is a 2025-2026 rebrand. When pulling images or reading docs, "Clawdbot/MoltBot" references may map to "OpenClaw" now. I'd double-check repo names and image tags before assuming a tutorial is current.
bashsudo apt update sudo apt -y full-upgrade sudo reboot
In my experience, this is what prevents a lot of the "random" container failures: old kernels, mismatched cgroups, stale libraries, that whole mess. Raspberry Pi OS updates also include network and filesystem fixes that matter a lot on always-on devices.
After reboot, confirm you are on 64-bit userspace:
bashuname -m getconf LONG_BIT
If uname -m shows aarch64 and LONG_BIT is 64, you're set. If not, switch to Raspberry Pi OS 64-bit before going further. Multi-arch images and memory behavior are just better (and you'll save yourself time later).
bashsudo apt -y install smartmontools lsblk
Running OpenClaw 24/7 writes state and logs. SSDs handle this way better than SD cards. If you have to use SD, keep logs small and rotate them (we do that later via Docker logging options).
bashcurl -fsSL https://get.docker.com | sudo sh sudo usermod -aG docker $USER newgrp docker
The get.docker.com script installs a Docker build that usually plays nicely with Raspberry Pi OS. Adding your user to the docker group means you won't be sprinkling sudo everywhere, which also helps avoid weird permission surprises on bind mounts.
Install the Compose plugin and basic tooling:
bashsudo apt -y install docker-compose-plugin git jq docker --version docker compose version
If docker compose version prints a version, you have the modern Compose plugin (which is what you want, not the old docker-compose Python binary).
Tip
[!TIP] If Docker commands hang on first run, reboot once. Some Pi setups just need a clean restart after installing kernel modules and enabling the Docker service.
bashmkdir -p ~/openclaw cd ~/openclaw
Nothing fancy here. Keeping everything in one folder makes upgrades and backups painless. The goal is a reproducible stack: Compose file, .env, and a persistent data directory.
Create docker-compose.yml:
yamlservices: openclaw: image: openclawai/openclaw:latest container_name: openclaw restart: unless-stopped # Default to LAN-only access. Change only if you have a VPN/tunnel/reverse proxy. ports: - "127.0.0.1:18789:18789" env_file: - .env volumes: - ./data:/var/lib/openclaw - ./logs:/var/log/openclaw # Keeps container logs from eating your SD/SSD over time logging: driver: "json-file" options: max-size: "10m" max-file: "3" # Helps on small devices: prevents runaway memory from killing the Pi mem_limit: 1500m
This Compose setup does three things that, from what I've seen, prevent the most common Raspberry Pi failures.
Binding 18789 to 127.0.0.1 keeps the gateway private (don't skip this). Exposing it to your WAN is the fastest way to get abused, and the 2026 security updates happened for a reason. The bind mounts ./data and ./logs make state survive container rebuilds and image updates. And log rotation prevents slow storage death by a million tiny writes.
Warning
[!WARNING]
Do not change 127.0.0.1:18789:18789 to 0.0.0.0:18789:18789 unless you are putting it behind a VPN, tunnel, or strict reverse proxy auth. Publicly exposed gateways have been abused in real deployments, and defaults have tightened in v2026.1.x for that reason.
Some guides reference older Clawdbot/MoltBot image names. If the pull fails, check the official Docker deployment doc and update the image: line accordingly: Docker Deployment Guide - Clawdbot AI. Also compare with the Compose approach described here: Running OpenClaw in Docker.

Create .env:
bashcd ~/openclaw nano .env
Paste and edit:
bash## OpenClaw gateway settings OPENCLAW_GATEWAY_PORT=18789 # Generate a strong token. Do not reuse passwords. OPENCLAW_GATEWAY_TOKEN=[PASTE_LONG_RANDOM_TOKEN] # Choose one provider (or both if supported by your build) OPENAI_API_KEY=[YOUR_OPENAI_KEY] ANTHROPIC_API_KEY=[YOUR_ANTHROPIC_KEY] # Optional: keep the bot predictable on a small device OPENCLAW_MAX_CONCURRENCY=2 OPENCLAW_LOG_LEVEL=info
Tokens and API keys belong in .env because it keeps secrets out of your Compose file and makes upgrades safer. Then when you back up docker-compose.yml, you can leave .env out (or stash it in a password manager).
Generate a strong token:
bashopenssl rand -hex 32
Paste that output into OPENCLAW_GATEWAY_TOKEN. Honestly, a long random token matters more than people expect because gateways get hit by automated scanners even on home networks (yep, really).
bashcd ~/openclaw docker compose pull docker compose up -d docker compose ps
pull forces a clean image download for ARM. up -d starts it in the background. ps shows whether the container is healthy or stuck restarting.
Check logs immediately:
bashdocker logs -n 200 openclaw
If OpenClaw requires an onboarding wizard, the logs usually show the first URL to open, pairing codes, or missing environment variables. Get that sorted before moving on, because "it runs but does nothing" is almost always onboarding or token-related.
From the Raspberry Pi itself:
bashcurl -sS http://127.0.0.1:18789/ | head
From another machine on your LAN, you have two safe options.
Option A: SSH port forward (fastest, no network changes):
bashssh -L 18789:127.0.0.1:18789 pi@[RASPBERRY_PI_IP]
Then open this locally:
bashhttp://127.0.0.1:18789
Option B: bind to LAN IP only (still private, but reachable on LAN). Change Compose ports: to:
yamlports: - "[RASPBERRY_PI_LAN_IP]:18789:18789"
SSH forwarding is usually the least error-prone because it never exposes the service to the whole subnet. LAN bind is fine if the network is trusted and segmented (and you know what else is on that network).
Note
[!NOTE]
Many tutorials cite port 18789 for the gateway. Keep it consistent. Randomizing ports doesn't replace authentication, but it does cut down on drive-by noise on shared networks.

Upgrade flow:
bashcd ~/openclaw docker compose pull docker compose up -d docker image prune -f
This pulls the latest image, recreates the container, and removes old images to save disk. Because state is in ./data, upgrades don't wipe your config or history.
For a reversible upgrade, pin a version tag instead of latest:
yamlimage: openclawai/openclaw:2026.1.3
Pinning is boring, which is exactly why it works. On a Raspberry Pi that runs 24/7, surprise changes are a top cause of downtime.
Install and enable a firewall:
bashsudo apt -y install ufw sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw allow 22/tcp sudo ufw enable sudo ufw status verbose
This blocks inbound traffic except SSH. Because OpenClaw is bound to localhost in Compose, you're already in decent shape, but a firewall still helps if someone later tweaks port bindings (future-you counts).
Add Fail2ban for SSH brute-force noise:
bashsudo apt -y install fail2ban sudo systemctl enable --now fail2ban sudo fail2ban-client status
These two steps cover the most common home Pi compromise path: exposed SSH with weak credentials. For Docker security posture and guardrails, the same principles apply as in our Claude Code 2026 Best Practices: Guardrails & Tests guide: restrict access paths first, then add automation.
Start with a curated list so you don't install random packages blindly:
The practical constraint on Raspberry Pi isn't "can it run" but "can it run while staying responsive." Skills that scrape web pages, run headless browsers, or spawn lots of subprocesses will starve the device.
And here's the thing: a good pattern is to keep OpenClaw on the Pi, but offload heavy tools to another machine via SSH or HTTP. Think of the Pi as the always-on coordinator, not the compute node.
Run these tests in order. They catch the real failures: bad mounts, bad tokens, and broken networking.
bashdocker compose ps docker inspect -f '{{.State.Status}} {{.State.Restarting}}' openclaw
If it is restarting, check logs and fix config first. Restart loops usually come from missing required env vars or a permissions mismatch on ./data.
bashcd ~/openclaw docker compose down docker compose up -d ls -la ./data
If ./data stays populated, you have real persistence. If it is empty or root-owned unexpectedly, fix permissions. A common fix:
bashsudo chown -R $USER:$USER ~/openclaw/data ~/openclaw/logs
bashss -lntp | grep 18789 || true
If you see 0.0.0.0:18789, you exposed it. Put it back to 127.0.0.1:18789 unless you have a VPN or strict reverse proxy auth.
bashdocker exec -it openclaw /bin/sh -lc 'env | egrep "OPENAI_API_KEY|ANTHROPIC_API_KEY|OPENCLAW_" | sed "s/=.*/=REDACTED/"'
If keys are missing, the .env file is not being loaded or has formatting issues. The most common mistake is spaces around = or copying smart quotes from a notes app (been there).
bashuname -m docker pull openclawai/openclaw:latest
If the Pi is 32-bit (armv7l), many images won't support it. Move to Raspberry Pi OS 64-bit. If you are already on 64-bit but still failing, the image may not be multi-arch. Confirm in the official Docker doc: Docker Deployment Guide - Clawdbot AI.
bashdocker logs -n 300 openclaw docker inspect openclaw --format '{{json.State}}' | jq
Exit-on-start is usually one of these: missing gateway token, missing provider key, or a required directory not writable. Fix .env first, then verify ./data permissions.
bashsudo ss -lntp | grep 18789 docker compose down
Another process is already using that port, or a previous container is still running. Stop the old container. If you must change ports, change both the host port mapping and any client URLs.
bashdocker stats --no-stream vcgencmd measure_temp
When RAM pressure hits, Linux will swap and everything feels broken. Reduce concurrency in .env, keep mem_limit, and remove heavy skills. If you need browser automation, run it on a separate box and call it from the Pi.
Read the incident-focused guidance: OpenClaw Complete Guide 2026. The practical takeaway is simple: private bind by default, strong token always, and avoid "no auth" modes if you see them in old tutorials.
Docker Compose is popular here because it gives repeatable deployments with a small operational surface area. That matters on edge devices where "fix it live" is painful (and usually happens at the worst time).
Here is how the trade-offs compare for Raspberry Pi deployments:
| Approach | Pros | Cons | Best For |
|---|---|---|---|
| Docker Compose (single service) | Reproducible, easy upgrades, clean persistence | Needs Docker knowledge, image tags matter | Most Pi users running 24/7 |
| Native install (npm/systemd) | Direct access to host, fewer layers | Dependency drift, harder rollbacks | Dev boxes and quick experiments |
| Compose + reverse proxy (Caddy/Nginx) | Clean HTTPS, better access control | More moving parts, cert management | Remote access with proper auth |
| Compose + VPN (Tailscale/WireGuard) | No public exposure, simple remote access | Requires VPN setup on clients | Home networks and small teams |
Big-company container patterns map down surprisingly well to a Pi. Netflix reported a 50% reduction in deployment-related incidents after moving services to immutable container images with standardized pipelines (Netflix TechBlog references across multiple posts). Stripe has described how strong isolation boundaries and repeatable deploys reduce "works on my machine" drift in production systems. Shopify has published multiple case studies showing that consistent build and release artifacts reduce rollback time during incidents.
Those are big-company examples, but the same mechanics apply on a Raspberry Pi: fewer snowflake dependencies, clearer rollback, and state kept outside the container.
Start here (your first step)
Create ~/openclaw/docker-compose.yml with 127.0.0.1:18789:18789 and a persistent ./data mount.
Quick wins (immediate impact)
OPENCLAW_GATEWAY_TOKEN with openssl rand -hex 32, then restart with docker compose up -d.ss -lntp | grep 18789 and verify it binds to 127.0.0.1.Deep dive (for those who want more)
2026.1.3) and document your upgrade command sequence in a RUNBOOK.md.A Raspberry Pi can run OpenClaw reliably, but only if the gateway stays private, state lives on persistent storage, and upgrades are treated as a repeatable process. Docker Compose is the simplest way to get those properties without turning your Pi into a fragile snowflake.
Once the base stack is stable, add skills slowly and offload heavy work to other machines instead of forcing everything onto the Pi. Let's be real: a Pi that tries to do everything ends up doing nothing well.