Onepagecode

Onepagecode

OpenClaw Installation, Hosting, Containers, and Maintenance Guide

A practical OpenClaw operations guide covering local install, VPS hosting, Docker and Podman runtimes, automation, updates, backups, migration, and safe uninstall.

Onepagecode's avatar
Onepagecode
May 07, 2026
∙ Paid

Download the Entire book on “Technical Guide to OpenClaw” Using the button at the end of this article!

Quickstart: One-line Install and First Checks

Start by running a single command that installs the OpenClaw CLI, ensures a suitable Node runtime is present (if needed), and—by default—launches the interactive onboarding flow that seeds your workspace and optionally installs the Gateway daemon.

On macOS, Linux, or WSL2 you can fetch and run the installer with curl and bash:

curl -fsSL https://openclaw.ai/install.sh | bash

On Windows use the PowerShell one-liner:

iwr -useb https://openclaw.ai/install.ps1 | iex

If you are automating installs or provisioning servers and do not want the interactive onboarding step to run, pass the --no-onboard flag to the installer. Example (Unix-like):

curl -fsSL https://openclaw.ai/install.sh | bash -s -- --no-onboard

PowerShell equivalent (unattended):

& ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -NoOnboard

Warning: piping remote scripts directly into a shell is convenient but risky. Verify the script source (HTTPS, expected host, checksum or fetch the file and inspect it) before running on production systems.

When to use the local-prefix installer If you prefer a per-user installation that does not rely on system-wide Node or global package hooks, use the local-prefix installer which installs both Node and OpenClaw under a local prefix (commonly ~/.openclaw). This is useful on shared servers or when you lack root privileges.

Run the local-prefix installer like this:

curl -fsSL https://openclaw.ai/install-cli.sh | bash

Alternative global installs If you manage Node and global packages yourself, you can install the CLI through standard package managers. Example with npm:

npm install -g openclaw@latest
openclaw onboard --install-daemon

bun also supports global CLI installation. Note: bun can install the CLI, but Node is still the recommended runtime for the Gateway daemon and for most integrations.

bun add -g openclaw@latest
openclaw onboard --install-daemon

After install: verification and basic health checks Confirm the CLI is available and run basic diagnostics:

openclaw --version # confirm the CLI is available
openclaw doctor # check for config issues
openclaw gateway status # verify the Gateway is running

If you used the installer without --no-onboard, the onboarding flow will guide you to create a workspace, configure providers, and optionally install the Gateway as a daemon. To explicitly install the Gateway service after onboarding (or from an already-configured machine), run:

  • interactive onboarding that also installs a daemon:

openclaw onboard --install-daemon

  • or install the service directly:

openclaw gateway install

These commands create a platform-appropriate service:

  • macOS: LaunchAgent (per-user)

  • Linux/WSL2: systemd user service

  • Windows: Scheduled Task

Node runtime requirement and quick check OpenClaw requires Node 22.14 or newer. Node 24 is the recommended runtime for installs, CI, and production. If you manage Node yourself, verify your installed version:

node -v

If this prints v24.x.x you’re on the recommended default. v22.14.x or higher is supported, but upgrading to Node 24 is recommended when convenient. The installer will detect and install Node for you when possible—use the installer unless you have a specific reason to manage Node manually.

VPS deployment OpenClaw can be deployed on any standard Linux VPS. The quick pattern is:

  • Provision a VPS (Ubuntu 24.04 recommended).

  • Run the same installer command on the VPS (use --no-onboard for fully automated image builds).

  • Optionally configure the Gateway to remain loopback-only and use an SSH tunnel or Tailscale for remote access.

Behavior notes and edge cases

  • If you run the installer from inside an OpenClaw source checkout (package.json + pnpm-workspace.yaml present), the installer may offer to use the local checkout for the CLI instead of downloading a release. This behaviour can differ in non-interactive shells; use --no-onboard and explicit flags for predictable automation.

  • If the install completes but the openclaw command is not found in a new terminal, the most common cause is PATH not including your global npm/bun/pnpm bin directory or the local-prefix bin path. Consult the Node troubleshooting section (node version / npm prefix -g path) and ensure (npm prefix -g)/bin or your local-prefix/bin is on PATH.

When installation fails: quick troubleshooting checklist

  • Confirm network access to https://openclaw.ai and that curl/iwr succeed.

  • Check node -v. If Node is absent or too old, either allow the installer to provision Node or install Node 24 manually.

  • Verify your package manager global bin directory is on PATH (npm prefix -g)/bin or bun/pnpm global bin.

  • On systems that fail native Sharp/libvips builds, set SHARPIGNOREGLOBAL_LIBVIPS=1 during the install or consult the platform Sharp troubleshooting steps.

This quickstart gets you to a usable CLI and basic Gateway service. The next pages show scripted installer flags for CI, deeper Node installation guidance, and platform-specific daemon controls.

Installer Scripts: install.sh, install-cli.sh, and install.ps1

Choose the installer that matches your environment and goals: the interactive, full-featured installer for typical laptops and servers; a local-prefix installer for per-user or containerized installs without root; or the PowerShell installer for Windows hosts. Each script can install Node (Node 24 recommended; Node 22.14+ supported), install or update Git, and install OpenClaw either via npm or by checking out the repository and building from source.

The three official installer entry points

  • install.sh — the macOS / Linux / WSL installer. Recommended for interactive installs. It auto-detects OS, verifies or installs Node, and on macOS will install Homebrew if Homebrew is missing and required tools are absent.

  • install-cli.sh — a local-prefix installer for macOS / Linux / WSL. Intended to install OpenClaw (and Node if needed) under a user-writable prefix (for example ~/.openclaw or /opt/openclaw) so no root privileges are required.

  • install.ps1 — the Windows PowerShell installer. Can be invoked interactively or scripted; installs Node if needed and supports npm- or git-based installation and onboarding flows.

Security and safety note Piping a remote script directly to a shell or invoking remote PowerShell with iex executes network-fetched code on your host. This is convenient but carries risk. Inspect with --help or fetch the script to disk and review before executing if you require assurance.

Quick examples — download-and-run (curl + bash) The following are runnable shell invocations showing typical installer usages. Use the --help forms below to inspect behavior before making changes.

Run the recommended interactive installer:

curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash

Print usage/help for install.sh without running it:

curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --help

Run the local-prefix installer:

curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install-cli.sh | bash

Print help for the local-prefix installer:

curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install-cli.sh | bash -s -- --help

PowerShell invocation patterns (Windows) Simple remote invocation with built-in downloader (convenient but inspect first):

iwr -useb https://openclaw.ai/install.ps1 | iex

A safer pattern that forwards parameters and executes as a scriptblock:

& ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -Tag beta -NoOnboard -DryRun

Interactive vs automation-friendly flags Installers accept a common set of flags and environment variables to control behavior. Grouped by purpose:

  • Interactive-control and method:

  • --install-method / -InstallMethod: choose between npm (default) or git.

  • --version / -Tag: select a version/tag/ref (e.g., main, latest, or a release tag).

  • --onboard / --no-onboard: run or skip the post-install onboarding prompt.

  • Automation and inspection:

  • --dry-run / -DryRun: print planned actions and exit without making changes.

  • --json: emit machine-readable JSON suitable for CI parsing.

  • --no-prompt or environment OPENCLAWNOPROMPT=1: run non-interactively.

  • Local-prefix / location control:

  • --prefix / --prefix path: (install-cli.sh) install into a specific user-writable prefix such as ~/.openclaw or /opt/openclaw.

  • --git-dir / -GitDir: when using git install method, control where the repository will be checked out.

Examples that illustrate these flags Disable interactive onboarding:

curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --no-onboard

Select git-based install method:

curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --install-method git

Select a specific ref (git tag or branch) for a git install:

curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --version main

Dry-run to review actions first:

curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --dry-run

Install into a system path (requires writable prefix) or to a managed location:

curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install-cli.sh | bash -s -- --prefix /opt/openclaw --version latest

Git-based local-prefix with custom checkout location:

curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install-cli.sh | bash -s -- --install-method git --git-dir ~/openclaw

Request JSON output for automation:

curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install-cli.sh | bash -s -- --json --prefix /opt/openclaw

How installers perform the install

  • install.sh installs system tools (Git) if missing, ensures Node of at least the supported version is present (preferring Node 24), and then installs OpenClaw either via npm global install or by cloning the repository and running the build (pnpm install / pnpm build), placing a wrapper CLI under a user-local bin when necessary.

  • install-cli.sh avoids system-wide changes by installing Node and OpenClaw under a given prefix. This is the preferred choice on shared systems, containers, or when you want per-user isolation. Ensure the chosen prefix is writable; using /opt/openclaw requires root or suitable directory permissions.

  • install.ps1 behaves similarly on Windows: it can install Node, perform npm or git installs, and take the same high-level flags (Tag, InstallMethod, GitDir, NoOnboard, DryRun).

Post-install and verification steps After installation the script attempts a best-effort gateway service refresh: it will try openclaw gateway install --force and then restart the gateway where appropriate. On upgrades or git installs the installer runs openclaw doctor --non-interactive to surface common fixes. For systems with image-processing libraries, the installer defaults to SHARPIGNOREGLOBAL_LIBVIPS=1; if you have a system libvips and want to force use of it, you can override that environment variable when invoking the installer.

Summary guidance

  • For an interactive laptop or straightforward server, start with install.sh.

  • For CI, containers, or single-user isolation, prefer install-cli.sh with --prefix and --json/--dry-run for automation.

  • For Windows, use install.ps1 and pass named parameters or use the scriptblock form for safer argument forwarding.

  • Always inspect the script with --help or fetch and review before piping to a shell, and include --dry-run / --json in automated flows so your tooling can validate planned actions before commit.

Package Managers and Building from Source

When you prefer a package manager or want to build from source instead of using the interactive installer, you have four practical choices: global package installs with npm/pnpm/bun, a per-user local-prefix install, cloning and building the repository, or installing directly from GitHub. Each option trades convenience, upgrade semantics, and required privileges.

Global installs (npm / pnpm / bun)

  • Use a global install when you want the simplest upgrade path for the CLI and you trust the published package channel. A global npm/pnpm/bun install places the openclaw binary on your system PATH (subject to your package manager’s global prefix). Be aware that installing a global CLI usually requires either a privileged shell or a properly configured user-global prefix.

  • Node is the recommended runtime for the Gateway daemon. bun can be used to install the CLI globally, but the Gateway daemon itself should run on Node (recommended Node 24; Node 22 LTS supported).

Runnable examples for a global install and immediate onboarding:

npm install -g openclaw@latest
openclaw onboard --install-daemon

If you use pnpm, note an important safety step: pnpm requires explicit approval when packages include build scripts. After your first pnpm global install run, approve build scripts globally so future installs and rebuilds proceed cleanly:

pnpm add -g openclaw@latest
pnpm approve-builds -g
openclaw onboard --install-daemon

bun users can install and then onboard similarly:

bun add -g openclaw@latest
openclaw onboard --install-daemon

Local-prefix and installer script modes

  • If you want to avoid system-level installs, the project provides a local-prefix installer (install-cli.sh) that keeps OpenClaw and Node under a user-local prefix (typically under ~/.local or the prefix you specify). The interactive install.sh auto-detects OS/WSL and can install Node and Git if missing. install.sh supports two install methods for the CLI: npm (global npm install) or git (clone + pnpm build). The PowerShell installer (install.ps1) performs equivalent tasks on Windows.

Building from source (developer workflow)

  • Clone, build, and link the CLI when you want to modify code or run a development build. This sequence installs dependencies, builds the server and UI, and then makes your checkout available as a global command via pnpm link:

git clone https://github.com/openclaw/openclaw.git
cd openclaw
pnpm install && pnpm build && pnpm ui:build
pnpm link --global
openclaw onboard --install-daemon
  • Using the git+pnpm flow ensures reproducible builds; it’s the recommended path for contributors.

Install directly from GitHub

  • For a quick test of the main branch without cloning, npm supports installing from GitHub:

npm install -g github:openclaw/openclaw#main

sharp / libvips build failure workaround

  • If a global libvips installation interferes with sharp’s native build during a global npm install, set SHARPIGNOREGLOBAL_LIBVIPS=1 to force sharp to build its bundled libvips:

SHARP_IGNORE_GLOBAL_LIBVIPS=1 npm install -g openclaw@latest

Use this only when you see sharp-related build failures.

Privileges and PATH notes

  • Global installs require that your package manager’s global bin directory is on PATH. For npm, ensure (npm prefix -g)/bin is visible to your shell. If you prefer no sudo, use a per-user npm prefix or the local-prefix installer. After any install, verify with openclaw --version and run openclaw doctor to validate the environment.

Choose the method that matches your needs: global npm/pnpm/bun for operators seeking quick upgrades, local-prefix or installer scripts for per-user isolation, and git builds for development and contribution. Remember pnpm’s approve-builds step and the SHARPIGNOREGLOBAL_LIBVIPS workaround if native builds fail.

Node.js: Recommended Versions and Installation Options

OpenClaw requires a modern Node runtime: Node 22.14 or newer is supported, and Node 24 is the recommended default for installs, CI, and releases. The installer scripts will detect and install Node for you, but when you prefer to manage Node yourself (system-wide or per-user), follow the options below so the OpenClaw CLI and daemon run on a supported runtime.

Quick version check Run this to see the active Node runtime:

node -v

If this prints v24.x.x you’re on the recommended runtime. v22.14.x or later is supported, but upgrading to Node 24 is advised when convenient.

System installs (fast, production-friendly)

  • macOS (Homebrew):

brew install node

Homebrew typically installs a recent LTS. Prefer system package installs for production servers or CI where you want a single global Node.

  • Debian/Ubuntu (NodeSource recipe for Node 24):

curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
sudo apt-get install -y nodejs
  • Fedora/RHEL (dnf):

sudo dnf install nodejs
  • Windows (winget / Chocolatey):

winget install OpenJS.NodeJS.LTS

or

choco install nodejs-lts

Per-user version managers (development and test) Using a version manager gives reproducible per-project runtimes without touching system packages. Example with fnm:

fnm install 24
fnm use 24

You can use fnm, nvm, volta, or similar tools. For CI and production, prefer either system-managed Node 24 or an image baked with Node 24 to match downstream release expectations.

Why Node 24 matters

  • Consistency: build tools and native modules are tested against Node 24 in release pipelines.

  • Long-term support: Node 22 is supported but will diverge in tooling and native binary compatibility over time.

If you must remain on Node 22.14+ for policy reasons, OpenClaw is compatible, but validate native dependencies (sharp, native addons) after install.

PATH and global CLI discovery When installing the openclaw CLI globally, ensure your global npm/pnpm prefix bin directory is on PATH. Check your node global bin location and PATH if the openclaw command isn’t found:

  • Find global bin (example):

  • npm: npm prefix -g (then /bin)

  • pnpm: pnpm bin -g

If a global install doesn’t expose openclaw, add the global bin directory to your PATH before continuing.

If you prefer automated setup, use the provided installer script — it auto-detects OS and Node, and will install Node 24 by default. Use the manual commands above only when you want explicit control over Node provisioning.

Verifying the Installation and Installing the Gateway Daemon

Before you let OpenClaw run as a persistent service, confirm the CLI works and that the Gateway can be installed or refreshed cleanly. A quick verification sequence saves time when onboarding or debugging daemon startup.

Start by confirming the CLI and basic runtime health. Run these three commands from a shell to check the binary, run the built-in diagnostics, and query the Gateway status:

openclaw --version # confirm the CLI is available
openclaw doctor # check for config issues
openclaw gateway status # verify the Gateway is running

