A thin, security-focused wrapper around the official OpenClaw
Docker setup. docker-compose.yml is byte-identical to upstream; all deviations
live in docker-compose.override.yml (auto-generated) and .env.
Two real security deltas vs. upstream, plus a setup wizard.
| Change | Where | Why it matters |
|---|---|---|
Host port bound to 127.0.0.1 |
docker-compose.override.yml |
Upstream binds gateway ports to 0.0.0.0, exposing the Web UI and bot tokens to your entire LAN / Wi-Fi / public IP. This restricts the attack surface to local processes on the host. |
| Telegram bot tokens via Docker secrets | secrets/ + override |
Upstream has no example, so most users paste raw tokens into openclaw.json or env vars where docker inspect, env dumps, and backups will leak them. Docker secrets keep tokens in a tmpfs mount, absent from image layers and inspect output. |
manage.py wizard |
— | Convenience: tokens, gateway token, ports, channel registration, backup/restore in one pass. No security value, just less foot-gun. |
Everything else (container_name, .env defaults, etc.) is convenience or bug-fix only.
git clone https://github.com/rightson/openclaw-hardened.git
cd openclaw-hardened
./manage.pyThe wizard creates .env, generates docker-compose.override.yml, mounts your
bot secrets, and starts the container. Then open the dashboard:
http://127.0.0.1:18789/
./manage.py # interactive setup wizard
./manage.py status # container + gateway health
./manage.py start | stop # control gateway
./manage.py backup [--dry-run] # snapshot ./data → backup-dir
./manage.py restore <file.tar.gz> # restore snapshot
./manage.py sync-upstream # diff/pull upstream docker-compose.yml
./manage.py config show # print current configdocker-compose.yml ← verbatim upstream, do not edit
docker-compose.override.yml ← all deviations (gitignored, generated)
.env ← gateway token + ports + paths (gitignored)
.env.example ← template
secrets/telegram-*.token ← bot tokens, mode 600 (gitignored)
data/ ← container state (gitignored)
manage.py ← wizard / start / backup / restore
specs/ ← spec-driven dev notes
Upstream maps both 18789 (gateway/UI) and 18790 (reserved). The Web UI
actually serves on 18789 because the compose command: passes
--port 18789; the upstream default config still references 18790 in a few
places, which is a known upstream inconsistency. The wizard normalises
gateway.controlUi.allowedOrigins to match.
echo '{"botToken":"NEW_TOKEN"}' > secrets/telegram-<name>.token
docker compose restart openclaw-gatewayLoopback binding + Docker secrets give you defense against:
- External network reach: blocked by
127.0.0.1:port mapping - Token leak via inspect / env / backup: blocked by Docker secrets
They do not protect against:
- A compromised process inside the gateway container reading mounted volumes
(
./data,./data/workspace) or attacking other containers on the same Docker bridge. Seespecs/security-hardening.mdfor proposals (cap_drop on gateway, read-only rootfs, workspace as named volume, egress restriction).
specs/align-with-official-compose.md— how this repo stays in sync with upstreamspecs/security-hardening.md— further hardening proposals (draft)