This guide installs OpenClaw on Unraid using the official openclaw/openclaw:latest Docker Hub image. It gives you the built-in browser UI on port 18789, persistent configuration and authentication data under /mnt/user/appdata/openclaw, a separate CLI service for administration, and token-protected access.
The setup deliberately does not mount the host filesystem, Docker socket, or a privileged container. OpenClaw publishes official images on GHCR and Docker Hub; use openclaw/openclaw rather than an unofficial mirror. Its built-in Control UI covers chat, agent management, configuration, and execution approvals, so a separate frontend such as Open WebUI is unnecessary.
1. Install Docker Compose support
Unraid does not provide native Docker Compose stack management. The simplest option is Compose Manager Plus, available through Community Applications.
- Open Apps in Unraid.
- Search for Compose Manager Plus.
- Install the plugin.
- Confirm Docker Compose is available in the Unraid terminal:
docker compose version
You can manage the completed stack through Compose Manager Plus or directly from the terminal.
2. Create persistent directories
In the Unraid terminal, create OpenClaw’s persistent directories and set the required permissions:
mkdir -p /mnt/user/appdata/openclaw/config/workspace
mkdir -p /mnt/user/appdata/openclaw/auth-profile-secrets
chown -R 1000:1000 /mnt/user/appdata/openclaw
chmod 700 /mnt/user/appdata/openclaw/auth-profile-secrets
The official image runs as the node user with UID 1000, so its mounted directories must be writable by that UID. The resulting layout is:
/mnt/user/appdata/openclaw/
├── .env
├── compose.yml
├── config/
│ ├── openclaw.json
│ ├── agents/
│ └── workspace/
└── auth-profile-secrets/
OpenClaw stores its configuration, agent authentication profiles, workspace, and OAuth encryption key in these locations.
3. Generate the Gateway token
Generate a random token and write it to an environment file:
TOKEN="$(openssl rand -hex 32)"
cat > /mnt/user/appdata/openclaw/.env <<EOF
OPENCLAW_GATEWAY_TOKEN=${TOKEN}
OPENCLAW_TZ=Europe/London
EOF
chown 1000:1000 /mnt/user/appdata/openclaw/.env
chmod 600 /mnt/user/appdata/openclaw/.env
Retrieve the token when needed:
grep '^OPENCLAW_GATEWAY_TOKEN=' /mnt/user/appdata/openclaw/.env | cut -d= -f2-
Keep this token private: it grants administrative access to OpenClaw.
4. Create the Docker Compose file
Create /mnt/user/appdata/openclaw/compose.yml with the following content:
name: openclaw
services:
openclaw-gateway:
image: openclaw/openclaw:latest
container_name: openclaw
restart: unless-stopped
init: true
env_file:
- /mnt/user/appdata/openclaw/.env
environment:
HOME: /home/node
OPENCLAW_HOME: /home/node
TERM: xterm-256color
TZ: Europe/London
OPENCLAW_STATE_DIR: /home/node/.openclaw
OPENCLAW_CONFIG_PATH: /home/node/.openclaw/openclaw.json
OPENCLAW_CONFIG_DIR: /home/node/.openclaw
OPENCLAW_WORKSPACE_DIR: /home/node/.openclaw/workspace
# Docker bridge networking does not reliably carry mDNS.
OPENCLAW_DISABLE_BONJOUR: "1"
command:
- node
- dist/index.js
- gateway
- --bind
- lan
- --port
- "18789"
ports:
- "18789:18789"
volumes:
- /mnt/user/appdata/openclaw/config:/home/node/.openclaw
- /mnt/user/appdata/openclaw/config/workspace:/home/node/.openclaw/workspace
- /mnt/user/appdata/openclaw/auth-profile-secrets:/home/node/.config/openclaw
extra_hosts:
- "host.docker.internal:host-gateway"
cap_drop:
- NET_RAW
- NET_ADMIN
security_opt:
- no-new-privileges:true
healthcheck:
test:
- CMD
- node
- -e
- >
fetch('http://127.0.0.1:18789/healthz')
.then((response) => process.exit(response.ok ? 0 : 1))
.catch(() => process.exit(1))
interval: 30s
timeout: 5s
retries: 5
start_period: 20s
openclaw-cli:
image: openclaw/openclaw:latest
profiles:
- cli
network_mode: "service:openclaw-gateway"
env_file:
- /mnt/user/appdata/openclaw/.env
environment:
HOME: /home/node
OPENCLAW_HOME: /home/node
TERM: xterm-256color
TZ: Europe/London
OPENCLAW_STATE_DIR: /home/node/.openclaw
OPENCLAW_CONFIG_PATH: /home/node/.openclaw/openclaw.json
OPENCLAW_CONFIG_DIR: /home/node/.openclaw
OPENCLAW_WORKSPACE_DIR: /home/node/.openclaw/workspace
BROWSER: echo
volumes:
- /mnt/user/appdata/openclaw/config:/home/node/.openclaw
- /mnt/user/appdata/openclaw/config/workspace:/home/node/.openclaw/workspace
- /mnt/user/appdata/openclaw/auth-profile-secrets:/home/node/.config/openclaw
cap_drop:
- NET_RAW
- NET_ADMIN
security_opt:
- no-new-privileges:true
stdin_open: true
tty: true
init: true
entrypoint:
- node
- dist/index.js
depends_on:
- openclaw-gateway
This follows the official OpenClaw Compose arrangement: a Gateway container plus a CLI service that shares its network and persistent directories. Only port 18789 is published; the separate bridge port is not required for basic dashboard and WebChat use.
5. Pull the image
cd /mnt/user/appdata/openclaw
docker compose pull
docker image inspect openclaw/openclaw:latest --format '{{.RepoTags}}'
6. Run the onboarding wizard
Before running the Gateway permanently, complete OpenClaw’s interactive onboarding:
cd /mnt/user/appdata/openclaw
docker compose run --rm --no-deps --entrypoint node openclaw-gateway \
dist/index.js onboard --mode local --no-install-daemon
During onboarding:
- Select your model provider.
- Enter its API key or complete its supported authentication flow.
- Choose a default model.
- Create the main agent and workspace.
- Skip messaging channels initially.
- Skip daemon installation because Docker handles startup.
The onboarding process configures the provider, authentication, Gateway, and initial agent. A standard provider API key is generally the least complicated authentication method in Docker.
7. Allow the Unraid UI address
OpenClaw checks the browser origin accessing its Control UI. Set your actual Unraid IP address and hostname before applying the configuration:
UNRAID_IP="192.168.1.50"
UNRAID_HOST="orion"
Replace these values as necessary, then run:
docker compose run --rm --no-deps --entrypoint node openclaw-gateway \
dist/index.js config set --batch-json "[
{\"path\":\"gateway.mode\",\"value\":\"local\"},
{\"path\":\"gateway.bind\",\"value\":\"lan\"},
{\"path\":\"gateway.controlUi.allowedOrigins\",\"value\":[
\"http://${UNRAID_IP}:18789\",
\"http://${UNRAID_HOST}:18789\",
\"http://localhost:18789\",
\"http://127.0.0.1:18789\"
]}
]"
Inspect the generated configuration if needed:
cat /mnt/user/appdata/openclaw/config/openclaw.json
This sets the Gateway to local mode, binds it to the LAN interface, and explicitly lists the Control UI origins.
8. Start OpenClaw
cd /mnt/user/appdata/openclaw
docker compose up -d openclaw-gateway
docker compose ps
docker compose logs -f openclaw-gateway
Use Ctrl + C to leave the log view; the container continues running. Test the health endpoint:
curl http://127.0.0.1:18789/healthz
9. Open the browser UI
Open http://192.168.1.50:18789, or http://orion:18789 when local DNS resolves the Unraid hostname. When prompted for authentication, retrieve the token:
grep '^OPENCLAW_GATEWAY_TOKEN=' /mnt/user/appdata/openclaw/.env | cut -d= -f2-
Paste it into the OpenClaw Control UI settings, then open WebChat and send a test message. OpenClaw applies authentication during the dashboard WebSocket connection. The token remains in browser session storage for the current tab, rather than permanently in local storage.
10. Test the CLI
cd /mnt/user/appdata/openclaw
docker compose run --rm openclaw-cli gateway probe
docker compose run --rm openclaw-cli models list
docker compose run --rm openclaw-cli agent \
--message "Reply with: OpenClaw is running on Unraid."
docker compose run --rm openclaw-cli doctor
11. Add a messaging channel later
Once WebChat works, add and test channels one at a time.
Telegram
docker compose run --rm openclaw-cli channels add \
--channel telegram --token "YOUR_TELEGRAM_BOT_TOKEN"
Discord
docker compose run --rm openclaw-cli channels add \
--channel discord --token "YOUR_DISCORD_BOT_TOKEN"
docker compose run --rm openclaw-cli channels login
The WhatsApp command presents a pairing flow. OpenClaw also supports Telegram, Discord, Slack, Signal, Microsoft Teams, and WebChat. Test a channel’s pairing and sender restrictions before moving on to another.
12. Update OpenClaw
cd /mnt/user/appdata/openclaw
docker compose pull
docker compose up -d openclaw-gateway
docker image prune
docker compose logs --tail=100 openclaw-gateway
OpenClaw runs supported state and configuration migrations when a newer image starts against an existing persistent configuration directory. For a more controlled deployment, replace openclaw/openclaw:latest with a tested version tag such as openclaw/openclaw:2026.x.x in both services. They must use the same image version.
13. Back up persistent state
Back up both of these directories:
/mnt/user/appdata/openclaw/config
/mnt/user/appdata/openclaw/auth-profile-secrets
The second contains the encryption material associated with stored OAuth authentication profiles. Losing it can make persisted provider credentials unusable. A basic manual backup is:
mkdir -p /mnt/user/backups/openclaw
tar -czf "/mnt/user/backups/openclaw/openclaw-$(date +%F).tar.gz" \
-C /mnt/user/appdata openclaw
14. Security recommendations
The Control UI is an administrative interface with chat, configuration, and execution-approval abilities. Do not expose it directly to the public internet.
- Do not forward port
18789through your router. - Do not expose it through Cloudflare Tunnel without an identity-aware access layer.
- Do not mount
/mnt/user,/boot, or other broad host paths into the container. - Do not mount
/var/run/docker.sock. - Keep the Gateway token out of screenshots, logs, and Git repositories.
- Review third-party skills before installing them.
- Start with low-risk, read-only integrations.
- Use Tailscale or an SSH tunnel for remote administration.
- Keep message-channel pairing enabled instead of accepting unrestricted inbound messages.
OpenClaw’s default direct-message policy pairs unknown senders rather than immediately processing their requests.
Troubleshooting
Permission denied or EACCES
chown -R 1000:1000 /mnt/user/appdata/openclaw
chmod 700 /mnt/user/appdata/openclaw/auth-profile-secrets
docker compose restart openclaw-gateway
The container runs as UID 1000, which is the usual cause of appdata permission errors.
The UI reports an invalid or rejected origin
Check the exact URL in your browser, for example http://192.168.1.50:18789. Its scheme, hostname, and port must appear in gateway.controlUi.allowedOrigins. Re-run step 7 with the correct values.
The UI opens but authentication fails
Confirm that the container received the token:
docker exec openclaw printenv OPENCLAW_GATEWAY_TOKEN
grep OPENCLAW_GATEWAY_TOKEN /mnt/user/appdata/openclaw/.env
docker compose restart openclaw-gateway
The container keeps restarting
Inspect the logs, then run the repair command using the same persistent mounts:
docker compose logs --tail=200 openclaw-gateway
docker compose run --rm --no-deps --entrypoint node openclaw-gateway \
dist/index.js doctor --fix
docker compose up -d openclaw-gateway
The official upgrade guidance recommends doctor --fix against the same mounted state when a startup migration cannot safely complete.
The Gateway is healthy but the model does not respond
docker compose run --rm openclaw-cli models list
docker compose run --rm openclaw-cli doctor
docker compose logs --tail=200 openclaw-gateway
Then return to the Control UI and confirm the default agent has a valid provider and model selected.
Finished result
You should now have:
- OpenClaw Control UI:
http://UNRAID-IP:18789 - Container:
openclaw - Persistent data:
/mnt/user/appdata/openclaw - Docker image:
openclaw/openclaw:latest
Use the built-in WebChat for initial testing. Add messaging channels and skills only after the base agent, provider, and workspace operate reliably.