If the CLI responds but the Gateway is not installed or not running, you can request the installer to create and enable the platform-appropriate service for you. Two entry points are common:

  • Use the interactive onboarding flow and ask it to install the daemon:

npm install -g openclaw@latest
openclaw onboard --install-daemon

This pattern installs the CLI (npm shown; pnpm or bun are alternatives below) and then runs the onboarding procedure which can create the service and perform initial workspace and provider setup.

  • Alternatively install the CLI by other package managers then explicitly install the Gateway service:

pnpm add -g openclaw@latest
pnpm approve-builds -g
openclaw onboard --install-daemon

Note: pnpm requires running pnpm approve-builds -g once after installs that include package build scripts.

Bun supports global CLI installs, but it is a CLI-only option: use bun if you only need the openclaw command locally. The Gateway runtime itself is recommended to run on Node (Node 24 recommended; Node 22 LTS supported). If you prefer bun for the CLI:

bun add -g openclaw@latest
openclaw onboard --install-daemon

For development or source installs, clone, build, and link the checkout:

git clone https://github.com/openclaw/openclaw.git
cd openclaw
pnpm install && pnpm build && pnpm ui:build
pnpm link --global
openclaw onboard --install-daemon

What installer creates on each platform

  • macOS: LaunchAgent (per-user) so the Gateway starts when the user logs in.

  • Linux / WSL2: systemd user service (runs under your user, not root).

  • Windows (native): Scheduled Task to start on login.

Post-install and troubleshooting checklist

  • If the service looks stale, run a best-effort refresh:

  • openclaw gateway install --force && openclaw gateway restart

  • After source or upgrade installs run:

  • openclaw doctor --non-interactive

This flags configuration drift and missing dependencies without interactive prompts.

  • If image-processing packages fail at runtime, set:

  • SHARPIGNOREGLOBAL_LIBVIPS=1

This forces Sharp to use its bundled libvips rather than a problematic global install.

Warnings and operational notes

  • Installing the CLI with bun is supported, but do not assume the Gateway will run well under bun. Use Node for the daemon.

  • When using pnpm globally, remember the approve-builds step; skipping it can leave the CLI unusable.

  • For headless VPS or CI automation, prefer the non-interactive doctor checks and explicit openclaw gateway install flows rather than relying on the onboarding UI.

These steps get you from a working CLI to a managed Gateway service. If the Gateway still fails to start, gather logs and run openclaw doctor and the gateway status probe as the first troubleshooting signals.

Troubleshooting: Missing CLI, PATH, and Uninstall Hints

Many “openclaw not found” problems trace to Node or the npm global bin directory not being on your shell PATH. OpenClaw requires Node 22.14+; Node 24 is recommended. The installer can install Node for you, but when you set up Node yourself you should verify the runtime and where npm places global executables.

Start with these diagnostics in a shell to confirm Node, the global npm prefix, and your PATH:

node -v # Node installed?
npm prefix -g # Where are global packages?
echo "$PATH" # Is the global bin dir in PATH?

If node -v reports a version older than v22.14 (or prints “command not found”), install a supported Node runtime (Node 24 recommended) via your system package manager, nvm, or the installer script. The installer script will detect and install Node automatically if you run it; run the installer only if you want that convenience.

Common failure mode: (npm prefix -g)/bin not in your $PATH. The npm prefix -g command prints the directory where global packages (and their executables) are installed. If you install OpenClaw with npm/pnpm globally, the openclaw CLI executable is placed in $(npm prefix -g)/bin. If that bin directory is not in your PATH, the shell cannot find openclaw.

Quick temporary fix (effective immediately in current shell):

export PATH="$(npm prefix -g)/bin:$PATH"

Persistent fixes — choose one:

  • Add the export to your shell startup file (~/.bashrc, ~/.bash_profile, ~/.zshrc, or the file your shell sources). After editing, either open a new terminal or source the file (source ~/.bashrc).

  • Configure a per-user npm prefix and place its bin on PATH (recommended if you want global npm packages without sudo). Create a local prefix, set npm to use it, and update PATH:

mkdir -p "$HOME/.npm-global"
npm config set prefix "$HOME/.npm-global"
export PATH="$HOME/.npm-global/bin:$PATH"

Add that export to your shell startup file to make it persistent.

A few operational notes and warnings:

  • After changing PATH in a startup file you must start a new shell session or run source ~/.profile (or the correct file) for the change to take effect.

  • If you used a system package manager to install Node, prefer the system’s global npm prefix; mixing multiple Node installers can produce conflicting prefixes.

  • If openclaw still fails after fixing PATH, re-run node -v and npm prefix -g to confirm you’re using the expected Node installation and prefix in the same shell where you try to run openclaw.

If you want to remove the global CLI later, uninstall with your package manager or npm/pnpm uninstall -g openclaw; ensure you back up any runtime state under ~/.openclaw before performing destructive uninstall or reset operations.

Hosting OpenClaw: Decision Framework and Deployment Recipes

Hosting choices and trade-offs

Deciding where to host OpenClaw comes down to five operational trade-offs: statefulness, exposure surface, concurrency/ram, platform-specific channels, and your capacity to maintain the machine. Treat the host you pick as the source of truth: the Gateway owns runtime state and workspace under ~/.openclaw, so whichever machine runs the gateway must be backed up and treated as stateful.

Checklist to pick a target

  • Stateful vs stateless: if you need persistent sessions, plugins, or local workspaces prefer a VPS, VM, or a persistent volume on PaaS. Containers without a host volume are ephemeral.

  • Expected concurrency / memory: plan >=2 GB for general-purpose gateway workloads; small 1 GB instances need swap or will OOM on heavy runs.

  • Channel requirements: macOS-required channels (iMessage) force a macOS VM or companion node.

  • Exposure model: prefer loopback + SSH/Tailscale by default; only open a public port when you can enforce TLS and a gateway token/password.

  • Maintenance capacity: managed platforms reduce operational burden but may impose limitations (persistent disk, cold-starts, cost).

The recurring pattern: loopback binding + secure remote access Keep the gateway loopback-only on the host and use ssh -L or Tailscale Serve to reach the Control UI. This avoids accidental public exposure and preserves WebSocket semantics. If you intentionally bind to LAN/public, enable gateway.auth (token or password) and terminate TLS at a reverse proxy or managed front end.

VPS / Linux server (general guidance) The Gateway runs on the VPS and owns state and workspace — back it up regularly. Use Ubuntu 24.04 LTS on droplets/VMs; avoid unreviewed marketplace images. Example: enumerate Canonical images with az before provisioning:

az vm image list \
 --publisher Canonical --offer ubuntu-24_04-lts \
 --sku server --all -o table

On initial connection to a fresh Droplet, update packages, install Node 24 and OpenClaw, and run onboarding:

ssh root@YOUR_DROPLET_IP

apt update && apt upgrade -y

## Install Node.js 24
curl -fsSL https://deb.nodesource.com/setup_24.x | bash -
apt install -y nodejs

## Install OpenClaw
curl -fsSL https://openclaw.ai/install.sh | bash
openclaw --version

If you use tiny 1 GB droplets, add swap to avoid OOMs:

fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab

Docker VM runtime: bake binaries, persist state Rule: bake required external binaries into the Docker image at build time; installing them at container runtime is lost on restart. All long-lived OpenClaw state must live on the host (e.g., /root/.openclaw). Use host-mounted volumes and set ownership for container user. Build and run images with compose:

docker compose build
docker compose up -d openclaw-gateway

Verify baked binaries inside the container:

docker compose exec openclaw-gateway which gog
docker compose exec openclaw-gateway which goplaces
docker compose exec openclaw-gateway which wacli

Expected output example:

/usr/local/bin/gog
/usr/local/bin/goplaces
/usr/local/bin/wacli

DigitalOcean / Hetzner / Hostinger patterns For DigitalOcean start from Ubuntu 24.04, install Node 24 and OpenClaw (see the SSH block above), run openclaw onboard --install-daemon to set up the systemd user service:

openclaw onboard --install-daemon

Hetzner and Hostinger follow the same Docker or systemd flow. Recommendation: Hetzner is a low-cost option—start small and scale up if you hit OOMs. Warning: on Hostinger, managed single-click handles updates; do not commit.env files with secrets.

Fly.io Fly is a common PaaS choice when you want automatic HTTPS and managed VMs. Goal: Gateway on Fly with a persistent volume mounted at /data and memory >= 2 GB. Quick steps (clone repo, create app, create volume):

git clone https://github.com/openclaw/openclaw.git
cd openclaw
fly apps create my-openclaw
fly volumes create openclaw_data --size 1 --region iad

Example fly.toml maps the mounted volume and process. Store secrets with fly secrets set (gateway token, provider keys). Never embed provider tokens in openclaw.json.

Kubernetes (minimal starter) The repo includes kustomize manifests and scripts for a minimal, non-production deployment. These helpers create a namespace, Secret with API keys, a PVC, and a ClusterIP Service. Use port-forward for local testing:

./scripts/k8s/deploy.sh
kubectl port-forward svc/openclaw 18789:18789 -n openclaw
open http://localhost:18789

Warning: the provided manifests are a starting point, not production-grade—handle TLS, pod security, and Secrets properly.

macOS VMs and BlueBubbles Use a macOS VM when you require macOS-only capabilities (iMessage) or stricter isolation. Lume helps create Apple Silicon VMs. Install OpenClaw in the VM, enable the daemon, and configure BlueBubbles (if used) to forward webhooks to the gateway. Rule: use a macOS VM rather than attempting to proxy iMessage from Linux.

Raspberry Pi / Oracle Always Free / Railway / Render specifics

  • Pi: Use Raspberry Pi OS Lite 64-bit, Node 24, add swap for 2 GB or less, prefer USB SSD over SD, and enable NODECOMPILECACHE to reduce CLI compile overhead:

`bash/text grep -q 'NODECOMPILECACHE=/var/tmp/openclaw-compile-cache' ~/.bashrc || cat >> ~/.bashrc <<'EOF' export NODECOMPILECACHE=/var/tmp/openclaw-compile-cache mkdir -p /var/tmp/openclaw-compile-cache export OPENCLAWNORESPAWN=1 EOF source ~/.bashrc


- Oracle Always Free ARM can host persistent Gateway instances; lock down VCN so only Tailscale or SSH can reach the host. If you hit capacity errors, try another AD.

- Railway: attach a persistent volume mounted at /data, set OPENCLAW_GATEWAY_PORT and OPENCLAW_GATEWAY_TOKEN, and enable the HTTP proxy (port mapping must match).

- Render: free plan spins down after 15 minutes and lacks persistent disk—use Starter+ with a persistent disk or lose state on idle.

Persistence, tokens, and backups
All long-lived state is under ~/.openclaw. Use openclaw backup create before destructive operations and store gateway tokens and provider keys in platform secrets (Fly secrets, Kubernetes Secrets, or host keyrings). Never commit.env files with secrets; generate random gateway tokens with openssl rand -hex 32.

Operational checks and quick troubleshooting
If the gateway won’t start, run openclaw doctor --non-interactive and inspect logs:

openclaw status systemctl --user status openclaw-gateway.service journalctl --user -u openclaw-gateway.service -f


Check port conflicts with lsof -i:18789. For containers, stream logs:

docker compose logs -f openclaw-gateway


If a Droplet appears to run out of memory, verify swap with free -h and consider increasing to 2 GB or upgrading the VM.

Final warnings and rules
- Keep the Gateway loopback-only and use SSH/Tailscale unless you can enforce TLS + gateway.auth.
- Bake external binaries into images at build time.
- Use macOS VMs when macOS-only channels are required.
- The helper manifests and scripts are minimal; harden before production.

These patterns let you choose the simplest secure path for your requirements: a small VPS for private team usage, Fly or Railway for managed HTTPS and fewer maintenance tasks, Kubernetes for centralized operations, and macOS VMs for platform-only channels.

## Secure exposure and remote access patterns (loopback, SSH tunneling, Tailscale, reverse proxies)

Your VM should not be the public-facing control plane. Keep the OpenClaw Gateway bound to localhost (127.0.0.1) on hosts whenever possible, and use a tunneling or trusted-proxy pattern to reach the Control UI. This reduces attack surface and forces explicit authentication (SSH key, Tailscale identity, or gateway token) before anyone can send WebSocket frames to the Gateway.

Decision flow (quick):
- Single-operator, ad-hoc access: keep gateway loopback-only and use an SSH local port forward from your laptop.
- Small private team: use Tailscale (Serve or tailnet bind) so team devices reach the mesh with identity-based access.
- Cloud-hosted production / publicly reachable web UIs: terminate TLS at a reverse proxy (nginx/Traefik) and enforce gateway token + firewall rules; prefer Bastion for SSH to avoid public VM SSH ports.

Keep the Gateway loopback-only and use SSH forwarding
Always prefer 127.0.0.1 binding on the host. That makes an SSH tunnel the simplest safe access method:

From your local machine; forwards remote 18789 → local 18789

ssh -L 18789:localhost:18789 root@YOURDROPLETIP


For GCP use gcloud's SSH wrapper with the same forwarding:

gcloud compute ssh openclaw-gateway --zone=us-central1-a -- -L 18789:127.0.0.1:18789


Azure Bastion: no public IP for VMs
Use Azure Bastion so VMs do not need public IP addresses. Create a Bastion resource in the VNet and restrict NSG rules so only the Bastion subnet can reach VM SSH. The NSG policy must include:
- Allow SSH from the Bastion subnet (priority 100).
- Deny SSH from the Internet (priority 110).
- Deny SSH from other VNet sources if you need isolation (priority 120).

Once Bastion and VM exist you can open an SSH session via Bastion using az network bastion ssh. This example uses your local private key:

VMID="$(az vm show -g "${RG}" -n "${VMNAME}" --query id -o tsv)"

az network bastion ssh \ --name "${BASTIONNAME}" \ --resource-group "${RG}" \ --target-resource-id "${VMID}" \ --auth-type ssh-key \ --username "${ADMINUSERNAME}" \ --ssh-key ~/.ssh/ided25519


Tailscale: private mesh and Serve
Tailscale is excellent for small teams and remote devices. Install and join the tailnet, then either Serve (Tailscale-managed HTTPS) or bind the gateway to the tailnet interface.

Install + Serve example (runnable shell):

curl -fsSL https://tailscale.com/install.sh | sh tailscale up openclaw config set gateway.tailscale.mode serve openclaw gateway restart


Or bind to Tailnet directly:

openclaw config set gateway.bind tailnet openclaw gateway restart


If you use Serve, traffic terminates at Tailscale and is proxied into 127.0.0.1:18789 — keep the Gateway loopback-only and require gateway token auth.

Reverse proxy and WebSocket forwarding (nginx)
When you must expose a public endpoint (exe.dev, Fly.io, or TLS-terminated proxy), configure the proxy to support WebSockets and long-lived connections. Overwrite forwarding headers instead of blindly appending client-supplied X-Forwarded-For values — this prevents header spoofing and preserves trusted-proxy semantics.

Example nginx server block (copy-paste safe):

server { listen 80 defaultserver; listen [::]:80 defaultserver; listen 8000; listen [::]:8000;

servername ;

location / { proxypass http://127.0.0.1:18789; proxyhttp_version 1.1;

WebSocket support

proxysetheader Upgrade $httpupgrade; proxyset_header Connection "upgrade";

Standard proxy headers

proxysetheader Host $host; proxysetheader X-Real-IP $remoteaddr; proxysetheader X-Forwarded-For $remoteaddr; proxysetheader X-Forwarded-Proto $scheme;

Timeout settings for long-lived connections

proxyreadtimeout 86400s; proxysendtimeout 86400s; } }


Hardening notes:
- Always keep the Gateway loopback-only on the host and use port forwarding, Tailscale Serve, or a trusted reverse proxy to expose it.
- When using a reverse proxy, set proxy_read_timeout to a large value because Gateway WebSocket sessions can be long-lived.
- Overwrite X-Forwarded-* headers at the proxy and configure the Gateway to trust only that proxy (avoid accepting arbitrary forwarded client headers).
- Public exposure requires gateway auth tokens and strict firewall rules.

Provider-specific pointers
- exe.dev / Fly.io: exe.dev automations or Fly apps commonly bake nginx and the OpenClaw install. When running via exe.dev, route port 8000/80 → 127.0.0.1:18789 in the VM and ensure nginx uses the WebSocket headers above. Secrets should be injected via provider secret stores, not baked into image layers.
- GCP: prefer loopback + gcloud SSH tunnel for initial runs. For automation, use a service account and instance templates; pick at least e2-small for Docker builds.
- DigitalOcean: on small droplets add a 1GB swap to avoid OOM during builds, and use SSH LocalForward or Tailscale for the Control UI.

Checklist before you open a public endpoint:
- Gateway bound to 127.0.0.1 or tailnet interface only.
- Reverse proxy configured with WebSocket headers and long timeouts.
- Firewall/NSG allows only trusted proxies and Bastion subnets to reach SSH.
- Gateway tokens rotated and stored securely; no credentials baked in container images.

## Persistence, state management, and update workflows

Persistent runtime state must survive container restarts, image rebuilds, and VM reboots. Treat the VM or host that runs the Gateway as the source of truth: map ~/.openclaw to a host-mounted volume, keep auth-profiles and openclaw.json on disk (not only in environment variables), and back up before any destructive operation.

Always persist under HOME/.openclaw
- Required: keep gateway config, auth-profiles.json, skill and workspace files, session transcripts, provider state (WhatsApp session, Gmail keyrings), and agent workspaces on host-mounted storage under /home/<user>/.openclaw (or /root/.openclaw if you run as root). This guarantees state survives image rebuilds, container replacement, and reboots.

Bake external binaries into images (Docker VM guidance)
- Do not fetch and install required system binaries at container runtime. If you install tools with apt/curl during container startup, the installed files disappear when the container is replaced. Bake them into the image at build time so they travel with the image and are available on restarts.
- The canonical Dockerfile below demonstrates baking binaries, enabling corepack/pnpm, building the UI, and setting the production command. This is a runnable Dockerfile example for building an image that already contains external tools:

FROM node:24-bookworm

RUN apt-get update && apt-get install -y socat && rm -rf /var/lib/apt/lists/*

Example binary 1: Gmail CLI

RUN curl -L https://github.com/steipete/gog/releases/latest/download/gogLinuxx86_64.tar.gz \ | tar -xz -C /usr/local/bin && chmod +x /usr/local/bin/gog

Example binary 2: Google Places CLI

RUN curl -L https://github.com/steipete/goplaces/releases/latest/download/goplacesLinuxx86_64.tar.gz \ | tar -xz -C /usr/local/bin && chmod +x /usr/local/bin/goplaces

Example binary 3: WhatsApp CLI

RUN curl -L https://github.com/steipete/wacli/releases/latest/download/wacliLinuxx86_64.tar.gz \ | tar -xz -C /usr/local/bin && chmod +x /usr/local/bin/wacli

Add more binaries below using the same pattern

WORKDIR /app COPY package.json pnpm-lock.yaml pnpm-workspace.yaml.npmrc./ COPY ui/package.json./ui/package.json COPY scripts./scripts

RUN corepack enable RUN pnpm install --frozen-lockfile

COPY.. RUN pnpm build RUN pnpm ui:install RUN pnpm ui:build

ENV NODE_ENV=production

CMD ["node","dist/index.js"]


Verify baked binaries inside the image
- Run a short container and check with which or --version: docker run --rm -it <image> which gog && gog --version. If a binary is missing, rebuild the image; do not attempt to install it at runtime.

Example Docker Compose fragment for persistence and loopback binding
- Use host volumes for ~/.openclaw and keep the Gateway bound to 127.0.0.1 by default so you access it via an SSH tunnel or Tailscale:

services: openclaw-gateway: image: ${OPENCLAWIMAGE} build:. restart: unless-stopped envfile: -.env environment:

  • HOME=/home/node

  • NODE_ENV=production

  • OPENCLAWGATEWAYBIND=${OPENCLAWGATEWAYBIND}

  • OPENCLAWGATEWAYPORT=${OPENCLAWGATEWAYPORT}

  • OPENCLAWGATEWAYTOKEN=${OPENCLAWGATEWAYTOKEN}

volumes:

  • ${OPENCLAWCONFIGDIR}:/home/node/.openclaw

  • ${OPENCLAWWORKSPACEDIR}:/home/node/.openclaw/workspace

ports:

  • "127.0.0.1:${OPENCLAWGATEWAYPORT}:18789"

command: ["node","dist/index.js","gateway","--bind","${OPENCLAWGATEWAYBIND}","--port","${OPENCLAWGATEWAYPORT}","--allow-unconfigured"]


Render and Northflank notes
- Render: declare your full stack in render.yaml (service, disk, env vars, health checks). This lets you keep infra versioned in repo. Set OPENCLAW_GATEWAY_PORT=8080 and use the generated service URL. Use Render's persistent disk for ~/.openclaw and its shell for state migration.
- Northflank: mount their persistent volume at /data; map /data to /home/node/.openclaw inside the container. Northflank volumes persist openclaw.json, auth-profiles.json, sessions, and workspace across redeploys.

Pre-update checklist and safe update workflow
- Checklist: create a backup, confirm free disk space, ensure swap is enabled on small VMs, temporarily reduce workspace concurrency if under heavy load, and check provider auth files are mounted (auth-profiles.json).
- Create a portable backup with the CLI before upgrading:

openclaw backup create


- Common Docker update workflow (VM with docker-compose):

git pull docker compose build docker compose up -d


Warnings and troubleshooting
- OOM during image build (pnpm install or build) commonly produces exit code 137. If builds fail, add swap or increase build VM memory. For pnpm installs, ensure pnpm lockfiles are present and use --frozen-lockfile to avoid network surprises.
- Avoid placing provider secrets directly in.env. Mount auth-profiles.json from the host and keep the file on secure storage; the Gateway reads auth-profiles.json from disk and it is easier to rotate and back up.
- If you must expose the Gateway to LAN or public networks, require gateway.auth.token or gateway.auth.password and firewall the port. Prefer loopback+SSH tunneling or Tailscale for secure access.

Host directory ownership example (Hetzner /root host)
- Ensure host directories exist and are owned by the container user (uid 1000):

mkdir -p /root/.openclaw/workspace chown -R 1000:1000 /root/.openclaw


Follow these practices to keep OpenClaw state durable across rebuilds and to reduce accidental secret exposure during updates.

## Azure VM recipe (Bastion, NSG, no public IP, install and validate)

When you want a production-ready VPS in Azure for running OpenClaw, prefer a private VM with no public IP and access it only through Azure Bastion. That pattern avoids exposing SSH/management ports to the Internet while still allowing interactive maintenance and installer runs. The recipe below walks through the required provider registration, network security group (NSG) design and priority rationale, Bastion subnet requirements, VM creation without a public IP, running the OpenClaw installer, validating the gateway, and safe cleanup.

1) Prerequisites — sign in and enable the SSH extension
Run the Azure CLI and add the SSH extension so you can use Bastion's native SSH tunneling from your workstation. This is an interactive step on your laptop; the az login will open a browser or use device code flow.

az login az extension add -n ssh


2) Register resource providers (one-time per subscription)
Azure requires certain resource providers for compute and networking. Register them before creating resources.

az provider register --namespace Microsoft.Compute az provider register --namespace Microsoft.Network


Verify registration reached Registered state:

az provider show --namespace Microsoft.Compute --query registrationState -o tsv az provider show --namespace Microsoft.Network --query registrationState -o tsv


3) Centralize deployment variables
Use shell variables so you can adapt names, CIDRs, and region quickly. Adjust LOCATION and prefixes to suit your organization.

RG="rg-openclaw" LOCATION="westus2" VNETNAME="vnet-openclaw" VNETPREFIX="10.40.0.0/16" VMSUBNETNAME="snet-openclaw-vm" VMSUBNETPREFIX="10.40.2.0/24" BASTIONSUBNETPREFIX="10.40.1.0/26" NSGNAME="nsg-openclaw-vm" VMNAME="vm-openclaw" ADMINUSERNAME="openclaw" BASTIONNAME="bas-openclaw" BASTIONPIPNAME="pip-openclaw-bastion"


4) SSH keys
Supply an existing SSH public key or generate a new ed25519 key on your workstation, then load it into a variable that will be passed to az vm create.

Use an existing key:

SSHPUBKEY="$(cat ~/.ssh/id_ed25519.pub)"


Or generate a new key pair (runnable on your workstation):

ssh-keygen -t ed25519 -a 100 -f ~/.ssh/ided25519 -C "you@example.com" SSHPUBKEY="$(cat ~/.ssh/ided25519.pub)"


5) VM sizing — pick a SKU and disk size
This example uses Standard_B2as_v2 with a 64 GB OS disk. Costs vary by region and subscription; as a rough ballpark the example SKU runs ~140/month for typical use in many regions. Treat 140/month as an approximate estimate tied to the SKU Standard_B2as_v2 — verify current pricing in your region before committing.

VMSIZE="StandardB2asv2" OSDISKSIZEGB=64


You can list available VM SKUs and check quotas:

az vm list-skus --location "${LOCATION}" --resource-type virtualMachines -o table az vm list-usage --location "${LOCATION}" -o table


6) Create resource group
Create the resource group to hold all resources so cleanup is simple.

az group create -n "${RG}" -l "${LOCATION}"


7) Create an NSG and fine-grained SSH rules
Attach the NSG to the VM subnet (not per-VM). Create a low-numbered Allow rule for SSH from the Bastion subnet, then Deny rules for broader sources. Azure evaluates NSG rules by priority (lower number wins). Use priority 100 for the Allow rule so it is evaluated before the Deny rules (110/120). This ordering prevents accidental lockouts because the explicit Allow for Bastion is evaluated first.

az network nsg create \ -g "${RG}" -n "${NSG_NAME}" -l "${LOCATION}"

Allow SSH from the Bastion subnet only

az network nsg rule create \ -g "${RG}" --nsg-name "${NSGNAME}" \ -n AllowSshFromBastionSubnet --priority 100 \ --access Allow --direction Inbound --protocol Tcp \ --source-address-prefixes "${BASTIONSUBNET_PREFIX}" \ --destination-port-ranges 22

Deny SSH from the public internet

az network nsg rule create \ -g "${RG}" --nsg-name "${NSG_NAME}" \ -n DenyInternetSsh --priority 110 \ --access Deny --direction Inbound --protocol Tcp \ --source-address-prefixes Internet \ --destination-port-ranges 22

Deny SSH from other VNet sources

az network nsg rule create \ -g "${RG}" --nsg-name "${NSG_NAME}" \ -n DenyVnetSsh --priority 120 \ --access Deny --direction Inbound --protocol Tcp \ --source-address-prefixes VirtualNetwork \ --destination-port-ranges 22


8) Create VNet and subnets — Bastion subnet naming and size constraint
Azure Bastion requires a dedicated subnet named AzureBastionSubnet with at least a /26 size. Create the VNet, attach the NSG to the VM subnet, and create the Bastion subnet.

az network vnet create \ -g "${RG}" -n "${VNETNAME}" -l "${LOCATION}" \ --address-prefixes "${VNETPREFIX}" \ --subnet-name "${VMSUBNETNAME}" \ --subnet-prefixes "${VMSUBNETPREFIX}"

Attach the NSG to the VM subnet

az network vnet subnet update \ -g "${RG}" --vnet-name "${VNETNAME}" \ -n "${VMSUBNETNAME}" --nsg "${NSGNAME}"

AzureBastionSubnet — name is required by Azure

az network vnet subnet create \ -g "${RG}" --vnet-name "${VNETNAME}" \ -n AzureBastionSubnet \ --address-prefixes "${BASTIONSUBNET_PREFIX}"


9) Create the VM without a public IP
Create the VM in the secured subnet and explicitly set --public-ip-address "" so it has no public IP. Do not attach an NSG at VM level because the NSG is applied at subnet level.

az vm create \ -g "${RG}" -n "${VMNAME}" -l "${LOCATION}" \ --image "Canonical:ubuntu-2404-lts:server:latest" \ --size "${VMSIZE}" \ --os-disk-size-gb "${OSDISKSIZEGB}" \ --storage-sku StandardSSDLRS \ --admin-username "${ADMINUSERNAME}" \ --ssh-key-values "${SSHPUBKEY}" \ --vnet-name "${VNETNAME}" \ --subnet "${VMSUBNET_NAME}" \ --public-ip-address "" \ --nsg ""


10) Provision Bastion with a public IP (tunneling)
Create a Standard static public IP for Bastion and provision the Bastion resource with tunneling enabled. Bastion will be your gateway for SSH into the private VM.

az network public-ip create \ -g "${RG}" -n "${BASTIONPIPNAME}" -l "${LOCATION}" \ --sku Standard --allocation-method Static

az network bastion create \ -g "${RG}" -n "${BASTIONNAME}" -l "${LOCATION}" \ --vnet-name "${VNETNAME}" \ --public-ip-address "${BASTIONPIPNAME}" \ --sku Standard --enable-tunneling true


11) Connect to the VM via Bastion SSH
Use az network bastion ssh from your workstation. The CLI will forward your local private key to Bastion; replace the path to your private key file if you generated one locally.

VMID="$(az vm show -g "${RG}" -n "${VMNAME}" --query id -o tsv)"

az network bastion ssh \ --name "${BASTIONNAME}" \ --resource-group "${RG}" \ --target-resource-id "${VMID}" \ --auth-type ssh-key \ --username "${ADMINUSERNAME}" \ --ssh-key ~/.ssh/ided25519


12) Install OpenClaw on the VM
Once SSHed into the VM, download and run the official installer script. The following commands are the runnable sequence you should execute on the VM shell.

curl -fsSL https://openclaw.ai/install.sh -o /tmp/install.sh bash /tmp/install.sh rm -f /tmp/install.sh


13) Validate the gateway
After installation, confirm the OpenClaw gateway daemon is running and healthy.

openclaw gateway status


If the daemon is a systemd service, you can inspect logs for startup errors:

- journalctl -u openclaw.gateway -f
- journalctl -b | grep openclaw

14) Stop/start and cleanup
To save costs, you can deallocate (stop) the VM and later start it. Deallocating releases compute billing but preserves disks.

az vm deallocate -g "${RG}" -n "${VMNAME}" az vm start -g "${RG}" -n "${VMNAME}"


When you no longer need any resources, delete the entire resource group. This is destructive and irreversible; double-check RG before running.

az group delete -n "${RG}" --yes --no-wait


Operational notes and gotchas
- Always name the Bastion subnet AzureBastionSubnet and use at least /26. Smaller subnets will cause Bastion provisioning to fail.
- NSG priority order matters: AllowSshFromBastionSubnet at priority 100 ensures Bastion traffic is permitted even though later Deny rules block broader sources. Setting priorities incorrectly can leave you locked out.
- The VM example SKU (Standard_B2as_v2) is a ballpark choice; confirm region availability and pricing. The rough cost estimate of 140/month is illustrative and will vary by region, reserved instances, and additional services (Bastion has its own charges).
- Keep the Gateway bound to loopback where possible and use tunnels (Bastion, SSH LocalForward, or Tailscale) when remote access is needed.

This sequence gives you a hardened Azure VM for OpenClaw: no public VM IP, controlled SSH via Bastion, NSG rules that limit blast radius, and a straightforward installer/validation path.

## GCP Compute Engine recipe (Docker-friendly VM, SSH tunnel, service account automation)

A reliable GCP workflow makes a small, Docker-ready VM the build-and-run host while keeping the Gateway bound to loopback and reachable only over an SSH tunnel. Use e2-small (2 vCPU, 2 GB RAM) as the minimum machine type for local Docker builds — e2-micro frequently runs out of memory during pnpm installs and Docker image builds. Expect roughly ~$25/mo for an e2-small in many regions; if you plan heavier builds or concurrent agents, choose a larger machine.

Start by authenticating and selecting a project, then enable Compute Engine for that project:

gcloud init gcloud auth login


Create and select a project:

gcloud projects create my-openclaw-project --name="OpenClaw Gateway" gcloud config set project my-openclaw-project


Enable the Compute Engine API:

gcloud services enable compute.googleapis.com


Provision a Debian VM sized for Docker builds. The example below creates an e2-small (2 vCPU, 2GB RAM) with a 20GB boot disk. Pick a zone close to you; if you need more memory, choose e2-medium or n2-standard variants.

gcloud compute instances create openclaw-gateway \ --zone=us-central1-a \ --machine-type=e2-small \ --boot-disk-size=20GB \ --image-family=debian-12 \ --image-project=debian-cloud


SSH into the VM using gcloud:

gcloud compute ssh openclaw-gateway --zone=us-central1-a


On the VM, install Docker and add your user to the docker group so you can run Docker without sudo. After usermod, you must log out and back in (or reconnect the SSH session) for group membership to take effect.

sudo apt-get update sudo apt-get install -y git curl ca-certificates curl -fsSL https://get.docker.com | sudo sh sudo usermod -aG docker $USER


Verify Docker and Docker Compose:

docker --version docker compose version


Clone the OpenClaw repository and prepare persistent host directories for runtime state and workspaces. Mounting ~/.openclaw to the container ensures updates and restarts keep state intact.

git clone https://github.com/openclaw/openclaw.git cd openclaw

mkdir -p ~/.openclaw mkdir -p ~/.openclaw/workspace


Create a small.env file to parameterize the Compose deployment. Keep provider credentials out of.env: runtime config keys (OPENCLAW_*) may live in.env, but sensitive provider OAuth/API keys belong in the mounted auth-profiles.json for each agent under ~/.openclaw/agents/<agentId>/agent/auth-profiles.json.

OPENCLAWIMAGE=openclaw:latest OPENCLAWGATEWAYTOKEN= OPENCLAWGATEWAYBIND=lan OPENCLAWGATEWAY_PORT=18789

OPENCLAWCONFIGDIR=/home/$USER/.openclaw OPENCLAWWORKSPACEDIR=/home/$USER/.openclaw/workspace

GOGKEYRINGPASSWORD= XDGCONFIGHOME=/home/node/.openclaw


Generate any random secrets (keyring password, tokens) with openssl:

openssl rand -hex 32


Use a docker-compose fragment that mounts the host ~/.openclaw and keeps the Gateway loopback-only on the VM by mapping 127.0.0.1:18789. This prevents accidental public exposure. If you must expose the service publicly, remove the 127.0.0.1 prefix and ensure firewall rules and HTTPS termination are in place.

services: openclaw-gateway: image: ${OPENCLAWIMAGE} build:. restart: unless-stopped envfile: -.env environment:

  • HOME=/home/node

  • NODE_ENV=production

  • TERM=xterm-256color

  • OPENCLAWGATEWAYBIND=${OPENCLAWGATEWAYBIND}

  • OPENCLAWGATEWAYPORT=${OPENCLAWGATEWAYPORT}

  • OPENCLAWGATEWAYTOKEN=${OPENCLAWGATEWAYTOKEN}

  • GOGKEYRINGPASSWORD=${GOGKEYRINGPASSWORD}

  • XDGCONFIGHOME=${XDGCONFIGHOME}

  • PATH=/home/linuxbrew/.linuxbrew/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

volumes:

  • ${OPENCLAWCONFIGDIR}:/home/node/.openclaw

  • ${OPENCLAWWORKSPACEDIR}:/home/node/.openclaw/workspace

ports:

  • "127.0.0.1:${OPENCLAWGATEWAYPORT}:18789"

command: [ "node", "dist/index.js", "gateway", "--bind", "${OPENCLAWGATEWAYBIND}", "--port", "${OPENCLAWGATEWAYPORT}", "--allow-unconfigured", ]


After the container is running, configure allowed Control UI origins to permit your local forwarded origin. Run this helper through the CLI container (it performs a config set against the running gateway):

docker compose run --rm openclaw-cli config set gateway.controlUi.allowedOrigins '["http://127.0.0.1:18789"]' --strict-json


Create an SSH tunnel from your laptop to forward the remote loopback port to your local machine. This keeps the Gateway unreachable from the public internet while giving you full UI access.

gcloud compute ssh openclaw-gateway --zone=us-central1-a -- -L 18789:127.0.0.1:18789


Open the dashboard locally by running the dashboard command inside the CLI container on the VM (this prints the dashboard URL without trying to open a browser on the VM):

docker compose run --rm openclaw-cli dashboard --no-open


Manage device approvals over the tunnel:

docker compose run --rm openclaw-cli devices list docker compose run --rm openclaw-cli devices approve <requestId>


Resizing and automation notes
- To change machine type: stop the VM, set the machine type, then start it again (the VM must be stopped to change type).

Stop the VM first

gcloud compute instances stop openclaw-gateway --zone=us-central1-a

Change machine type

gcloud compute instances set-machine-type openclaw-gateway \ --zone=us-central1-a \ --machine-type=e2-small

Start the VM

gcloud compute instances start openclaw-gateway --zone=us-central1-a


- For unattended provisioning, create a service account and grant compute instance administration so automation can start/stop or recreate instances:

gcloud iam service-accounts create openclaw-deploy \ --display-name="OpenClaw Deployment"

gcloud projects add-iam-policy-binding my-openclaw-project \ --member="serviceAccount:openclaw-deploy@my-openclaw-project.iam.gserviceaccount.com" \ --role="roles/compute.instanceAdmin.v1"


Validation and cleanup checklist
- Confirm docker compose services start and that the Gateway process logs show it bound to 127.0.0.1:18789.
- Verify Control UI loads locally over the SSH tunnel.
- Confirm sensitive provider keys are stored under ~/.openclaw/agents/.../auth-profiles.json, not.env.
- If you modify docker group membership, reconnect SSH to pick up the change.
- To decommission, stop the VM and delete it from the project; if you used a service account key on disk, revoke it and remove keys from the VM.

Following this recipe gives a secure, repeatable GCP VM deployment for building and running OpenClaw with Docker while minimizing public exposure and providing clear upgrade and automation paths.

## Managed platform recipes: Fly.io and Render

Keep the Gateway bound to localhost and let the platform’s reverse proxy or an SSH/Tailscale tunnel terminate public TLS. Binding the Gateway to 127.0.0.1 eliminates an entire class of accidental exposures; if you must bind to a LAN or tailnet address, enforce gateway.auth.token or gateway.auth.password in config.

On managed hosts such as Fly.io and Render you typically deploy a container image that contains a baked OpenClaw install (node, pnpm artifacts, built JS). The container should start the gateway with its HTTP/WebSocket listener set to 127.0.0.1:18789 (default) while the platform config forwards public traffic to that loopback. Build images so startup is fast and the runtime user is non-root. Persist ~/.openclaw to a platform volume.

Checklist for adapting images
- Bake Node 24 and pnpm-built app artifacts into the final layer; avoid installing at runtime.
- Configure OpenClaw to bind 127.0.0.1 by setting gateway.listen.host or via env OPENCLAW_BIND=127.0.0.1.
- Mount a persistent volume to /home/node/.openclaw (or the chosen user’s home).
- Expose only the platform proxy port; do not open 18789 publicly.
- Add a health check endpoint that probes localhost:18789/health.

Dockerfile fragment for baking node/pnpm artifacts (illustrative)

FROM node:24-alpine AS builder WORKDIR /src COPY package.json pnpm-lock.yaml./ RUN corepack enable && corepack prepare pnpm@latest --activate COPY.. RUN pnpm install --frozen-lockfile && pnpm build

FROM node:24-alpine RUN addgroup -S app && adduser -S app -G app USER app WORKDIR /home/app COPY --from=builder /src/dist./dist COPY --from=builder /src/package.json./ ENV NODE_ENV=production

Persisted runtime home; platform must mount this path as a volume

VOLUME ["/home/app/.openclaw"] CMD ["node", "dist/cli.js", "gateway", "start", "--listen-host=127.0.0.1"]


Platform volume notes (short)
- Fly.io: supports persistent volumes; size must be declared per-app and cannot be resized without rebuild. Good for ~/.openclaw but use external backups.
- Render: persistent disks available on web services; snapshots are supported but retention varies.
- Both: ephemeral instance storage still possible — always mount a volume for ~/.openclaw.

DigitalOcean / generic Linux VPS tips
- Use Ubuntu 24.04 LTS for compatibility. On constrained 1 GB droplets add swap to reduce OOMs:

ssh root@YOURVPSIP

apt-get update apt-get install -y git curl ca-certificates curl -fsSL https://get.docker.com | sh

- On a 1 GB Droplet, create a 2 GB swapfile (mkswap/swapon) before heavy installs. This reduces build/run OOMs during package installs or node builds.
- Prefer installing via the baked container approach above; if installing directly, run openclaw onboard and openclaw gateway install to set up the daemon.

Access patterns
- Default: loopback-only + SSH -L or Tailscale. Example SSH tunnel: ssh -N -L 18789:127.0.0.1:18789 user@host
- If binding public: require gateway.auth.token or gateway.auth.password and rotate credentials regularly.

Persistence & backup
- Treat the platform volume as primary runtime storage and run regular backups (tar -czf ~/.openclaw-backup.tgz) to object storage. See the Persistence & updates chapter for recommended backup cadence and the openclaw backup create/verify workflow.

Follow these patterns to keep a managed deployment simple, auditable, and secure while preserving the Gateway’s on-disk state.

## Docker VM recipe (systemd + docker-compose): quick host run

Running OpenClaw in a VM with Docker and docker-compose gives a small, repeatable host deployment pattern: bake required native binaries into the image, mount persistent state from the host, bind the Gateway to loopback for safety, and manage lifecycle with a systemd unit that runs docker-compose. The examples below provide a minimal, copy-paste-safe starting point and the common update/rollback steps you will reuse.

Baked-image principle
- Install any external native binaries at image-build time. Installing them inside a running container (apt/curl in an entrypoint) is fragile and not persisted across image updates. The Dockerfile below demonstrates the pattern: apt packages, curl/tar to /usr/local/bin, Node 24 base image, pnpm install/build, and a production CMD.

Dockerfile (runnable image build)

FROM node:24-bookworm

RUN apt-get update && apt-get install -y socat && rm -rf /var/lib/apt/lists/*

Example native binaries baked into image:

RUN curl -L https://github.com/steipete/gog/releases/latest/download/gogLinuxx86_64.tar.gz \ | tar -xz -C /usr/local/bin && chmod +x /usr/local/bin/gog

RUN curl -L https://github.com/steipete/goplaces/releases/latest/download/goplacesLinuxx86_64.tar.gz \ | tar -xz -C /usr/local/bin && chmod +x /usr/local/bin/goplaces

WORKDIR /app COPY package.json pnpm-lock.yaml pnpm-workspace.yaml.npmrc./ COPY ui/package.json./ui/package.json COPY scripts./scripts

RUN corepack enable RUN pnpm install --frozen-lockfile

COPY.. RUN pnpm build RUN pnpm ui:install RUN pnpm ui:build

ENV NODE_ENV=production

CMD ["node","dist/index.js"]


Compose fragment: loopback bind + host volume
- Persist all OpenClaw runtime state on the host (default ~/.openclaw). Bind the Gateway to 127.0.0.1 to avoid accidental public exposure; use SSH/Tailscale/Reverse proxy patterns to access remotely.

docker-compose.yml fragment

version: "3.8" services: openclaw: image: "${OPENCLAW_IMAGE:-openclaw:latest}" restart: unless-stopped environment:

  • OPENCLAWGATEWAYBIND=loopback

  • OPENCLAWGATEWAYPORT=18789

  • OPENCLAWGATEWAYTOKEN=${OPENCLAWGATEWAYTOKEN}

  • OPENCLAWCONFIGDIR=/data/.openclaw

  • OPENCLAWWORKSPACEDIR=/data/.openclaw/workspace

volumes:

  • /root/.openclaw:/data/.openclaw

ports:

  • "127.0.0.1:18789:18789"


Persistent dirs and ownership
- Create and own the host directories before first run to avoid permission surprises when the container user differs from host UID/GID.

Commands to prepare host directories

mkdir -p /root/.openclaw/workspace

If the container runs as UID 1000, ensure ownership:

chown -R 1000:1000 /root/.openclaw


Environment template
- Use an env file to centralize image and runtime variables.

.env

OPENCLAWIMAGE=openclaw:latest OPENCLAWGATEWAYTOKEN= OPENCLAWGATEWAYBIND=lan OPENCLAWGATEWAY_PORT=18789

OPENCLAWCONFIGDIR=/root/.openclaw OPENCLAWWORKSPACEDIR=/root/.openclaw/workspace

GOGKEYRINGPASSWORD= XDGCONFIGHOME=/home/node/.openclaw


systemd unit to run docker-compose
- A lightweight unit ensures the compose stack starts on boot and restarts on failure.

/etc/systemd/system/openclaw.service

[Unit] Description=OpenClaw Docker Compose After=network.target docker.service Requires=docker.service

[Service] Type=oneshot RemainAfterExit=yes WorkingDirectory=/opt/openclaw ExecStart=/usr/local/bin/docker compose up -d ExecStop=/usr/local/bin/docker compose down TimeoutStartSec=120 Restart=on-failure RestartSec=10

[Install] WantedBy=multi-user.target


Update, rebuild, and rollback
- Update flow is simple: pull code, rebuild image, then recreate containers. Tag images with immutable tags for rollbacks.

Update commands

git pull docker compose build docker compose up -d

- For rollback, docker compose pull or docker run using the previous tag (e.g., openclaw:2026.04.10) and restart the service.

Common failure and troubleshooting
- If docker compose build fails with an early "Killed" or exit code 137 during pnpm install --frozen-lockfile, the VM likely ran out of memory. Increase VM memory (or add swap) and re-run the build.
- If containers start but OpenClaw cannot write state, check host directory ownership and SELinux/AppArmor policies. Matching UID/GID or an entrypoint chown is the usual fix.
- If the Gateway is unexpectedly reachable from the public network, verify docker-compose ports map to 127.0.0.1 and check host firewall (ufw/iptables) and cloud provider security groups.

Northflank note
- Northflank offers a one-click OpenClaw template that runs the Gateway without server terminal access. It provides persistent storage mounted at /data so state survives redeploys; use the provided UI path /openclaw and set OPENCLAW_GATEWAY_TOKEN in the service variables.

Checklist before production
- Confirm all native binaries are baked into the image.
- Ensure /root/.openclaw (or chosen config dir) is mounted and owned correctly.
- Bind Gateway to loopback or protect it with firewall/SSH/Tailscale.
- Tag built images for revertability and test restore from a backup of ~/.openclaw before destructive upgrades.

## Kubernetes deployment patterns (stateful, PVCs, ingress with WebSocket)

Kubernetes clusters are convenient for hosting containerized services, but OpenClaw is stateful: the Gateway keeps workspace files, agent transcripts, and local auth state under ~/.openclaw. Treat that state as first-class when you design manifests: use a PersistentVolumeClaim (PVC), keep a single active replica unless you add shared storage and a leader-election layer, and preserve the recommended secure-exposure posture (Gateway bound to loopback, accessed via SSH tunnel or Tailscale by default).

Secure-default rule
- By default keep the Gateway bound to loopback and reach it through an SSH LocalForward or Tailscale tunnel. If you choose to bind the Gateway to a cluster IP / LAN / tailnet, require gateway.auth.token or gateway.auth.password in your config so the Control UI and WS API remain protected.

Pod model: Deployment vs StatefulSet
- Use a Deployment for ephemeral or stateless replicas only if you have an external store for workspaces and implement leader election for write operations.
- For a single instance that owns local state, prefer a single-replica Deployment or StatefulSet with a PVC. StatefulSet is helpful if you later need stable identity and ordered rollouts, but a Deployment with persistent storage is simpler for a single replica.

Example PVC + Deployment fragment
- Mount the PVC at the same path the Gateway expects. Containers do not expand ~ in Kubernetes, so use the absolute path the image uses (adjust if your image runs as non-root).

apiVersion: v1 kind: PersistentVolumeClaim metadata: name: openclaw-data namespace: openclaw spec: accessModes:

  • ReadWriteOnce

resources: requests: storage: 10Gi


apiVersion: apps/v1 kind: Deployment metadata: name: openclaw namespace: openclaw spec: replicas: 1 selector: matchLabels: app: openclaw template: metadata: labels: app: openclaw spec: containers:

  • name: gateway

image: openclaw/gateway:stable ports:

  • containerPort: 18789

name: http volumeMounts:

Adjust the path if your image runs as another user

  • name: openclaw-data

mountPath: /root/.openclaw volumes:

  • name: openclaw-data

persistentVolumeClaim: claimName: openclaw-data


Liveness and readiness probes
- Gateway startup can be slower when it initializes plugins and providers; choose conservative timing.
- Use an HTTP GET probe against the Gateway health endpoint (Gateway exposes HTTP/WS on the same port). Example values below are conservative and safe for production:

Add to container spec

livenessProbe: httpGet: path: /health port: 18789 initialDelaySeconds: 30 timeoutSeconds: 5 periodSeconds: 10 failureThreshold: 6

readinessProbe: httpGet: path: /health port: 18789 initialDelaySeconds: 15 timeoutSeconds: 5 periodSeconds: 10 failureThreshold: 3


Ingress / IngressController considerations for WebSocket
- The Gateway uses long-lived WebSocket connections. Configure your Ingress so it preserves Upgrade/Connection headers, uses HTTP/1.1 to the backend, and sets extended proxy timeouts. For nginx-ingress the common annotations are:

- proxy-read-timeout and proxy-send-timeout large enough for long-lived WS streams (e.g., 3600s).
- ensure the controller forwards Upgrade/Connection and uses proxy_http_version: "1.1".

Example nginx ingress annotations:

apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: openclaw-ingress namespace: openclaw annotations: kubernetes.io/ingress.class: "nginx" nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" nginx.ingress.kubernetes.io/proxy-http-version: "1.1" nginx.ingress.kubernetes.io/proxy-set-headers: "ingress-nginx/custom-headers" spec: rules:

  • host: openclaw.example.com

http: paths:

  • path: /

pathType: Prefix backend: service: name: openclaw port: number: 18789


- If your cluster sits behind a trusted proxy, ensure you configure trusted IP blocks in the ingress controller so X-Forwarded-* headers are preserved safely. Do not blindly trust client-supplied headers when exposing Gateway control endpoints.

Single-replica recommendation and replication trade-offs
- Prefer a single replica unless you provide shared persistent storage and a coordination mechanism for writes:
 - Local PVCs (ReadWriteOnce) are simplest and safe for a single active pod.
 - Shared volumes (ReadWriteMany) or externalized object storage plus a leader-election mechanism allow multi-replica topologies but add complexity and potential consistency issues for session/compaction logic.
- If you need HA, plan for an external object store and a leader/lease implementation before scaling replicas.

Kubernetes secrets and token retrieval
- Store gateway tokens or provider keys in a Secret and mount them or inject via env. To read the gateway token stored in a Secret in the openclaw namespace, decode it with kubectl and base64:

```bash/text
kubectl get secret openclaw-secrets -n openclaw -o jsonpath='{.data.OPENCLAW_GATEWAY_TOKEN}' | base64 -d

Local testing and deploy helpers

  • Use the project helper to create a local kind cluster for testing or tear it down:

`bash/text ./scripts/k8s/create-kind.sh # auto-detects docker or podman ./scripts/k8s/create-kind.sh --delete # tear down


- Deploy scripts accept a provider API key exported into the environment. Example pattern to set a provider key and run the deploy helper:

```bash/text
# Replace with ANTHROPIC, OPENAI, OPENROUTER, etc.
export <PROVIDER>_API_KEY="..."
./scripts/k8s/deploy.sh
  • You can separate secret creation from deployment:

`bash/text export <PROVIDER>APIKEY="..." ./scripts/k8s/deploy.sh --create-secret ./scripts/k8s/deploy.sh


Operational checklist
- Mount ~/.openclaw via a PVC; verify ownership/permissions match the container user.
- Start with a single replica and enable readiness/liveness probes.
- Keep Gateway bound to loopback when possible; otherwise enforce gateway.auth credentials.
- Configure ingress with WebSocket-safe annotations and extended timeouts.
- Backup the PVC contents regularly (openclaw backup create/verify on a node or via sidecar job) and test restore.

Finally, prefer conservative rollouts: test in-kind or a staging cluster first, verify the Control UI can connect using the token from your Secret, and run openclaw onboard --install-daemon on a dedicated Linux host when you need the systemd-managed, single-host daemon variant rather than the container deployment.

## Raspberry Pi and single-board host recipe (arm builds, constrained memory)

Edge devices are useful for local sensors, cameras, or when you need a companion node close to a private network. On Raspberry Pi and other single‑board hosts you must manage two constraints: limited RAM during builds/installs, and storage wear on SD cards. Plan for persistent storage off SD (USB SSD or NAS) and a small swapfile to avoid OOM during large installs (pnpm, sharp builds).

Prepare the OS and persistent storage
- Boot a recent Raspberry Pi OS (64‑bit recommended on Pi 4/400/Compute Module on modern images). Attach an external SSD and mount it at /var/lib/openclaw or bind‑mount to ~/.openclaw to keep runtime state off the SD card.
- Create a swapfile if you expect heavy builds or pnpm installs. Use conservative size (1–2 GiB) and mark swappiness low so the device prefers RAM:

sudo fallocate -l 1G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile

persist across reboots

echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab


Install OpenClaw: arm builds and Docker
If you want a native ARM install, use the installer; expect longer build times and higher RAM pressure. Alternatively, prefer Docker images that are multi‑arch or that you build with multi‑arch tooling and bake required native binaries into the image.

Important Docker VM runtime rules:
- Bake external binaries at image build time. Installing large native dependencies at container startup on Pi risks OOM or corrupt state. If a skill later requires new binaries, update your Dockerfile, rebuild the image, and restart containers to include the new artifacts. This is essential for reproducible, stable runtime images.
- If a build fails with exit code 137, it usually indicates the kernel OOM killed the process; increase swap, reduce parallelism, or build on a more powerful machine with cross‑compile/docker buildx.

Expose the Control UI securely
Never open the gateway port to the public internet. Use Tailscale or SSH tunnel for remote access. Example SSH tunnel from your laptop to the Pi:

- Local SSH tunnel: ssh -N -L 18789:127.0.0.1:18789 pi@edge-host

macOS VM note (Apple Silicon)
You can run macOS VMs on Apple Silicon with Lume. After creating the VM enable Remote Login in System Settings, SSH in, install OpenClaw, then onboard and install the daemon:

- Enable Remote Login (System Settings → General → Sharing → Remote Login)
- SSH in, run the installer, then:
 sudo openclaw onboard --install-daemon

Kubernetes and image pinning
When deploying via Kubernetes, set a non‑default namespace with an environment variable when running the supplied deploy script:

```bash/text
OPENCLAW_NAMESPACE=my-namespace./scripts/k8s/deploy.sh

And pin images in manifests to avoid surprising upgrades:

`yaml/text image: ghcr.io/openclaw/openclaw:latest # or pin to a specific version from https://github.com/openclaw/openclaw/releases


Checklist before declaring an edge host production-ready
- State directory (~/.openclaw) mounted on SSD or network storage.
- Swapfile in place and swappiness tuned.
- Backups scheduled (tar + manifest of ~/.openclaw).
- Remote access via Tailscale or SSH tunnel; no public gateway port.
- Rebuild image whenever skills add native binaries; do not rely on runtime apt/pnpm installs for production images.

## macOS VM recipe and macOS-specific channels (iMessage companion)

Certain channels—most notably iMessage—require a macOS host or companion. Use a macOS VM or a physical Mac when you must host the macOS companion app (LaunchAgent-based Canvas, IPC, camera/canvas access). Plan for macOS licensing and maintenance: follow Apple’s licensing and platform docs for VM use and do not attempt unsupported host circumventions.

Verify your Lume tool before creating a VM:
```bash/text
lume --version

Create a macOS VM quickly with Lume (example creates a VM named "openclaw" using the latest IPSW): `bash/text lume create openclaw --os macos --ipsw latest


Prepare the macOS host:
- Install Node and the macOS companion build prerequisites (Xcode toolchain if building locally).
- Create a dedicated system user for the companion and restrict SSH/remote access to that account.
- Install the companion app and register its LaunchAgent. Keep the Gateway loopback-only (127.0.0.1:18789) and use SSH LocalForward, Tailscale Serve/Funnel, or a TLS-terminating reverse proxy to expose the Gateway safely if remote access is required.

Pairing and security notes for the companion:
- Approve the companion device via openclaw devices approve on the Gateway; companion pairing is stored under ~/.openclaw/devices.
- Use the Gateway token or SecretRef for auth; do not disable gateway auth for convenience.

Operational warning: exposing the Gateway without loopback binding + auth risks unauthorized tool execution and provider credential leakage. Always keep gateway.auth enabled and terminate TLS at a trusted edge.

Kubernetes deploy helper (note for admins): deploy.sh can create a Secret containing provider API keys and an auto-generated OPENCLAW_GATEWAY_TOKEN when you run it with exported provider keys. If that Secret already exists, deploy.sh preserves the current gateway token and any provider keys you are not changing. Use kubectl port-forward for local testing; to expose beyond port-forward, change the Gateway bind address explicitly and keep auth + TLS in place.

## Monitoring, backups, and operational checks

A fast operational checklist reduces mean-time-to-recovery. Start by verifying the Gateway process and then inspect logs, disk, and memory. On systemd hosts use openclaw gateway status and journalctl. In container or cloud-hosted services use docker logs or the platform shell. If a managed host exposes a service URL (Render, Northflank, Fly), prefer the platform shell to collect logs and the generated service health endpoints rather than opening the Gateway to the public.

Basic commands you will run often:
- Check the daemon: openclaw gateway status
- Create an on-demand state backup (portable archive created by the OpenClaw CLI):
```bash/text
openclaw backup create
  • SSH to a headless host (Raspberry Pi or VM) to run further checks:

`bash/text ssh user@gateway-host


Common failure symptoms and quick diagnostics
- Service not responding: confirm openclaw gateway status, then inspect logs. On systemd:
 - sudo journalctl -u openclaw -f --no-pager
 In Docker:
 - docker-compose logs -f gateway
 If the Gateway process starts and exits immediately, capture exit code and recent journal entries.
- OOM / exit code 137: a process killed with 137 usually means the kernel OOM killer terminated it. Remedies: increase instance memory, add swap (small swap file avoids transient failures during rebuilds), or reduce concurrency (lower threads/workers during updates). If this happens during image build, allocate more build VM memory or build with --memory swap adjustments.
- Disk full: sessions, provider auth, and workspace state live under ~/.openclaw; running out of disk will break writes and can corrupt in-flight state. Check with df -h and du -sh ~/.openclaw. Add disk or rotate/prune transcripts.

Platform-specific persistence notes
- Northflank: the platform mounts persistent storage at /data. Use that mount for runtime state: ensure OpenClaw writes its state under /data/.openclaw (or symlink /home/node/.openclaw → /data/.openclaw). Northflank Volume at /data preserves openclaw.json, auth-profiles.json, channel/provider state, sessions, and workspace across redeploys.
- Render: the render.yaml Blueprint can auto-generate a secure OPENCLAW_GATEWAY_TOKEN for your service (generateValue: true). After deploy, find the token in the Dashboard → Environment. When deploying to Render set OPENCLAW_GATEWAY_PORT=8080 and bind the Gateway to that port internally; use Render’s service URL and built-in health checks. Do not expose Gateway tokens publicly—use platform environment secrets.

Persistent-state rule (must follow)
Persist all long-lived runtime state (gateway config, model auth-profiles, skill configs, agent workspace, WhatsApp sessions, Gmail keyring) on host-mounted volumes under /home/node/.openclaw or an equivalent persistent mount. If you bake an image, ensure the runtime uses a mounted volume for state so rebuilds and redeploys do not lose data.

Runbook: service down (quick)
1. openclaw gateway status → if stopped, attempt openclaw gateway start.
2. Collect logs: journalctl -u openclaw -n 200 or docker logs -t <container>.
3. Check disk: df -h; disk full → free space or attach volume.
4. Check memory and OOM: free -h; dmesg | grep -i kill
5. If corrupted state suspected, restore last good backup (store backups off-host—S3, cloud drive, or a separate NAS) and restart:
 - openclaw backup restore <path-to-archive>
6. If the service fails repeatedly during updates, roll back to the previous image and rebuild with increased memory or add swap.

Backup cadence and retention
Take backups after any configuration change and nightly for production. Keep at least 7 daily backups and one weekly snapshot for a 30-day window if storage permits. Store backups off-host (S3, cloud object store, or another VM). The openclaw backup create command produces a portable archive suitable for these policies.

Lightweight monitoring suggestions
- Process check (systemd): systemctl is-active openclaw && echo OK || alert
- Disk alert: if [ $(df /home | awk 'NR==2{print $5+0}') -gt 85 ]; then alert; fi
- Memory alert: similar free-based check; set an alert when free+cached < threshold
Use your platform’s alerting (Render/Northflank health checks) or a small cron script that posts to PagerDuty/Slack when thresholds are crossed.

Warnings
Never expose the Gateway port without a token-protected reverse proxy or secure tunnel. For single-host gateways prefer loopback-only binding with SSH tunneling, Tailscale, or a properly configured reverse proxy that enforces WebSocket header forwarding and token auth.

Hosting OpenClaw: Containers, Declarative Installs, and Automation

Containers and Install Modes — choosing the right runtime

Pick the runtime that matches your operational constraints: do you need single-user convenience, strong isolation, immutable configuration, or a repeatable host bootstrap? Each mode trades installation friction for containment and restart semantics.

Native installs (local prefix)

  • Surface: the Gateway runs as a systemd user or system service on the host.

  • Isolation: minimal — uses host Node/pnpm runtime; sandboxes are optional and use Docker when enabled.

  • Persistence: ~/.openclaw for runtime state and workspaces.

  • Auto-start model: systemd LaunchAgent/Service.

  • Best for: single-developer laptops, tightly integrated companion apps, or when low latency and direct host tooling access matter.

Docker (containerized)

  • Surface: run the Gateway inside a container image (build or pull).

  • Isolation: strong process boundary and dependency isolation; useful for throwaway or disposable Gateways.

  • Persistence: mount host ~/.openclaw into the container to persist state.

  • Auto-start model: docker-compose, systemd unit, or container platforms.

  • Best for: ephemeral test environments, hosts without Node/pnpm, or when you prefer container lifecycle management.

Docker is optional — use it when you want isolation or to avoid installing dependencies on the host. Enabling sandbox backends uses Docker; see the Docker section for build, onboarding, and compose recipes.

Podman (rootless)

  • Surface: the Gateway runs in a rootless container as the current non-root user.

  • Isolation: similar to Docker but without daemon privileges; uses user namespaces.

  • Persistence: defaults to ~/.openclaw on the host (bind mount).

  • Auto-start model: optional systemd --user Quadlet unit to integrate with user session.

  • Best for: operators requiring daemonless containers and avoiding root; CLI can still manage the container by setting OPENCLAW_CONTAINER.

Nix / nix-openclaw (declarative)

  • Surface: declarative flake + Home Manager module pins Gateway and tools.

  • Immutable install behavior: set OPENCLAWNIXMODE=1 to disable auto-install and self-mutation flows; OpenClaw will surface Nix-specific remediation guidance rather than altering the store.

  • Persistence: configure OPENCLAWCONFIGPATH and OPENCLAWSTATEDIR so runtime state lives outside the Nix store.

  • Best for: reproducible deployments, multi-host consistency, and users already on Nix.

Ansible (openclaw-ansible) The Ansible playbook installs and hardens a host for production. It establishes a 4-layer defense model: UFW firewall (SSH + Tailscale only), Tailscale VPN for mesh access, Docker CE (for sandbox isolation), and systemd hardening (NoNewPrivileges, PrivateTmp, unprivileged openclaw user). The playbook can run as a one-command installer or via curated roles; after install, switch to the openclaw user, run onboarding, and login providers.

Health probes and CLI targeting Health endpoints are available without auth on the Control UI port:

curl -fsS http://127.0.0.1:18789/healthz # liveness
curl -fsS http://127.0.0.1:18789/readyz # readiness

Choosing container vs native changes how host CLI commands target the running gateway (set OPENCLAW_CONTAINER to point CLI at a containerized instance). Also decide where credentials and.env/openclaw.json live because mounts determine persistence and secret handling.

Automated Host Deployment with openclaw-ansible

Run the installer once to provision a hardened OpenClaw host, or follow the manual playbook flow so you can audit each step.

Warning: piping a remote script into bash executes code from the network. Inspect the installer URL before running it, or use the manual playbook path below if you must audit every change.

Quick one-line bootstrap (audit first)

curl -fsSL https://raw.githubusercontent.com/openclaw/openclaw-ansible/main/install.sh | bash

Prerequisites and supported hosts

  • The playbook targets Debian/Ubuntu families (Debian 11+ or Ubuntu 20.04+).

  • You must have root or sudo privileges on the target machine and an internet connection for package installation.

  • The playbook is designed for production-like installs and will configure system services and firewall rules—plan for maintenance windows.

What the playbook configures (4-layer defense model)

  • UFW firewall with a strict default deny and explicit allowances: SSH is permitted; other external ports are blocked by default.

  • Tailscale is installed and configured to provide mesh access; the Gateway itself is intentionally reachable only over Tailscale unless you change the defaults.

  • Docker CE is installed as the default sandbox backend so agents can run in containerized sandboxes. Note: the Gateway runs on the host (systemd unit); it is not deployed inside Docker by default.

  • systemd service hardening: the openclaw service is created for an unprivileged openclaw user and applies standard hardening directives (NoNewPrivileges, PrivateTmp, etc.).

Manual (auditable) installation steps

On a machine where you prefer to inspect artifacts first, install prerequisites:

sudo apt update && sudo apt install -y ansible git

Clone the repo and enter it:

git clone https://github.com/openclaw/openclaw-ansible.git
cd openclaw-ansible

Install any required Ansible collections:

ansible-galaxy collection install -r requirements.yml

Run the provided wrapper (it prompts for elevation as needed and is idempotent):

./run-playbook.sh

Alternate direct playbook run (you will be prompted for sudo password):

ansible-playbook playbook.yml --ask-become-pass
## When the playbook completes it writes a setup script; run:
## /tmp/openclaw-setup.sh

Idempotence and re-running The playbook and its run wrapper are safe to run multiple times. Use this for updates or to re-apply configuration changes:

cd openclaw-ansible
./run-playbook.sh

Post-install checks and onboarding

  • Switch to the unprivileged openclaw account to run interactive CLI steps and onboarding:

sudo -i -u openclaw
  • From the openclaw user, run the onboarding and authenticate channels (WhatsApp/Telegram/Discord/etc.):

openclaw channels login
  • Verify the systemd unit and follow logs:

sudo systemctl status openclaw
sudo journalctl -u openclaw -f

A compact collection of maintenance commands:

# Check service status
sudo systemctl status openclaw

# View live logs
sudo journalctl -u openclaw -f

# Restart gateway
sudo systemctl restart openclaw

# Provider login (run as openclaw user)
sudo -i -u openclaw
openclaw channels login

Validate external attack surface Confirm only SSH is externally exposed (run from a remote workstation):

nmap -p- YOUR_SERVER_IP

When installed with defaults, only port 22 should be reachable externally; the gateway is reachable over Tailscale.

Troubleshooting tips

  • If the service won’t start, check recent logs and permissions:

# Recent logs
sudo journalctl -u openclaw -n 100

# File permissions
sudo ls -la /opt/openclaw

# Test manual gateway run as the openclaw user
sudo -i -u openclaw
cd ~/openclaw
openclaw gateway run
  • Docker/sandbox failures: confirm Docker is running and sandbox images exist:

sudo systemctl status docker
sudo docker images | grep openclaw-sandbox

# Build sandbox image if missing (run from repo path)
cd /opt/openclaw/openclaw
sudo -u openclaw./scripts/sandbox-setup.sh

Common failure modes: incorrect file ownership under /opt/openclaw, missing Docker images, or systemd unit permission errors. Fix ownership with sudo chown -R openclaw:openclaw /opt/openclaw before retrying.

Operational cautions

  • SSH (port 22) is always allowed by the default firewall; ensure SSH access is secured (keys, bastion, or restricted IPs) before enabling other remote access.

  • The gateway is intentionally loopback/Tailscale-restricted—do not open the gateway port publicly unless you understand the implications.

  • Back up runtime state (~/.openclaw) before destructive operations or major upgrades.

Using Ansible for ongoing maintenance is an operational advantage: the repo becomes your single source of truth for configuration. Re-run the playbook when you want to apply updates or drift-correct hosts.

Docker: build, onboard, and run the containerized Gateway

Start by deciding whether you want an isolated, disposable Gateway container or a full local install. Docker is optional and well suited for throwaway environments, CI, or hosts where you cannot or prefer not to install Node and pnpm system-wide. The repository includes a small orchestration helper that builds (or pulls) a Gateway image, runs onboarding inside the container, writes a.env with the gateway token, and brings the Gateway up via docker compose.

Run the repository setup script to build and onboard the containerized Gateway (recommended quick path):

./scripts/docker/setup.sh

If you prefer to skip a local build and use a prebuilt image from a registry, set OPENCLAW_IMAGE before running the setup script. This speeds setup and avoids a local pnpm build:

export OPENCLAW_IMAGE="ghcr.io/openclaw/openclaw:latest"
./scripts/docker/setup.sh

Why onboarding must run inside the gateway entrypoint Onboarding and initial config writes must execute via the gateway container entrypoint (node dist/index.js) with the --no-deps flag. The reason is simple: the CLI shipped in the image is intended as a post-start tool; the correct initialization path runs the Gateway entrypoint to ensure config files, SecretRef handling, and token generation are applied to the container filesystem and compose volumes before the long-lived gateway process starts. The manual equivalent demonstrates this pattern.

Manual build + onboard + start If you want to run the steps yourself rather than using the helper script, build the image, run the onboarding entrypoint, set initial config, then start the service:

docker build -t openclaw:local -f Dockerfile.
docker compose run --rm --no-deps --entrypoint node openclaw-gateway \
 dist/index.js onboard --mode local --no-install-daemon
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://localhost:18789","http://127.0.0.1:18789"]}]'
docker compose up -d openclaw-gateway

Health probes and dashboard URL The Gateway exposes unauthenticated liveness and readiness endpoints on the Control UI port. Probe them from the host to validate the container:

curl -fsS http://127.0.0.1:18789/healthz # liveness
curl -fsS http://127.0.0.1:18789/readyz # readiness

To obtain the dashboard URL from within the compose network without opening a browser, run the CLI container:

docker compose run --rm openclaw-cli dashboard --no-open

Authenticated health check and operational probes For token-authenticated operations (health, gateway probe, devices list), run the CLI in the compose network and pass the saved token. The setup script writes the gateway token into.env inside the compose project; export it locally before invoking these commands:

docker compose exec openclaw-gateway node dist/index.js health --token "$OPENCLAW_GATEWAY_TOKEN"
docker compose run -T --rm openclaw-cli gateway probe
docker compose run -T --rm openclaw-cli devices list --json

Configure messaging channels from inside the compose network Use the CLI container to add channels once the Gateway container exists. WhatsApp pairing is interactive (QR); Telegram and Discord require tokens:

# WhatsApp (QR)
docker compose run --rm openclaw-cli channels login

# Telegram
docker compose run --rm openclaw-cli channels add --channel telegram --token "<token>"

# Discord
docker compose run --rm openclaw-cli channels add --channel discord --token "<token>"

Sandbox bootstrap opt-in and Docker socket override If you want the Gateway to manage sandbox backends (the sandbox backend uses Docker when enabled), opt in during setup by exporting OPENCLAW_SANDBOX. You can also override the Docker socket path the script uses (useful for rootless Docker or nonstandard socket hosts):

export OPENCLAW_SANDBOX=1
export OPENCLAW_DOCKER_SOCKET=/run/user/1000/docker.sock
./scripts/docker/setup.sh

If you set OPENCLAWEXTRAMOUNTS or OPENCLAWHOMEVOLUME, the setup helper writes docker-compose.extra.yml. Include it when you run docker compose with -f to ensure the volumes/mounts are applied.

Memory and build warnings Building the image runs pnpm install and can be OOM-killed on small hosts. Hosts with ~1 GB RAM commonly fail with exit 137 during pnpm install. For a reliable build, provide at least 2 GB of RAM or use the prebuilt registry image to avoid local builds.

Common fixes and diagnostics

  • If host-mounted state directories lead to permission errors in the container, change ownership to the container UID (1000):

sudo chown -R 1000:1000 /path/to/openclaw-config /path/to/openclaw-workspace
  • Install Playwright browsers inside the CLI container if you plan to use browser sandboxing or UI automation:

docker compose run --rm openclaw-cli \
 node /app/node_modules/playwright-core/cli.js install chromium
  • Run the repository sandbox helper if the project includes it:

scripts/sandbox-setup.sh

Quick diagnostic sequence A common diagnostic flow inside the compose network: show dashboard URL, list devices, and approve a pending device request:

docker compose run --rm openclaw-cli dashboard --no-open
docker compose run --rm openclaw-cli devices list
docker compose run --rm openclaw-cli devices approve <requestId>

Security considerations for public hosts If you place a Docker-based Gateway on a VPS or public host, harden the network exposure. Keep the Gateway bound to loopback when possible, restrict host firewall rules (Docker DOCKER-USER chain), and review the docker-compose ports mapping to avoid exposing the Control UI or WebSocket port directly to the Internet.

Sandbox defaults example If you want to set sandbox defaults in config JSON, use strict JSON. An example runtime agent defaults snippet:

{
 "agents": {
 "defaults": {
 "sandbox": {
 "mode": "non-main",
 "scope": "agent"
 }
 }
 }
}

This workflow covers the automated setup script, manual build/onboard sequence, health probes, sandbox opt-in, and the typical fixes you’ll need when running OpenClaw inside Docker.

ClawDock — shell helpers for local Docker development

ClawDock is a lightweight shell helper that wraps the common docker-compose steps you run for a local Docker-based OpenClaw gateway. It exposes short commands (clawdock-start, clawdock-dashboard, clawdock-devices, clawdock-approve, clawdock-show-config, etc.) so you can bring up the gateway, open the control UI, inspect configuration, and approve device pairings without typing long compose invocations or entering the container manually.

Install the helper by placing the provided script under your home directory and sourcing it from your shell rc. The snippet below is a runnable bash sequence that creates ~/.clawdock, downloads the helper, appends a source line to ~/.zshrc (adjust for bash/fish), and reloads the shell so the clawdock-* commands become available.

mkdir -p ~/.clawdock && curl -sL https://raw.githubusercontent.com/openclaw/openclaw/main/scripts/clawdock/clawdock-helpers.sh -o ~/.clawdock/clawdock-helpers.sh
echo 'source ~/.clawdock/clawdock-helpers.sh' >> ~/.zshrc && source ~/.zshrc

ClawDock relies on the same Docker configuration split used by the Docker install workflow: project-level environment values (project.env or.env alongside your compose file) for runtime knobs, ~/.openclaw/.env for provider secrets and sensitive credentials, per-agent auth-profiles.json for provider identities, and ~/.openclaw/openclaw.json for OpenClaw behavior and non-secret settings. clawdock-show-config prints the active.env files and openclaw.json but redacts secret values to reduce accidental exposure when you inspect configuration on a shared machine.

A typical first-time flow using ClawDock is intentionally short. Start the local compose stack, inject or repair the gateway token, then open the dashboard. The commands below are the usual sequence; clawdock-fix-token runs a convenience helper that sets the gateway token in the container so the dashboard can connect for onboarding.

clawdock-start
clawdock-fix-token
clawdock-dashboard

If the dashboard reports “pairing required” you can list pending device pairing requests and approve a request by id using the helper commands. This avoids entering the container to run device approval commands by hand:

clawdock-devices
clawdock-approve <request-id>

Warning: project and user.env files contain secrets. Do not cat or source them into untrusted shells. Use clawdock-show-config for quick, redacted checks and open the files only when you need to edit credentials.

ClawDock is a convenience layer; it’s not a replacement for understanding the underlying Docker compose files. When you need to debug networking, volumes, or health probes, fall back to the Docker section’s manual compose commands and logs troubleshooting. Use ClawDock for routine workflows and rapid local development; switch to manual compose for deep diagnostics or CI-oriented builds.

Podman: running OpenClaw rootless and systemd --user integration

Running OpenClaw under Podman lets you keep the Gateway process owned by your regular user while persisting runtime state on the host filesystem (~/.openclaw). This rootless model keeps permissions simple: on-disk state (sessions, configs, creds) lives under your home directory by default, and the container maps that same directory so the Gateway sees canonical paths.

Start by using the provided Podman helper scripts. The setup script builds the image, wires up mounts and env defaults, and can install a Quadlet unit for systemd --user auto-start. Run the setup helper with --quadlet to install the systemd user unit:

./scripts/podman/setup.sh --quadlet

The launch helper starts the container with sensible mounts and an allowlist of Podman-related environment keys. Use the launch command to bring the Gateway up:

./scripts/run-openclaw-podman.sh launch

To run onboarding (the interactive workspace/model/auth setup) inside the container immediately after launch, use the helper with the setup subcommand. This spawns the container and executes the same onboarding steps you would run on a native host:

./scripts/run-openclaw-podman.sh launch setup

When the Podman setup runs it creates or updates two host-side files if missing:

  • ~/.openclaw/openclaw.json with gateway.mode: "local"

  • ~/.openclaw/.env populated with an OPENCLAWGATEWAYTOKEN for container-host CLI use

For security, the launch helper passes a small allowlist of env vars (Podman-related keys) into the container instead of handing Podman your entire.env file. This reduces credential exposure while still enabling required runtime behavior.

If you want the host openclaw CLI to operate against the container by default, export OPENCLAW_CONTAINER with the container name the helpers use (openclaw):

export OPENCLAW_CONTAINER=openclaw

After that, host-side openclaw invocations are proxied into the running Podman container. Typical commands become:

openclaw dashboard --no-open
openclaw gateway status --deep # includes extra service scan
openclaw doctor
openclaw channels login

Quadlet integration: the setup script places a unit file for systemd --user at:

~/.config/containers/systemd/openclaw.container

When you edit that Quadlet, apply changes with the standard user-systemd sequence:

systemctl --user daemon-reload
systemctl --user restart openclaw.service

On headless or rebooting hosts, enable lingering so your user services persist without an interactive login:

sudo loginctl enable-linger "$(whoami)"

Networking recommendations and pitfalls

  • Publish container ports on 127.0.0.1 only. This keeps the Gateway loopback-bound and avoids accidental public exposure.

  • Prefer running Tailscale on the host and using Tailscale Serve or a host-level proxy rather than enabling gateway --tailscale serve inside the container. Host-managed Tailscale preserves identity and reduces NAT/traversal surprises.

  • Warning: on macOS you typically run a Podman VM/machine. That VM can make browsers appear non-local to the Gateway and cause device-auth or pairing failures. If you see device-auth errors, follow the remote-access guidance (use Tailscale or host proxies) rather than exposing the Gateway to 0.0.0.0.

These Podman helpers and Quadlet integration give you a repeatable, rootless deployment with persistent user services and a smooth host CLI experience.

Nix and deterministic installs (nix-openclaw)

A declarative, reproducible install eliminates drift: pin the OpenClaw binaries, macOS companion app, and supporting tools in a Nix flake and let Home Manager activate them. nix-openclaw supplies a batteries‑included Home Manager module that does exactly that — it provides a flake template which installs the Gateway, the macOS GUI bundle where applicable, and pinned tool artifacts so your workstation state is reproducible across machines.

Before you begin: ensure Nix itself is present. Use a determinate Nix installer (the single-file, fixed-output installer) to avoid bootstrapping nondeterminism; do this once before attempting to use the nix-openclaw flake. After Nix is available, create a local flake directory and copy the provided template (for example, the agent-first template) into it so you can customize the flake for your username, git remotes, and pinned inputs:

mkdir -p ~/code/openclaw-local
## Copy templates/agent-first/flake.nix from the nix-openclaw repo

Edit the flake to set the desired pinned versions and any Home Manager options (agents, macOS bundle settings, GUI defaults). When ready, activate the configuration with Home Manager. This runs the switch that creates symlinks, installs pinned packages, and writes any per-user launch config the module provides:

home-manager switch

Nix mode: OpenClaw exposes a runtime mode that makes the daemon and CLI behave safely under a declarative regime. Set OPENCLAWNIXMODE=1 in the environment to opt into Nix mode. In that mode OpenClaw disables auto-install and any self-mutation flows; instead it surfaces remediation instructions appropriate for Nix-managed systems so you can fix state from your flake and re-run home-manager:

export OPENCLAW_NIX_MODE=1

On macOS the GUI does not inherit your shell environment, so the GUI won't see OPENCLAWNIXMODE unless you make it persistent via defaults. To ensure the macOS app runs in Nix mode, write the preference key the nix-openclaw module expects:

defaults write ai.openclaw.mac openclaw.nixMode -bool true

Important rule: keep mutable runtime state and editable config out of the immutable Nix store. Configure OPENCLAWCONFIGPATH and OPENCLAWSTATEDIR to writable, Nix-managed locations (for example, $HOME/.local/openclaw/config and $HOME/.local/openclaw/state). Pointing runtime paths to these locations preserves reproducibility while allowing the Gateway to write logs, transcripts, and runtime artifacts without attempting to modify the Nix store.

If you need to change installed binaries or the GUI bundle, update the flake inputs and re-run home-manager switch; do not rely on the Gateway to self-upgrade when NIX mode is enabled.

Bun: experimental developer runtime notes

If you want faster TypeScript iteration or to experiment with an alternate JS runtime, Bun can run OpenClaw locally — but treat it as experimental and never as the production Gateway runtime. Bun has known incompatibilities with several provider integrations (notably some WhatsApp and Telegram adapters) and with tooling assumptions that OpenClaw’s test and CI flows make. For production and CI, use Node (recommended) and pnpm.

Bun ignores pnpm-lock.yaml. The repository intentionally avoids committing Bun lock artifacts (bun.lock / bun.lockb are kept out of version control) to prevent churn and divergent lockfiles. If you run Bun locally, expect that your install will not reproduce pnpm’s exact dependency resolution and that you must not commit Bun lockfiles to the repo.

If you want to try Bun without disturbing repository lockfiles, install dependencies without writing a lockfile:

Runnable command — install dependencies with Bun (experimental)

bun install

To avoid writing lockfiles into the working tree (safe for ephemeral experiments), pass --no-save:

Runnable command — do not write a lockfile

bun install --no-save

Many repository scripts and CI tasks still call pnpm directly (for example docs:build, ui:* tasks, protocol:check). When you need to run those scripts, prefer pnpm to avoid surprising failures.

Bun is conservative about running third-party package lifecycle scripts: it blocks lifecycle scripts by default for safety. Some packages used by providers execute build or install-time code (native bindings, code generation). If Bun blocks a lifecycle script you need, you can grant explicit trust to the package(s) so Bun will run their scripts. Treat this as a security decision: only trust packages you audit or understand.

Runnable command — trust package lifecycle scripts in Bun

bun pm trust @whiskeysockets/baileys protobufjs

You can use Bun to run build and test lifecycle scripts, which is convenient for local iteration. Example:

Runnable command — run build and tests with Bun

bun run build
bun run vitest run

Summary checklist

  • Use Node + pnpm for CI and production Gateway runtime.

  • Use Bun only for local experimentation or faster TypeScript runs.

  • Run bun install --no-save to avoid lockfile churn.

  • If Bun blocks a needed lifecycle script, run bun pm trust <packages> after verifying them.

  • When a task or script is still pnpm-centric, run it under pnpm to match CI behavior.

Health probes, sandbox opt-in, and quick security reminders

The fastest way to verify a running Control UI / Gateway is to hit the unprotected health endpoints. These endpoints require no auth and are suitable for liveness/readiness probes from container orchestrators or local scripts:

curl -fsS http://127.0.0.1:18789/healthz # liveness
curl -fsS http://127.0.0.1:18789/readyz # readiness

Sandbox bootstrap (the optional, agent-executed isolation layer) is explicitly opt-in. Set OPENCLAW_SANDBOX to a truthy value (1, true, yes, on) before running the Docker setup script to enable the sandbox bootstrap flow; the sandbox backend will use Docker when enabled:

export OPENCLAW_SANDBOX=1
./scripts/docker/setup.sh

If your environment uses a nonstandard Docker socket (for example a per-user socket under Podman or non-root Docker setups), export OPENCLAWDOCKERSOCKET to override the socket the setup script binds into the container:

export OPENCLAW_SANDBOX=1
export OPENCLAW_DOCKER_SOCKET=/run/user/1000/docker.sock
./scripts/docker/setup.sh

Security checklist and minimal hardening to apply after any container or host install:

  • OpenClaw’s installer and recommended Ansible playbooks set a four-layer defense model by default: UFW firewall rules that restrict inbound to SSH and Tailscale, Tailscale mesh for remote management, Docker isolation for sandboxes, and systemd hardening for the gateway service (NoNewPrivileges, PrivateTmp, running as an unprivileged openclaw user). Keep these layers enabled where possible.

  • Prefer keeping the gateway bound to loopback (127.0.0.1) and front it with a reverse-proxy or tunnel (SSH LocalForward, Tailscale Serve/Funnel). For Podman, keep published ports on 127.0.0.1 and prefer a host-managed Tailscale service instead of the gateway’s --tailscale serve mode.

  • If deploying to a VPS or any public host, explicitly review Docker DOCKER-USER and host firewall policies. Misconfigured DOCKER-USER rules can expose containers even when UFW is present.

  • Regularly run the health probes above from your orchestrator or a monitoring job; failing readyz signals configuration or provider onboarding problems.

Operational tip for permission errors when mounting host state into containers: ensure the mounted directories are owned by the container runtime UID (container user 1000 is common):

sudo chown -R 1000:1000 /path/to/openclaw-config /path/to/openclaw-workspace

After probes succeed and sandbox is enabled (if required), switch to the openclaw user (or connect to the container) to run onboarding and provider login steps described in the earlier install workflows.

Maintenance Runbook: Safe Updates, Migration, and Uninstall

Maintenance Overview and Safety Principles

Maintain a consistent, restorable state snapshot before any maintenance that mutates or moves runtime data. Stop the Gateway, create an archive of the entire state tree (including hidden files), verify the archive, and ensure ownership and permissions match the target runtime user. Treat archives as secrets: encrypt them in transit and at rest, and rotate credentials if you suspect exposure.

Preflight checklist (run before updates, migrations, or uninstall)

  • Stop the gateway process to prevent in-flight writes: openclaw gateway stop.

  • Confirm the state directory path (default: ~/.openclaw) and any workspace-specific directories you plan to include.

  • Archive the entire state tree, not just openclaw.json. Auth profiles, channel credentials, and provider artifacts live across hidden files and subdirectories.

  • Verify the archive integrity and size. Keep at least one separate copy before destructive operations.

  • Ensure the user on the destination machine will own and run the gateway; plan chown/chmod steps if you copied files as root.

  • Treat the archive as sensitive material: use encrypted transfer (scp with key, sftp over SSH, or an encrypted cloud bucket) and rotate keys if compromise is suspected.

  • Run openclaw doctor --repair (or at least openclaw doctor) before and after migration to surface configuration or platform discrepancies.

Why stop the Gateway first The Gateway continuously writes session transcripts, auth caches, and provider state. Copying files while those writes are active risks partial, inconsistent, or corrupted snapshots that break startup checks on the destination. Always stop the daemon and let filesystem I/O settle before taking the snapshot.

Create an archive of the full state tree The following runnable shell snippet stops the gateway and creates a compressed tarball of the user’s state directory. It preserves hidden files and directory structure.

openclaw gateway stop
cd ~
tar -czf openclaw-state.tgz.openclaw

Unpack on the destination host On the destination machine, extract the archive into the home directory of the user that will run OpenClaw. If you extracted as root, fix ownership before starting the Gateway.

cd ~
tar -xzf openclaw-state.tgz

Ownership and permission notes If you copied the archive or extracted it as root (for example via sudo or a privileged bootstrap), run chown -R user:group ~/.openclaw where user:group is the intended runtime account. Failing to adjust ownership can prevent the Gateway daemon or service from reading keys, writing logs, or creating sockets.

Security and handling of archives Backups contain provider API keys, channel credentials, and device pairing secrets. Encrypt archives with a strong key before transmission (e.g., gpg symmetric or an encrypted object store). Store backups with an access policy and rotate any credentials if an archive may have been exposed.

When in doubt, run openclaw doctor and gateway status after restoring state and before opening the service to public access. These checks surface common permission, config, and provider-auth problems so you can fix them before traffic arrives.

Matrix Migration: Snapshot, Verify, and Limitations

OpenClaw protects you from accidental data loss during Matrix plugin upgrades by ensuring a recovery snapshot exists before it changes any on-disk Matrix state. The migration code will either create a fresh snapshot or reuse a previously-created one that matches the same migration run. If OpenClaw cannot produce that snapshot, it will skip the migration for that run rather than proceed without a recovery point.

A successful pre-migration snapshot is recorded by writing a marker file at ~/.openclaw/matrix/migration-snapshot.json. Presence of this file indicates the archival step completed and later migration passes will reuse the same archive instead of re-snapshotting.

What the automatic migration preserves

  • The plugin identity: @openclaw/matrix remains associated with the migrated data.

  • The channel name and configuration namespace: channels.matrix and its config keys are preserved.

  • Credential cache: files under ~/.openclaw/credentials/matrix/ are copied or retained.

  • Runtime stores: the plugin runtime layout under ~/.openclaw/matrix/ is preserved where possible.

Legacy-store consolidation When OpenClaw finds an older flat Matrix sync/crypto store, it will attempt to relocate the oldest flat stores into the newer account-scoped layout. This consolidation only occurs when OpenClaw can safely resolve the target Matrix account. For a flat legacy store that has no account-scoped identity, automatic migration will attempt to map it into one resolved account and will move the store contents into that account’s scoped directory.

Multi-account constraint A single flat legacy store may be migrated into only one resolved Matrix account. If you previously kept separate account-scoped stores, each is processed independently. If multiple accounts reasonably claim the same legacy data, OpenClaw will not silently duplicate or split the flat store — the operator must reconcile which account should own that legacy history.

Irrecoverable items — strong warning Local-only room encryption keys that were never uploaded to the homeserver cannot be reconstructed by OpenClaw. If encrypted history depended on keys stored only on another device and that device’s keys were not backed up to the homeserver, those rooms’ history may remain unreadable after migration. Treat this as irreversible: if you depend on any local-only keys, ensure you have exported or recovered them before migration.

Custom installs and doctor warnings If you installed the Matrix plugin from a custom path (for example pinned to a repository path), OpenClaw’s automatic migration may not handle that layout. Startup and openclaw doctor will surface these installs as warnings; you must manually migrate files for those cases.

Operational sequences — safe workflow

Pre-check current status and backups. Confirm plugin and backup status:

openclaw matrix verify status
openclaw matrix verify backup status

Run the verbose variants when you need diagnostic details (these logs may include sensitive tokens; store them securely):

openclaw matrix verify status --verbose
openclaw matrix verify backup status --verbose

If you need to restore a homeserver backup (have a recovery key), run:

openclaw matrix verify backup restore --recovery-key "<your-recovery-key>"

After a restore, re-run status checks to confirm keys and backups are healthy.

Device verification. If you must confirm a device or run verification tooling:

openclaw matrix verify device "<your-recovery-key>"

If you need to reset backup metadata (destructive), confirm and run:

openclaw matrix verify backup reset --yes
openclaw matrix verify backup status --verbose
openclaw matrix verify status

The combined flow above resets, then reports backup status and verification state.

Automatic repairs and migrations are exposed via the doctor command. If pre-checks look good, let doctor attempt safe fixes (it honors the snapshot rule above):

openclaw doctor --fix

Doctor will create/reuse the migration snapshot before making state changes. If snapshot creation fails, doctor will skip matrix migration and report the failure — do not attempt manual state changes unless you have a verified backup.

Failure modes and audit points

  • If snapshot creation fails, migration is skipped. Inspect openclaw doctor output and the directory ~/.openclaw/matrix/ for partial changes; do not assume migration succeeded.

  • After any migration or restore, validate the existence of ~/.openclaw/matrix/migration-snapshot.json and re-run openclaw matrix verify status.

  • Keep verbose diagnostic logs in a secure location; they may include homeserver tokens, recovery keys (if provided in commands), or other sensitive metadata.

When in doubt, stop the Gateway, snapshot the entire ~/.openclaw directory (tar + checksum), and only then run doctor --fix or the verify/restore commands. That simple snapshot remains your last-resort recovery point if anything goes wrong.

Full System Migration: Copying the State Directory

A safe migration means copying the entire runtime state while the Gateway is quiescent, then verifying the new host can run the same runtime with the same profile and permissions. Stop services, snapshot everything (including hidden files), transfer securely, fix ownership, run the built-in health and migration checks, then restart and verify.

Pre-copy: stop the gateway and create an archive Stop the gateway on the source host so no files change during copy. Then create a tarball from the user home that preserves hidden OpenClaw state (.openclaw) and file metadata.

The following runnable shell snippets stop the daemon and archive the state directory on the source machine:

openclaw gateway stop
cd ~
tar -czf openclaw-state.tgz.openclaw

Transfer the archive securely Treat the archive as highly sensitive (it contains auth profiles, channel credentials, and provider state). Use an encrypted transfer channel (scp over SSH, rsync over SSH, or a secure cloud storage bucket with server-side encryption). Avoid plaintext email or public object storage without encryption.

Extract and fix ownership on the destination On the destination host extract into the target user's home directory. If you copied the archive as root or via a different account, you must correct ownership so the runtime user can read/write the files. Typical fixes are chown -R user:group ~/.openclaw and suitable chmod adjustments for private keys.

Extract example (runnable on destination):

cd ~
tar -xzf openclaw-state.tgz

If you extracted as root and the runtime will run as your non-root user, fix ownership:

sudo chown -R youruser:yourgroup ~/.openclaw

Profile and state-dir constraint If the source gateway ran with a non-default profile (--profile or OPENCLAWSTATEDIR), channels and auth can look logged out when you start the Gateway without the same profile or state dir. Either launch the gateway with the same --profile/OPENCLAWSTATEDIR used on the source, or rename/move the migrated state into the default state dir on the destination and ensure openclaw is started with the intended profile.

Post-copy checks: doctor, restart, verify Run the doctor command so OpenClaw can apply any on-disk migrations and flag repairs. Then restart the gateway and confirm status.

Run these commands on the destination (runnable):

openclaw doctor
openclaw gateway restart
openclaw status

Security and rollback notes Backups and migration archives contain credentials. Encrypt archives at rest and in transit (e.g., use gpg symmetric encryption or an encrypted storage bucket). If an archive is suspected exposed, rotate any provider keys and channel credentials after restoring, and treat the archive as compromised. Keep a retention policy and delete transient archives once the migration is verified.

Special-case: Matrix or other channel plugins Some channel adapters (Matrix room keys, device-specific tokens) require plugin-specific verification after migration. After the gateway is running, run channel-specific status and pairing checks (openclaw channels status / openclaw devices list) and re-run any channel pairing flows if the adapter reports missing keys.

Quick checklist

  • Pre-copy: stop gateway, archive entire ~/.openclaw

  • Transfer: use encrypted channel, avoid exposing the archive

  • Post-copy: extract, chown/chmod as runtime user, run openclaw doctor, restart, verify status

  • If profile/state-dir differs: start gateway with the original profile or relocate the state

  • If compromise suspected: rotate credentials and delete archives

Following these steps preserves runtime continuity and makes rollback straightforward: keep the original machine offline (or its stopped archive) until verification completes.

Release Channels and One-off Tags

OpenClaw publishes three distinct update channels. Choose the channel that matches your risk tolerance and operational needs before you start updating a production node.

  • stable — the production channel. For package installs this follows the npm dist-tag "latest" and is the conservative default.

  • beta — a pre-release channel published to the npm dist-tag "beta". When a beta dist-tag is absent or points to an older build, installs using the beta channel may fall back to the stable/latest artifact; the beta channel is intended for testing and early validation.

  • dev — a development workflow that installs from a git checkout (typically the repository's main branch) rather than a packaged npm dist-tag. The dev flow checks out, rebases, builds and installs from source.

The npm dist-tags (latest, beta, etc.) are authoritative for package installs. Project maintainers often promote a build to the "latest" dist-tag without changing package version numbers; that behavior is how a new stable build can be moved into production without a numeric version bump.

Persisted channel vs one-off tag --channel sets a persistent setting. It writes update.channel into the OpenClaw config and changes how subsequent update operations resolve targets (package vs git behavior included). Example:

openclaw update --channel stable
openclaw update --channel beta
openclaw update --channel dev

--tag performs a single-run override and is not persisted. It accepts an npm dist-tag, a version, or a package spec. Important: --tag only applies to package installs (npm tarballs/dist-tags); it is ignored for git-based dev installs. Examples of one-off runs:

# Install a specific version
openclaw update --tag 2026.4.1-beta.1

# One-off install from the beta dist-tag (does not persist)
openclaw update --tag beta

# One-off install targeting GitHub main (npm tarball)
openclaw update --tag main

# Explicit package spec
openclaw update --tag openclaw@2026.4.1-beta.1

Dev channel mechanics When you select dev (--channel dev) OpenClaw will operate from a git checkout (default location is ~/openclaw unless overridden via OPENCLAWGITDIR). The dev update flow will switch to main, rebase on upstream, build, and install the CLI from that checkout. This requires a working git toolchain and any build tools (pnpm bootstrap/build) used by the repository; it is not a simple npm dist-tag install.

Preview and verify before applying Always preview an update plan before mutating a production node. Use --dry-run to see the effective channel, target version or source, and whether the update would require downgrade confirmation. Combine with --json for machine-readable output:

openclaw update --dry-run
openclaw update --channel beta --dry-run
openclaw update --tag 2026.4.1-beta.1 --dry-run
openclaw update --dry-run --json

Query current state at any time:

openclaw update status

Operational guidance

  • Use stable for production; use beta for evaluation clusters and staging; use dev only for developer or CI nodes that can tolerate transient failures.

  • If you need a single, non-persistent test of a dist-tag, use --tag instead of changing persistent configuration.

  • Be aware: a beta dist-tag may be absent or older. The beta channel may therefore fall back to latest; using --tag beta targets the dist-tag exactly for that run.

  • Warning: beta and dev builds may omit a macOS app artifact. It is acceptable to publish tags without a macOS build, but release notes should call that out so operators aren't surprised.

Preview, snapshot, and rollback steps (recommended)

openclaw update --dry-run (inspect target).

Take a backup or snapshot of ~/.openclaw and any host service state.

Run openclaw update (or install) on a single node; validate with openclaw update status and openclaw doctor.

If rollback is necessary, reinstall the prior dist-tag/version via --tag or switch channel back and re-run update.

These controls let you balance safe maintenance with the flexibility to test pre-release and development builds when necessary.

Updating, Auto-updater, and Rollback Procedures

Keep updates predictable and reversible: prefer the built-in updater for routine upgrades, run a dry-run first, snapshot state, then verify with the diagnostic flow. The updater understands how OpenClaw was installed and performs the appropriate fetch-and-apply steps, runs post-update migrations, and restarts the Gateway when finished.

Run the canonical update command to fetch and apply the recommended update flow. This command auto-detects whether you installed via package manager or source and will attempt the correct steps for your environment.

openclaw update

Preview an update before applying it. Use --dry-run to see what would change. You can also target channels or specific tags when you want to control what gets applied.

openclaw update --channel beta
openclaw update --tag main
openclaw update --dry-run # preview without applying

If openclaw update is not suitable for your environment you can re-run the installer script or update the global package manually. Re-running the installer is a pragmatic alternative that behaves like a fresh install but will preserve state under ~/.openclaw unless you explicitly remove it.

curl -fsSL https://openclaw.ai/install.sh | bash

Manual package updates (global) are supported for npm, pnpm, and bun:

npm i -g openclaw@latest
pnpm add -g openclaw@latest
bun add -g openclaw@latest

Auto-updater configuration is off by default. Enable it only after you’ve validated updates in a staging environment and are comfortable with automatic restarts. Place this JSON in ~/.openclaw/openclaw.json to enable and control timing:

{
 "update": {
 "channel": "stable",
 "auto": {
 "enabled": true,
 "stableDelayHours": 6,
 "stableJitterHours": 12,
 "betaCheckIntervalHours": 1
 }
 }
}
  • stableDelayHours: how long the node waits after a stable release becomes available before attempting apply.

  • stableJitterHours: a deterministic spread window applied across fleet nodes so upgrades are staggered and not simultaneous.

  • betaCheckIntervalHours: frequency to poll and apply beta channel updates (applies immediately when found).

  • dev channel: not auto-applied.

Practice the pre-check / action / post-check pattern on every update:

  • Pre-check: snapshot runtime state (tar -czf openclaw-state.tgz ~/.openclaw), run openclaw update --dry-run, and ensure you have a current backup.

  • Action: run openclaw update (or your chosen manual method).

  • Post-check: run openclaw doctor, restart the gateway, and verify health.

openclaw doctor
openclaw gateway restart
openclaw health

Rollback options

  • Package rollback (npm): pin to a published version, then run doctor and restart.

npm i -g openclaw@<version>
openclaw doctor
openclaw gateway restart
  • Source rollback: check out a pinned commit or an earlier date, rebuild, and restart.

git fetch origin
git checkout "$(git rev-list -n 1 --before="2026-01-01" origin/main)"
pnpm install && pnpm build
openclaw gateway restart

Troubleshooting notes

  • If you run openclaw update --channel dev on a source checkout and encounter pnpm/corepack bootstrap errors, either install pnpm manually or enable corepack before retrying. The updater attempts to auto-bootstraps pnpm when possible, but source checkouts can require an explicit pnpm install.

  • For sensitive production systems prefer manual updates and staged rollouts. Use stableDelayHours + stableJitterHours to spread automatic upgrades across nodes when auto-updater is enabled.

A disciplined dry-run, a saved state snapshot, and the doctor → restart → health verification sequence are the minimal safety net for reliable updates and fast rollback.

Uninstall: Built-in and Manual Removal

If the OpenClaw CLI binary is available, use the built-in uninstaller — it handles stopping the daemon, removing the installed service, and cleaning up common runtime state. For a simple interactive uninstall run:

openclaw uninstall

For automation or CI scripts use the non-interactive flags; this runs the same flow without prompts:

openclaw uninstall --all --yes --non-interactive
npx -y openclaw uninstall --all --yes --non-interactive

Before you remove anything, stop the gateway and snapshot any data you might later need. Back up ~/.openclaw (or any profile-specific state dirs) if you want to preserve workspaces, agent transcripts, or credentials. These uninstall steps permanently delete local credentials and state.

If the CLI is missing or you prefer doing steps manually, follow this safe sequence: stop the running gateway, remove the installed service/unit, then delete state and workspace directories. Use the CLI to stop/uninstall where available:

openclaw gateway stop
openclaw gateway uninstall

Platform-specific manual removal

  • macOS (launchd user agent)

  • Stop the user agent and remove the LaunchAgent plist. These exact commands stop the running service and remove the plist from ~/Library/LaunchAgents:

launchctl bootout gui/$UID/ai.openclaw.gateway
rm -f ~/Library/LaunchAgents/ai.openclaw.gateway.plist
  • Linux (systemd --user)

  • Stop and disable the systemd user unit, remove the unit file, then reload the user daemon:

systemctl --user disable --now openclaw-gateway.service
rm -f ~/.config/systemd/user/openclaw-gateway.service
systemctl --user daemon-reload
  • Windows (Scheduled Task)

  • Remove the scheduled task and the gateway script placed in the state directory:

schtasks /Delete /F /TN "OpenClaw Gateway"
Remove-Item -Force "$env:USERPROFILE\.openclaw\gateway.cmd"

After service removal delete state and workspace. The following command removes the default state dir; it respects OPENCLAWSTATEDIR if set:

rm -rf "${OPENCLAW_STATE_DIR:-$HOME/.openclaw}"

Remove the workspace directory separately if you keep it outside the main state path:

rm -rf ~/.openclaw/workspace

If you set OPENCLAWCONFIGPATH to a file outside the state directory, that file is not removed by the previous steps — you must delete it explicitly. If you used profiles (--profile or OPENCLAW_PROFILE), state lives under profile-aware directories (for example ~/.openclaw-<profile>); repeat deletion for each profile you created.

Finally, uninstall any global CLI package using the package manager you originally used:

npm rm -g openclaw
pnpm remove -g openclaw
bun remove -g openclaw

If you installed from a git checkout, uninstall the gateway service before deleting the repository directory. Then delete the repo and state/workspace directories.

Checklist before destructive actions

  • Stop gateway and confirm no running processes.

  • Create a backup archive of ~/.openclaw if you may need data later.

  • Ensure you know where OPENCLAWCONFIGPATH and profile-specific state dirs live.

  • Remove service/unit (platform specific) then delete state, workspace, and global CLI.

Warning: these steps permanently destroy local data and credentials. Take a backup if you think you may restore agents, transcripts, or provider auth later.

Post-change Verification and Troubleshooting

Before you trust an updated Gateway or a migrated backing store, perform a short, repeatable verification ladder. The goal is to confirm the update/migration completed, apply any automated repairs, restart the runtime cleanly, and validate health—then capture logs if something failed. Follow this order for predictable outcomes.

Start with a dry-run and status checks Run a dry-run to preview what an updater would do. This shows the effective channel, target version or tag, and whether a downgrade would prompt confirmation. Use --json when you need machine-readable output for automation or audit logs.

openclaw update --dry-run
openclaw update --channel beta --dry-run
openclaw update --tag 2026.4.1-beta.1 --dry-run
openclaw update --dry-run --json

Check the active update metadata before and after any operation:

openclaw update status

Apply automated repairs and migrations OpenClaw ships a diagnostic tool that can apply conservative repairs and trigger supported on-disk migrations (Matrix migration being an example). Run the doctor tool as a read-only check, and run doctor --fix to let the Gateway apply fixes the tool recommends. The doctor command is the single most useful first-line remediation after an update.

The following runnable shell command invokes the automated repair/migration pass:

openclaw doctor --fix

Matrix migration snapshot rule Before any step that mutates Matrix on-disk state, OpenClaw creates (or reuses) a focused recovery snapshot. If a migration cannot snapshot the pre-migration state, the migration will be skipped: stop the Gateway and create a manual backup first, then retry the migration. If the doctor reports that a Matrix migration was skipped due to snapshot failure, follow the full Matrix migration procedure in the Matrix migration section—do not attempt forceful in-place edits.

Restart and verify the Gateway After doctor and any fixes complete, restart the Gateway so the runtime loads the new code and migrated state:

openclaw gateway restart

Then check runtime health:

openclaw health

If health reports warnings or failures, capture logs (and redact secrets) before escalating. Useful log sources include the systemd/user journal or files under ~/.openclaw/logs. When asking for help, include output from openclaw doctor, openclaw update status, openclaw health, and the last 200–500 log lines.

Common troubleshooting notes

  • Profile/state-dir mismatches often present as channels appearing “logged out” or missing pairings after an upgrade. Confirm you’re running the Gateway under the same profile and state-dir used prior to the change.

  • If openclaw update --channel dev or a source checkout run errors with pnpm/corepack bootstrap failures, manually install pnpm or re-enable corepack and retry; the updater tries to auto-bootstrap pnpm but that can fail in developer checkouts. Example remedies: install pnpm globally or run corepack enable && corepack prepare pnpm@latest --activate.

  • If automated fixes don’t resolve the issue, stop the Gateway, create a backup (tar the ~/.openclaw directory), and follow the more detailed migration or rollback procedures.

Always redact credentials and share only the minimal logs needed when requesting external support.

Download the Entire book as pdf here:

This post is for paid subscribers

Already a paid subscriber? Sign in
© 2026 Onepagecode · Privacy ∙ Terms ∙ Collection notice
Start your SubstackGet the app
Substack is the home for great culture