重构主控编排与运行时预热链路,统一工作区提示词/专家调度协议并补齐 wiki 记忆注入与写回闭环。

同时收敛启动与运维脚本默认行为(含 wiki worker)、更新 Admin 可观测性与相关测试,降低首轮时延并提高运行稳定性。

Made-with: Cursor
This commit is contained in:
oliver 2026-04-26 08:34:33 +08:00
parent 4a23b715a2
commit dbbe3add6a
14438 changed files with 2693620 additions and 2546 deletions

View file

@ -0,0 +1,230 @@
---
summary: "Automated, hardened OpenClaw installation with Ansible, Tailscale VPN, and firewall isolation"
read_when:
- You want automated server deployment with security hardening
- You need firewall-isolated setup with VPN access
- You're deploying to remote Debian/Ubuntu servers
title: "Ansible"
---
# Ansible Installation
Deploy OpenClaw to production servers with **[openclaw-ansible](https://github.com/openclaw/openclaw-ansible)** -- an automated installer with security-first architecture.
<Info>
The [openclaw-ansible](https://github.com/openclaw/openclaw-ansible) repo is the source of truth for Ansible deployment. This page is a quick overview.
</Info>
## Prerequisites
| Requirement | Details |
| ----------- | --------------------------------------------------------- |
| **OS** | Debian 11+ or Ubuntu 20.04+ |
| **Access** | Root or sudo privileges |
| **Network** | Internet connection for package installation |
| **Ansible** | 2.14+ (installed automatically by the quick-start script) |
## What You Get
- **Firewall-first security** -- UFW + Docker isolation (only SSH + Tailscale accessible)
- **Tailscale VPN** -- secure remote access without exposing services publicly
- **Docker** -- isolated sandbox containers, localhost-only bindings
- **Defense in depth** -- 4-layer security architecture
- **Systemd integration** -- auto-start on boot with hardening
- **One-command setup** -- complete deployment in minutes
## Quick Start
One-command install:
```bash
curl -fsSL https://raw.githubusercontent.com/openclaw/openclaw-ansible/main/install.sh | bash
```
## What Gets Installed
The Ansible playbook installs and configures:
1. **Tailscale** -- mesh VPN for secure remote access
2. **UFW firewall** -- SSH + Tailscale ports only
3. **Docker CE + Compose V2** -- for agent sandboxes
4. **Node.js 24 + pnpm** -- runtime dependencies (Node 22 LTS, currently `22.14+`, remains supported)
5. **OpenClaw** -- host-based, not containerized
6. **Systemd service** -- auto-start with security hardening
<Note>
The gateway runs directly on the host (not in Docker), but agent sandboxes use Docker for isolation. See [Sandboxing](/gateway/sandboxing) for details.
</Note>
## Post-Install Setup
<Steps>
<Step title="Switch to the openclaw user">
```bash
sudo -i -u openclaw
```
</Step>
<Step title="Run the onboarding wizard">
The post-install script guides you through configuring OpenClaw settings.
</Step>
<Step title="Connect messaging providers">
Log in to WhatsApp, Telegram, Discord, or Signal:
```bash
openclaw channels login
```
</Step>
<Step title="Verify the installation">
```bash
sudo systemctl status openclaw
sudo journalctl -u openclaw -f
```
</Step>
<Step title="Connect to Tailscale">
Join your VPN mesh for secure remote access.
</Step>
</Steps>
### Quick Commands
```bash
# 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
```
## Security Architecture
The deployment uses a 4-layer defense model:
1. **Firewall (UFW)** -- only SSH (22) + Tailscale (41641/udp) exposed publicly
2. **VPN (Tailscale)** -- gateway accessible only via VPN mesh
3. **Docker isolation** -- DOCKER-USER iptables chain prevents external port exposure
4. **Systemd hardening** -- NoNewPrivileges, PrivateTmp, unprivileged user
To verify your external attack surface:
```bash
nmap -p- YOUR_SERVER_IP
```
Only port 22 (SSH) should be open. All other services (gateway, Docker) are locked down.
Docker is installed for agent sandboxes (isolated tool execution), not for running the gateway itself. See [Multi-Agent Sandbox and Tools](/tools/multi-agent-sandbox-tools) for sandbox configuration.
## Manual Installation
If you prefer manual control over the automation:
<Steps>
<Step title="Install prerequisites">
```bash
sudo apt update && sudo apt install -y ansible git
```
</Step>
<Step title="Clone the repository">
```bash
git clone https://github.com/openclaw/openclaw-ansible.git
cd openclaw-ansible
```
</Step>
<Step title="Install Ansible collections">
```bash
ansible-galaxy collection install -r requirements.yml
```
</Step>
<Step title="Run the playbook">
```bash
./run-playbook.sh
```
Alternatively, run directly and then manually execute the setup script afterward:
```bash
ansible-playbook playbook.yml --ask-become-pass
# Then run: /tmp/openclaw-setup.sh
```
</Step>
</Steps>
## Updating
The Ansible installer sets up OpenClaw for manual updates. See [Updating](/install/updating) for the standard update flow.
To re-run the Ansible playbook (for example, for configuration changes):
```bash
cd openclaw-ansible
./run-playbook.sh
```
This is idempotent and safe to run multiple times.
## Troubleshooting
<AccordionGroup>
<Accordion title="Firewall blocks my connection">
- Ensure you can access via Tailscale VPN first
- SSH access (port 22) is always allowed
- The gateway is only accessible via Tailscale by design
</Accordion>
<Accordion title="Service will not start">
```bash
# Check logs
sudo journalctl -u openclaw -n 100
# Verify permissions
sudo ls -la /opt/openclaw
# Test manual start
sudo -i -u openclaw
cd ~/openclaw
openclaw gateway run
```
</Accordion>
<Accordion title="Docker sandbox issues">
```bash
# Verify Docker is running
sudo systemctl status docker
# Check sandbox image
sudo docker images | grep openclaw-sandbox
# Build sandbox image if missing
cd /opt/openclaw/openclaw
sudo -u openclaw ./scripts/sandbox-setup.sh
```
</Accordion>
<Accordion title="Provider login fails">
Make sure you are running as the `openclaw` user:
```bash
sudo -i -u openclaw
openclaw channels login
```
</Accordion>
</AccordionGroup>
## Advanced Configuration
For detailed security architecture and troubleshooting, see the openclaw-ansible repo:
- [Security Architecture](https://github.com/openclaw/openclaw-ansible/blob/main/docs/security.md)
- [Technical Details](https://github.com/openclaw/openclaw-ansible/blob/main/docs/architecture.md)
- [Troubleshooting Guide](https://github.com/openclaw/openclaw-ansible/blob/main/docs/troubleshooting.md)
## Related
- [openclaw-ansible](https://github.com/openclaw/openclaw-ansible) -- full deployment guide
- [Docker](/install/docker) -- containerized gateway setup
- [Sandboxing](/gateway/sandboxing) -- agent sandbox configuration
- [Multi-Agent Sandbox and Tools](/tools/multi-agent-sandbox-tools) -- per-agent isolation

View file

@ -0,0 +1,311 @@
---
summary: "Run OpenClaw Gateway 24/7 on an Azure Linux VM with durable state"
read_when:
- You want OpenClaw running 24/7 on Azure with Network Security Group hardening
- You want a production-grade, always-on OpenClaw Gateway on your own Azure Linux VM
- You want secure administration with Azure Bastion SSH
title: "Azure"
---
# OpenClaw on Azure Linux VM
This guide sets up an Azure Linux VM with the Azure CLI, applies Network Security Group (NSG) hardening, configures Azure Bastion for SSH access, and installs OpenClaw.
## What you will do
- Create Azure networking (VNet, subnets, NSG) and compute resources with the Azure CLI
- Apply Network Security Group rules so VM SSH is allowed only from Azure Bastion
- Use Azure Bastion for SSH access (no public IP on the VM)
- Install OpenClaw with the installer script
- Verify the Gateway
## What you need
- An Azure subscription with permission to create compute and network resources
- Azure CLI installed (see [Azure CLI install steps](https://learn.microsoft.com/cli/azure/install-azure-cli) if needed)
- An SSH key pair (the guide covers generating one if needed)
- ~20-30 minutes
## Configure deployment
<Steps>
<Step title="Sign in to Azure CLI">
```bash
az login
az extension add -n ssh
```
The `ssh` extension is required for Azure Bastion native SSH tunneling.
</Step>
<Step title="Register required resource providers (one-time)">
```bash
az provider register --namespace Microsoft.Compute
az provider register --namespace Microsoft.Network
```
Verify registration. Wait until both show `Registered`.
```bash
az provider show --namespace Microsoft.Compute --query registrationState -o tsv
az provider show --namespace Microsoft.Network --query registrationState -o tsv
```
</Step>
<Step title="Set deployment variables">
```bash
RG="rg-openclaw"
LOCATION="westus2"
VNET_NAME="vnet-openclaw"
VNET_PREFIX="10.40.0.0/16"
VM_SUBNET_NAME="snet-openclaw-vm"
VM_SUBNET_PREFIX="10.40.2.0/24"
BASTION_SUBNET_PREFIX="10.40.1.0/26"
NSG_NAME="nsg-openclaw-vm"
VM_NAME="vm-openclaw"
ADMIN_USERNAME="openclaw"
BASTION_NAME="bas-openclaw"
BASTION_PIP_NAME="pip-openclaw-bastion"
```
Adjust names and CIDR ranges to fit your environment. The Bastion subnet must be at least `/26`.
</Step>
<Step title="Select SSH key">
Use your existing public key if you have one:
```bash
SSH_PUB_KEY="$(cat ~/.ssh/id_ed25519.pub)"
```
If you don't have an SSH key yet, generate one:
```bash
ssh-keygen -t ed25519 -a 100 -f ~/.ssh/id_ed25519 -C "you@example.com"
SSH_PUB_KEY="$(cat ~/.ssh/id_ed25519.pub)"
```
</Step>
<Step title="Select VM size and OS disk size">
```bash
VM_SIZE="Standard_B2as_v2"
OS_DISK_SIZE_GB=64
```
Choose a VM size and OS disk size available in your subscription and region:
- Start smaller for light usage and scale up later
- Use more vCPU/RAM/disk for heavier automation, more channels, or larger model/tool workloads
- If a VM size is unavailable in your region or subscription quota, pick the closest available SKU
List VM sizes available in your target region:
```bash
az vm list-skus --location "${LOCATION}" --resource-type virtualMachines -o table
```
Check your current vCPU and disk usage/quota:
```bash
az vm list-usage --location "${LOCATION}" -o table
```
</Step>
</Steps>
## Deploy Azure resources
<Steps>
<Step title="Create the resource group">
```bash
az group create -n "${RG}" -l "${LOCATION}"
```
</Step>
<Step title="Create the network security group">
Create the NSG and add rules so only the Bastion subnet can SSH into the VM.
```bash
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 "${NSG_NAME}" \
-n AllowSshFromBastionSubnet --priority 100 \
--access Allow --direction Inbound --protocol Tcp \
--source-address-prefixes "${BASTION_SUBNET_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
```
The rules are evaluated by priority (lowest number first): Bastion traffic is allowed at 100, then all other SSH is blocked at 110 and 120.
</Step>
<Step title="Create the virtual network and subnets">
Create the VNet with the VM subnet (NSG attached), then add the Bastion subnet.
```bash
az network vnet create \
-g "${RG}" -n "${VNET_NAME}" -l "${LOCATION}" \
--address-prefixes "${VNET_PREFIX}" \
--subnet-name "${VM_SUBNET_NAME}" \
--subnet-prefixes "${VM_SUBNET_PREFIX}"
# Attach the NSG to the VM subnet
az network vnet subnet update \
-g "${RG}" --vnet-name "${VNET_NAME}" \
-n "${VM_SUBNET_NAME}" --nsg "${NSG_NAME}"
# AzureBastionSubnet — name is required by Azure
az network vnet subnet create \
-g "${RG}" --vnet-name "${VNET_NAME}" \
-n AzureBastionSubnet \
--address-prefixes "${BASTION_SUBNET_PREFIX}"
```
</Step>
<Step title="Create the VM">
The VM has no public IP. SSH access is exclusively through Azure Bastion.
```bash
az vm create \
-g "${RG}" -n "${VM_NAME}" -l "${LOCATION}" \
--image "Canonical:ubuntu-24_04-lts:server:latest" \
--size "${VM_SIZE}" \
--os-disk-size-gb "${OS_DISK_SIZE_GB}" \
--storage-sku StandardSSD_LRS \
--admin-username "${ADMIN_USERNAME}" \
--ssh-key-values "${SSH_PUB_KEY}" \
--vnet-name "${VNET_NAME}" \
--subnet "${VM_SUBNET_NAME}" \
--public-ip-address "" \
--nsg ""
```
`--public-ip-address ""` prevents a public IP from being assigned. `--nsg ""` skips creating a per-NIC NSG (the subnet-level NSG handles security).
**Reproducibility:** The command above uses `latest` for the Ubuntu image. To pin a specific version, list available versions and replace `latest`:
```bash
az vm image list \
--publisher Canonical --offer ubuntu-24_04-lts \
--sku server --all -o table
```
</Step>
<Step title="Create Azure Bastion">
Azure Bastion provides managed SSH access to the VM without exposing a public IP. Standard SKU with tunneling is required for CLI-based `az network bastion ssh`.
```bash
az network public-ip create \
-g "${RG}" -n "${BASTION_PIP_NAME}" -l "${LOCATION}" \
--sku Standard --allocation-method Static
az network bastion create \
-g "${RG}" -n "${BASTION_NAME}" -l "${LOCATION}" \
--vnet-name "${VNET_NAME}" \
--public-ip-address "${BASTION_PIP_NAME}" \
--sku Standard --enable-tunneling true
```
Bastion provisioning typically takes 5-10 minutes but can take up to 15-30 minutes in some regions.
</Step>
</Steps>
## Install OpenClaw
<Steps>
<Step title="SSH into the VM through Azure Bastion">
```bash
VM_ID="$(az vm show -g "${RG}" -n "${VM_NAME}" --query id -o tsv)"
az network bastion ssh \
--name "${BASTION_NAME}" \
--resource-group "${RG}" \
--target-resource-id "${VM_ID}" \
--auth-type ssh-key \
--username "${ADMIN_USERNAME}" \
--ssh-key ~/.ssh/id_ed25519
```
</Step>
<Step title="Install OpenClaw (in the VM shell)">
```bash
curl -fsSL https://openclaw.ai/install.sh -o /tmp/install.sh
bash /tmp/install.sh
rm -f /tmp/install.sh
```
The installer installs Node LTS and dependencies if not already present, installs OpenClaw, and launches the onboarding wizard. See [Install](/install) for details.
</Step>
<Step title="Verify the Gateway">
After onboarding completes:
```bash
openclaw gateway status
```
Most enterprise Azure teams already have GitHub Copilot licenses. If that is your case, we recommend choosing the GitHub Copilot provider in the OpenClaw onboarding wizard. See [GitHub Copilot provider](/providers/github-copilot).
</Step>
</Steps>
## Cost considerations
Azure Bastion Standard SKU runs approximately **\$140/month** and the VM (Standard_B2as_v2) runs approximately **\$55/month**.
To reduce costs:
- **Deallocate the VM** when not in use (stops compute billing; disk charges remain). The OpenClaw Gateway will not be reachable while the VM is deallocated — restart it when you need it live again:
```bash
az vm deallocate -g "${RG}" -n "${VM_NAME}"
az vm start -g "${RG}" -n "${VM_NAME}" # restart later
```
- **Delete Bastion when not needed** and recreate it when you need SSH access. Bastion is the largest cost component and takes only a few minutes to provision.
- **Use the Basic Bastion SKU** (~\$38/month) if you only need Portal-based SSH and don't require CLI tunneling (`az network bastion ssh`).
## Cleanup
To delete all resources created by this guide:
```bash
az group delete -n "${RG}" --yes --no-wait
```
This removes the resource group and everything inside it (VM, VNet, NSG, Bastion, public IP).
## Next steps
- Set up messaging channels: [Channels](/channels)
- Pair local devices as nodes: [Nodes](/nodes)
- Configure the Gateway: [Gateway configuration](/gateway/configuration)
- For more details on OpenClaw Azure deployment with the GitHub Copilot model provider: [OpenClaw on Azure with GitHub Copilot](https://github.com/johnsonshi/openclaw-azure-github-copilot)

View file

@ -0,0 +1,55 @@
---
summary: "Bun workflow (experimental): installs and gotchas vs pnpm"
read_when:
- You want the fastest local dev loop (bun + watch)
- You hit Bun install/patch/lifecycle script issues
title: "Bun (Experimental)"
---
# Bun (Experimental)
<Warning>
Bun is **not recommended for gateway runtime** (known issues with WhatsApp and Telegram). Use Node for production.
</Warning>
Bun is an optional local runtime for running TypeScript directly (`bun run ...`, `bun --watch ...`). The default package manager remains `pnpm`, which is fully supported and used by docs tooling. Bun cannot use `pnpm-lock.yaml` and will ignore it.
## Install
<Steps>
<Step title="Install dependencies">
```sh
bun install
```
`bun.lock` / `bun.lockb` are gitignored, so there is no repo churn. To skip lockfile writes entirely:
```sh
bun install --no-save
```
</Step>
<Step title="Build and test">
```sh
bun run build
bun run vitest run
```
</Step>
</Steps>
## Lifecycle Scripts
Bun blocks dependency lifecycle scripts unless explicitly trusted. For this repo, the commonly blocked scripts are not required:
- `@whiskeysockets/baileys` `preinstall` -- checks Node major >= 20 (OpenClaw defaults to Node 24 and still supports Node 22 LTS, currently `22.14+`)
- `protobufjs` `postinstall` -- emits warnings about incompatible version schemes (no build artifacts)
If you hit a runtime issue that requires these scripts, trust them explicitly:
```sh
bun pm trust @whiskeysockets/baileys protobufjs
```
## Caveats
Some scripts still hardcode pnpm (for example `docs:build`, `ui:*`, `protocol:check`). Run those via pnpm for now.

View file

@ -0,0 +1,106 @@
---
summary: "ClawDock shell helpers for Docker-based OpenClaw installs"
read_when:
- You run OpenClaw with Docker often and want shorter day-to-day commands
- You want a helper layer for dashboard, logs, token setup, and pairing flows
title: "ClawDock"
---
# ClawDock
ClawDock is a small shell-helper layer for Docker-based OpenClaw installs.
It gives you short commands like `clawdock-start`, `clawdock-dashboard`, and `clawdock-fix-token` instead of longer `docker compose ...` invocations.
If you have not set up Docker yet, start with [Docker](/install/docker).
## Install
Use the canonical helper path:
```bash
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
```
If you previously installed ClawDock from `scripts/shell-helpers/clawdock-helpers.sh`, reinstall from the new `scripts/clawdock/clawdock-helpers.sh` path. The old raw GitHub path was removed.
## What you get
### Basic operations
| Command | Description |
| ------------------ | ---------------------- |
| `clawdock-start` | Start the gateway |
| `clawdock-stop` | Stop the gateway |
| `clawdock-restart` | Restart the gateway |
| `clawdock-status` | Check container status |
| `clawdock-logs` | Follow gateway logs |
### Container access
| Command | Description |
| ------------------------- | --------------------------------------------- |
| `clawdock-shell` | Open a shell inside the gateway container |
| `clawdock-cli <command>` | Run OpenClaw CLI commands in Docker |
| `clawdock-exec <command>` | Execute an arbitrary command in the container |
### Web UI and pairing
| Command | Description |
| ----------------------- | ---------------------------- |
| `clawdock-dashboard` | Open the Control UI URL |
| `clawdock-devices` | List pending device pairings |
| `clawdock-approve <id>` | Approve a pairing request |
### Setup and maintenance
| Command | Description |
| -------------------- | ------------------------------------------------ |
| `clawdock-fix-token` | Configure the gateway token inside the container |
| `clawdock-update` | Pull, rebuild, and restart |
| `clawdock-rebuild` | Rebuild the Docker image only |
| `clawdock-clean` | Remove containers and volumes |
### Utilities
| Command | Description |
| ---------------------- | --------------------------------------- |
| `clawdock-health` | Run a gateway health check |
| `clawdock-token` | Print the gateway token |
| `clawdock-cd` | Jump to the OpenClaw project directory |
| `clawdock-config` | Open `~/.openclaw` |
| `clawdock-show-config` | Print config files with redacted values |
| `clawdock-workspace` | Open the workspace directory |
## First-time flow
```bash
clawdock-start
clawdock-fix-token
clawdock-dashboard
```
If the browser says pairing is required:
```bash
clawdock-devices
clawdock-approve <request-id>
```
## Config and secrets
ClawDock works with the same Docker config split described in [Docker](/install/docker):
- `<project>/.env` for Docker-specific values like image name, ports, and the gateway token
- `~/.openclaw/.env` for env-backed provider keys and bot tokens
- `~/.openclaw/agents/<agentId>/agent/auth-profiles.json` for stored provider OAuth/API-key auth
- `~/.openclaw/openclaw.json` for behavior config
Use `clawdock-show-config` when you want to inspect the `.env` files and `openclaw.json` quickly. It redacts `.env` values in its printed output.
## Related pages
- [Docker](/install/docker)
- [Docker VM Runtime](/install/docker-vm-runtime)
- [Updating](/install/updating)

View file

@ -0,0 +1,131 @@
---
summary: "Stable, beta, and dev channels: semantics, switching, pinning, and tagging"
read_when:
- You want to switch between stable/beta/dev
- You want to pin a specific version, tag, or SHA
- You are tagging or publishing prereleases
title: "Release Channels"
sidebarTitle: "Release Channels"
---
# Development channels
OpenClaw ships three update channels:
- **stable**: npm dist-tag `latest`. Recommended for most users.
- **beta**: npm dist-tag `beta` when it is current; if beta is missing or older than
the latest stable release, the update flow falls back to `latest`.
- **dev**: moving head of `main` (git). npm dist-tag: `dev` (when published).
The `main` branch is for experimentation and active development. It may contain
incomplete features or breaking changes. Do not use it for production gateways.
We usually ship stable builds to **beta** first, test them there, then run an
explicit promotion step that moves the vetted build to `latest` without
changing the version number. Maintainers can also publish a stable release
directly to `latest` when needed. Dist-tags are the source of truth for npm
installs.
## Switching channels
```bash
openclaw update --channel stable
openclaw update --channel beta
openclaw update --channel dev
```
`--channel` persists your choice in config (`update.channel`) and aligns the
install method:
- **`stable`** (package installs): updates via npm dist-tag `latest`.
- **`beta`** (package installs): prefers npm dist-tag `beta`, but falls back to
`latest` when `beta` is missing or older than the current stable tag.
- **`stable`** (git installs): checks out the latest stable git tag.
- **`beta`** (git installs): prefers the latest beta git tag, but falls back to
the latest stable git tag when beta is missing or older.
- **`dev`**: ensures a git checkout (default `~/openclaw`, override with
`OPENCLAW_GIT_DIR`), switches to `main`, rebases on upstream, builds, and
installs the global CLI from that checkout.
Tip: if you want stable + dev in parallel, keep two clones and point your
gateway at the stable one.
## One-off version or tag targeting
Use `--tag` to target a specific dist-tag, version, or package spec for a single
update **without** changing your persisted channel:
```bash
# Install a specific version
openclaw update --tag 2026.4.1-beta.1
# Install from the beta dist-tag (one-off, does not persist)
openclaw update --tag beta
# Install from GitHub main branch (npm tarball)
openclaw update --tag main
# Install a specific npm package spec
openclaw update --tag openclaw@2026.4.1-beta.1
```
Notes:
- `--tag` applies to **package (npm) installs only**. Git installs ignore it.
- The tag is not persisted. Your next `openclaw update` uses your configured
channel as usual.
- Downgrade protection: if the target version is older than your current version,
OpenClaw prompts for confirmation (skip with `--yes`).
- `--channel beta` is different from `--tag beta`: the channel flow can fall back
to stable/latest when beta is missing or older, while `--tag beta` targets the
raw `beta` dist-tag for that one run.
## Dry run
Preview what `openclaw update` would do without making changes:
```bash
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
```
The dry run shows the effective channel, target version, planned actions, and
whether a downgrade confirmation would be required.
## Plugins and channels
When you switch channels with `openclaw update`, OpenClaw also syncs plugin
sources:
- `dev` prefers bundled plugins from the git checkout.
- `stable` and `beta` restore npm-installed plugin packages.
- npm-installed plugins are updated after the core update completes.
## Checking current status
```bash
openclaw update status
```
Shows the active channel, install kind (git or package), current version, and
source (config, git tag, git branch, or default).
## Tagging best practices
- Tag releases you want git checkouts to land on (`vYYYY.M.D` for stable,
`vYYYY.M.D-beta.N` for beta).
- `vYYYY.M.D.beta.N` is also recognized for compatibility, but prefer `-beta.N`.
- Legacy `vYYYY.M.D-<patch>` tags are still recognized as stable (non-beta).
- Keep tags immutable: never move or reuse a tag.
- npm dist-tags remain the source of truth for npm installs:
- `latest` -> stable
- `beta` -> candidate build or beta-first stable build
- `dev` -> main snapshot (optional)
## macOS app availability
Beta and dev builds may **not** include a macOS app release. That is OK:
- The git tag and npm dist-tag can still be published.
- Call out "no macOS build for this beta" in release notes or changelog.

View file

@ -0,0 +1,129 @@
---
summary: "Host OpenClaw on a DigitalOcean Droplet"
read_when:
- Setting up OpenClaw on DigitalOcean
- Looking for a simple paid VPS for OpenClaw
title: "DigitalOcean"
---
# DigitalOcean
Run a persistent OpenClaw Gateway on a DigitalOcean Droplet.
## Prerequisites
- DigitalOcean account ([signup](https://cloud.digitalocean.com/registrations/new))
- SSH key pair (or willingness to use password auth)
- About 20 minutes
## Setup
<Steps>
<Step title="Create a Droplet">
<Warning>
Use a clean base image (Ubuntu 24.04 LTS). Avoid third-party Marketplace 1-click images unless you have reviewed their startup scripts and firewall defaults.
</Warning>
1. Log into [DigitalOcean](https://cloud.digitalocean.com/).
2. Click **Create > Droplets**.
3. Choose:
- **Region:** Closest to you
- **Image:** Ubuntu 24.04 LTS
- **Size:** Basic, Regular, 1 vCPU / 1 GB RAM / 25 GB SSD
- **Authentication:** SSH key (recommended) or password
4. Click **Create Droplet** and note the IP address.
</Step>
<Step title="Connect and install">
```bash
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
```
</Step>
<Step title="Run onboarding">
```bash
openclaw onboard --install-daemon
```
The wizard walks you through model auth, channel setup, gateway token generation, and daemon installation (systemd).
</Step>
<Step title="Add swap (recommended for 1 GB Droplets)">
```bash
fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab
```
</Step>
<Step title="Verify the gateway">
```bash
openclaw status
systemctl --user status openclaw-gateway.service
journalctl --user -u openclaw-gateway.service -f
```
</Step>
<Step title="Access the Control UI">
The gateway binds to loopback by default. Pick one of these options.
**Option A: SSH tunnel (simplest)**
```bash
# From your local machine
ssh -L 18789:localhost:18789 root@YOUR_DROPLET_IP
```
Then open `http://localhost:18789`.
**Option B: Tailscale Serve**
```bash
curl -fsSL https://tailscale.com/install.sh | sh
tailscale up
openclaw config set gateway.tailscale.mode serve
openclaw gateway restart
```
Then open `https://<magicdns>/` from any device on your tailnet.
**Option C: Tailnet bind (no Serve)**
```bash
openclaw config set gateway.bind tailnet
openclaw gateway restart
```
Then open `http://<tailscale-ip>:18789` (token required).
</Step>
</Steps>
## Troubleshooting
**Gateway will not start** -- Run `openclaw doctor --non-interactive` and check logs with `journalctl --user -u openclaw-gateway.service -n 50`.
**Port already in use** -- Run `lsof -i :18789` to find the process, then stop it.
**Out of memory** -- Verify swap is active with `free -h`. If still hitting OOM, use API-based models (Claude, GPT) rather than local models, or upgrade to a 2 GB Droplet.
## Next steps
- [Channels](/channels) -- connect Telegram, WhatsApp, Discord, and more
- [Gateway configuration](/gateway/configuration) -- all config options
- [Updating](/install/updating) -- keep OpenClaw up to date

View file

@ -0,0 +1,142 @@
---
summary: "Shared Docker VM runtime steps for long-lived OpenClaw Gateway hosts"
read_when:
- You are deploying OpenClaw on a cloud VM with Docker
- You need the shared binary bake, persistence, and update flow
title: "Docker VM Runtime"
---
# Docker VM Runtime
Shared runtime steps for VM-based Docker installs such as GCP, Hetzner, and similar VPS providers.
## Bake required binaries into the image
Installing binaries inside a running container is a trap.
Anything installed at runtime will be lost on restart.
All external binaries required by skills must be installed at image build time.
The examples below show three common binaries only:
- `gog` for Gmail access
- `goplaces` for Google Places
- `wacli` for WhatsApp
These are examples, not a complete list.
You may install as many binaries as needed using the same pattern.
If you add new skills later that depend on additional binaries, you must:
1. Update the Dockerfile
2. Rebuild the image
3. Restart the containers
**Example Dockerfile**
```dockerfile
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/gog_Linux_x86_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/goplaces_Linux_x86_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/wacli_Linux_x86_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"]
```
<Note>
The download URLs above are for x86_64 (amd64). For ARM-based VMs (e.g. Hetzner ARM, GCP Tau T2A), replace the download URLs with the appropriate ARM64 variants from each tool's release page.
</Note>
## Build and launch
```bash
docker compose build
docker compose up -d openclaw-gateway
```
If build fails with `Killed` or `exit code 137` during `pnpm install --frozen-lockfile`, the VM is out of memory.
Use a larger machine class before retrying.
Verify binaries:
```bash
docker compose exec openclaw-gateway which gog
docker compose exec openclaw-gateway which goplaces
docker compose exec openclaw-gateway which wacli
```
Expected output:
```
/usr/local/bin/gog
/usr/local/bin/goplaces
/usr/local/bin/wacli
```
Verify Gateway:
```bash
docker compose logs -f openclaw-gateway
```
Expected output:
```
[gateway] listening on ws://0.0.0.0:18789
```
## What persists where
OpenClaw runs in Docker, but Docker is not the source of truth.
All long-lived state must survive restarts, rebuilds, and reboots.
| Component | Location | Persistence mechanism | Notes |
| ------------------- | --------------------------------- | ---------------------- | ------------------------------------------------------------- |
| Gateway config | `/home/node/.openclaw/` | Host volume mount | Includes `openclaw.json`, `.env` |
| Model auth profiles | `/home/node/.openclaw/agents/` | Host volume mount | `agents/<agentId>/agent/auth-profiles.json` (OAuth, API keys) |
| Skill configs | `/home/node/.openclaw/skills/` | Host volume mount | Skill-level state |
| Agent workspace | `/home/node/.openclaw/workspace/` | Host volume mount | Code and agent artifacts |
| WhatsApp session | `/home/node/.openclaw/` | Host volume mount | Preserves QR login |
| Gmail keyring | `/home/node/.openclaw/` | Host volume + password | Requires `GOG_KEYRING_PASSWORD` |
| External binaries | `/usr/local/bin/` | Docker image | Must be baked at build time |
| Node runtime | Container filesystem | Docker image | Rebuilt every image build |
| OS packages | Container filesystem | Docker image | Do not install at runtime |
| Docker container | Ephemeral | Restartable | Safe to destroy |
## Updates
To update OpenClaw on the VM:
```bash
git pull
docker compose build
docker compose up -d
```

View file

@ -0,0 +1,406 @@
---
summary: "Optional Docker-based setup and onboarding for OpenClaw"
read_when:
- You want a containerized gateway instead of local installs
- You are validating the Docker flow
title: "Docker"
---
# Docker (optional)
Docker is **optional**. Use it only if you want a containerized gateway or to validate the Docker flow.
## Is Docker right for me?
- **Yes**: you want an isolated, throwaway gateway environment or to run OpenClaw on a host without local installs.
- **No**: you are running on your own machine and just want the fastest dev loop. Use the normal install flow instead.
- **Sandboxing note**: agent sandboxing uses Docker too, but it does **not** require the full gateway to run in Docker. See [Sandboxing](/gateway/sandboxing).
## Prerequisites
- Docker Desktop (or Docker Engine) + Docker Compose v2
- At least 2 GB RAM for image build (`pnpm install` may be OOM-killed on 1 GB hosts with exit 137)
- Enough disk for images and logs
- If running on a VPS/public host, review
[Security hardening for network exposure](/gateway/security),
especially Docker `DOCKER-USER` firewall policy.
## Containerized Gateway
<Steps>
<Step title="Build the image">
From the repo root, run the setup script:
```bash
./scripts/docker/setup.sh
```
This builds the gateway image locally. To use a pre-built image instead:
```bash
export OPENCLAW_IMAGE="ghcr.io/openclaw/openclaw:latest"
./scripts/docker/setup.sh
```
Pre-built images are published at the
[GitHub Container Registry](https://github.com/openclaw/openclaw/pkgs/container/openclaw).
Common tags: `main`, `latest`, `<version>` (e.g. `2026.2.26`).
</Step>
<Step title="Complete onboarding">
The setup script runs onboarding automatically. It will:
- prompt for provider API keys
- generate a gateway token and write it to `.env`
- start the gateway via Docker Compose
During setup, pre-start onboarding and config writes run through
`openclaw-gateway` directly. `openclaw-cli` is for commands you run after
the gateway container already exists.
</Step>
<Step title="Open the Control UI">
Open `http://127.0.0.1:18789/` in your browser and paste the configured
shared secret into Settings. The setup script writes a token to `.env` by
default; if you switch the container config to password auth, use that
password instead.
Need the URL again?
```bash
docker compose run --rm openclaw-cli dashboard --no-open
```
</Step>
<Step title="Configure channels (optional)">
Use the CLI container to add messaging channels:
```bash
# 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>"
```
Docs: [WhatsApp](/channels/whatsapp), [Telegram](/channels/telegram), [Discord](/channels/discord)
</Step>
</Steps>
### Manual flow
If you prefer to run each step yourself instead of using the setup script:
```bash
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
```
<Note>
Run `docker compose` from the repo root. If you enabled `OPENCLAW_EXTRA_MOUNTS`
or `OPENCLAW_HOME_VOLUME`, the setup script writes `docker-compose.extra.yml`;
include it with `-f docker-compose.yml -f docker-compose.extra.yml`.
</Note>
<Note>
Because `openclaw-cli` shares `openclaw-gateway`'s network namespace, it is a
post-start tool. Before `docker compose up -d openclaw-gateway`, run onboarding
and setup-time config writes through `openclaw-gateway` with
`--no-deps --entrypoint node`.
</Note>
### Environment variables
The setup script accepts these optional environment variables:
| Variable | Purpose |
| ------------------------------ | ---------------------------------------------------------------- |
| `OPENCLAW_IMAGE` | Use a remote image instead of building locally |
| `OPENCLAW_DOCKER_APT_PACKAGES` | Install extra apt packages during build (space-separated) |
| `OPENCLAW_EXTENSIONS` | Pre-install extension deps at build time (space-separated names) |
| `OPENCLAW_EXTRA_MOUNTS` | Extra host bind mounts (comma-separated `source:target[:opts]`) |
| `OPENCLAW_HOME_VOLUME` | Persist `/home/node` in a named Docker volume |
| `OPENCLAW_SANDBOX` | Opt in to sandbox bootstrap (`1`, `true`, `yes`, `on`) |
| `OPENCLAW_DOCKER_SOCKET` | Override Docker socket path |
### Health checks
Container probe endpoints (no auth required):
```bash
curl -fsS http://127.0.0.1:18789/healthz # liveness
curl -fsS http://127.0.0.1:18789/readyz # readiness
```
The Docker image includes a built-in `HEALTHCHECK` that pings `/healthz`.
If checks keep failing, Docker marks the container as `unhealthy` and
orchestration systems can restart or replace it.
Authenticated deep health snapshot:
```bash
docker compose exec openclaw-gateway node dist/index.js health --token "$OPENCLAW_GATEWAY_TOKEN"
```
### LAN vs loopback
`scripts/docker/setup.sh` defaults `OPENCLAW_GATEWAY_BIND=lan` so host access to
`http://127.0.0.1:18789` works with Docker port publishing.
- `lan` (default): host browser and host CLI can reach the published gateway port.
- `loopback`: only processes inside the container network namespace can reach
the gateway directly.
<Note>
Use bind mode values in `gateway.bind` (`lan` / `loopback` / `custom` /
`tailnet` / `auto`), not host aliases like `0.0.0.0` or `127.0.0.1`.
</Note>
### Storage and persistence
Docker Compose bind-mounts `OPENCLAW_CONFIG_DIR` to `/home/node/.openclaw` and
`OPENCLAW_WORKSPACE_DIR` to `/home/node/.openclaw/workspace`, so those paths
survive container replacement.
That mounted config directory is where OpenClaw keeps:
- `openclaw.json` for behavior config
- `agents/<agentId>/agent/auth-profiles.json` for stored provider OAuth/API-key auth
- `.env` for env-backed runtime secrets such as `OPENCLAW_GATEWAY_TOKEN`
For full persistence details on VM deployments, see
[Docker VM Runtime - What persists where](/install/docker-vm-runtime#what-persists-where).
**Disk growth hotspots:** watch `media/`, session JSONL files, `cron/runs/*.jsonl`,
and rolling file logs under `/tmp/openclaw/`.
### Shell helpers (optional)
For easier day-to-day Docker management, install `ClawDock`:
```bash
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
```
If you installed ClawDock from the older `scripts/shell-helpers/clawdock-helpers.sh` raw path, rerun the install command above so your local helper file tracks the new location.
Then use `clawdock-start`, `clawdock-stop`, `clawdock-dashboard`, etc. Run
`clawdock-help` for all commands.
See [ClawDock](/install/clawdock) for the full helper guide.
<AccordionGroup>
<Accordion title="Enable agent sandbox for Docker gateway">
```bash
export OPENCLAW_SANDBOX=1
./scripts/docker/setup.sh
```
Custom socket path (e.g. rootless Docker):
```bash
export OPENCLAW_SANDBOX=1
export OPENCLAW_DOCKER_SOCKET=/run/user/1000/docker.sock
./scripts/docker/setup.sh
```
The script mounts `docker.sock` only after sandbox prerequisites pass. If
sandbox setup cannot complete, the script resets `agents.defaults.sandbox.mode`
to `off`.
</Accordion>
<Accordion title="Automation / CI (non-interactive)">
Disable Compose pseudo-TTY allocation with `-T`:
```bash
docker compose run -T --rm openclaw-cli gateway probe
docker compose run -T --rm openclaw-cli devices list --json
```
</Accordion>
<Accordion title="Shared-network security note">
`openclaw-cli` uses `network_mode: "service:openclaw-gateway"` so CLI
commands can reach the gateway over `127.0.0.1`. Treat this as a shared
trust boundary. The compose config drops `NET_RAW`/`NET_ADMIN` and enables
`no-new-privileges` on `openclaw-cli`.
</Accordion>
<Accordion title="Permissions and EACCES">
The image runs as `node` (uid 1000). If you see permission errors on
`/home/node/.openclaw`, make sure your host bind mounts are owned by uid 1000:
```bash
sudo chown -R 1000:1000 /path/to/openclaw-config /path/to/openclaw-workspace
```
</Accordion>
<Accordion title="Faster rebuilds">
Order your Dockerfile so dependency layers are cached. This avoids re-running
`pnpm install` unless lockfiles change:
```dockerfile
FROM node:24-bookworm
RUN curl -fsSL https://bun.sh/install | bash
ENV PATH="/root/.bun/bin:${PATH}"
RUN corepack enable
WORKDIR /app
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml .npmrc ./
COPY ui/package.json ./ui/package.json
COPY scripts ./scripts
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"]
```
</Accordion>
<Accordion title="Power-user container options">
The default image is security-first and runs as non-root `node`. For a more
full-featured container:
1. **Persist `/home/node`**: `export OPENCLAW_HOME_VOLUME="openclaw_home"`
2. **Bake system deps**: `export OPENCLAW_DOCKER_APT_PACKAGES="git curl jq"`
3. **Install Playwright browsers**:
```bash
docker compose run --rm openclaw-cli \
node /app/node_modules/playwright-core/cli.js install chromium
```
4. **Persist browser downloads**: set
`PLAYWRIGHT_BROWSERS_PATH=/home/node/.cache/ms-playwright` and use
`OPENCLAW_HOME_VOLUME` or `OPENCLAW_EXTRA_MOUNTS`.
</Accordion>
<Accordion title="OpenAI Codex OAuth (headless Docker)">
If you pick OpenAI Codex OAuth in the wizard, it opens a browser URL. In
Docker or headless setups, copy the full redirect URL you land on and paste
it back into the wizard to finish auth.
</Accordion>
<Accordion title="Base image metadata">
The main Docker image uses `node:24-bookworm` and publishes OCI base-image
annotations including `org.opencontainers.image.base.name`,
`org.opencontainers.image.source`, and others. See
[OCI image annotations](https://github.com/opencontainers/image-spec/blob/main/annotations.md).
</Accordion>
</AccordionGroup>
### Running on a VPS?
See [Hetzner (Docker VPS)](/install/hetzner) and
[Docker VM Runtime](/install/docker-vm-runtime) for shared VM deployment steps
including binary baking, persistence, and updates.
## Agent Sandbox
When `agents.defaults.sandbox` is enabled, the gateway runs agent tool execution
(shell, file read/write, etc.) inside isolated Docker containers while the
gateway itself stays on the host. This gives you a hard wall around untrusted or
multi-tenant agent sessions without containerizing the entire gateway.
Sandbox scope can be per-agent (default), per-session, or shared. Each scope
gets its own workspace mounted at `/workspace`. You can also configure
allow/deny tool policies, network isolation, resource limits, and browser
containers.
For full configuration, images, security notes, and multi-agent profiles, see:
- [Sandboxing](/gateway/sandboxing) -- complete sandbox reference
- [OpenShell](/gateway/openshell) -- interactive shell access to sandbox containers
- [Multi-Agent Sandbox and Tools](/tools/multi-agent-sandbox-tools) -- per-agent overrides
### Quick enable
```json5
{
agents: {
defaults: {
sandbox: {
mode: "non-main", // off | non-main | all
scope: "agent", // session | agent | shared
},
},
},
}
```
Build the default sandbox image:
```bash
scripts/sandbox-setup.sh
```
## Troubleshooting
<AccordionGroup>
<Accordion title="Image missing or sandbox container not starting">
Build the sandbox image with
[`scripts/sandbox-setup.sh`](https://github.com/openclaw/openclaw/blob/main/scripts/sandbox-setup.sh)
or set `agents.defaults.sandbox.docker.image` to your custom image.
Containers are auto-created per session on demand.
</Accordion>
<Accordion title="Permission errors in sandbox">
Set `docker.user` to a UID:GID that matches your mounted workspace ownership,
or chown the workspace folder.
</Accordion>
<Accordion title="Custom tools not found in sandbox">
OpenClaw runs commands with `sh -lc` (login shell), which sources
`/etc/profile` and may reset PATH. Set `docker.env.PATH` to prepend your
custom tool paths, or add a script under `/etc/profile.d/` in your Dockerfile.
</Accordion>
<Accordion title="OOM-killed during image build (exit 137)">
The VM needs at least 2 GB RAM. Use a larger machine class and retry.
</Accordion>
<Accordion title="Unauthorized or pairing required in Control UI">
Fetch a fresh dashboard link and approve the browser device:
```bash
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>
```
More detail: [Dashboard](/web/dashboard), [Devices](/cli/devices).
</Accordion>
<Accordion title="Gateway target shows ws://172.x.x.x or pairing errors from Docker CLI">
Reset gateway mode and bind:
```bash
docker compose run --rm openclaw-cli config set --batch-json '[{"path":"gateway.mode","value":"local"},{"path":"gateway.bind","value":"lan"}]'
docker compose run --rm openclaw-cli devices list --url ws://127.0.0.1:18789
```
</Accordion>
</AccordionGroup>
## Related
- [Install Overview](/install) — all installation methods
- [Podman](/install/podman) — Podman alternative to Docker
- [ClawDock](/install/clawdock) — Docker Compose community setup
- [Updating](/install/updating) — keeping OpenClaw up to date
- [Configuration](/gateway/configuration) — gateway configuration after install

View file

@ -0,0 +1,133 @@
---
summary: "Run OpenClaw Gateway on exe.dev (VM + HTTPS proxy) for remote access"
read_when:
- You want a cheap always-on Linux host for the Gateway
- You want remote Control UI access without running your own VPS
title: "exe.dev"
---
# exe.dev
Goal: OpenClaw Gateway running on an exe.dev VM, reachable from your laptop via: `https://<vm-name>.exe.xyz`
This page assumes exe.dev's default **exeuntu** image. If you picked a different distro, map packages accordingly.
## Beginner quick path
1. [https://exe.new/openclaw](https://exe.new/openclaw)
2. Fill in your auth key/token as needed
3. Click on "Agent" next to your VM and wait for Shelley to finish provisioning
4. Open `https://<vm-name>.exe.xyz/` and authenticate with the configured shared secret (this guide uses token auth by default, but password auth works too if you switch `gateway.auth.mode`)
5. Approve any pending device pairing requests with `openclaw devices approve <requestId>`
## What you need
- exe.dev account
- `ssh exe.dev` access to [exe.dev](https://exe.dev) virtual machines (optional)
## Automated Install with Shelley
Shelley, [exe.dev](https://exe.dev)'s agent, can install OpenClaw instantly with our
prompt. The prompt used is as below:
```
Set up OpenClaw (https://docs.openclaw.ai/install) on this VM. Use the non-interactive and accept-risk flags for openclaw onboarding. Add the supplied auth or token as needed. Configure nginx to forward from the default port 18789 to the root location on the default enabled site config, making sure to enable Websocket support. Pairing is done by "openclaw devices list" and "openclaw devices approve <request id>". Make sure the dashboard shows that OpenClaw's health is OK. exe.dev handles forwarding from port 8000 to port 80/443 and HTTPS for us, so the final "reachable" should be <vm-name>.exe.xyz, without port specification.
```
## Manual installation
## 1) Create the VM
From your device:
```bash
ssh exe.dev new
```
Then connect:
```bash
ssh <vm-name>.exe.xyz
```
Tip: keep this VM **stateful**. OpenClaw stores `openclaw.json`, per-agent
`auth-profiles.json`, sessions, and channel/provider state under
`~/.openclaw/`, plus the workspace under `~/.openclaw/workspace/`.
## 2) Install prerequisites (on the VM)
```bash
sudo apt-get update
sudo apt-get install -y git curl jq ca-certificates openssl
```
## 3) Install OpenClaw
Run the OpenClaw install script:
```bash
curl -fsSL https://openclaw.ai/install.sh | bash
```
## 4) Setup nginx to proxy OpenClaw to port 8000
Edit `/etc/nginx/sites-enabled/default` with
```
server {
listen 80 default_server;
listen [::]:80 default_server;
listen 8000;
listen [::]:8000;
server_name _;
location / {
proxy_pass http://127.0.0.1:18789;
proxy_http_version 1.1;
# WebSocket support
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Standard proxy headers
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
# Timeout settings for long-lived connections
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
}
}
```
Overwrite forwarding headers instead of preserving client-supplied chains.
OpenClaw trusts forwarded IP metadata only from explicitly configured proxies,
and append-style `X-Forwarded-For` chains are treated as a hardening risk.
## 5) Access OpenClaw and grant privileges
Access `https://<vm-name>.exe.xyz/` (see the Control UI output from onboarding). If it prompts for auth, paste the
configured shared secret from the VM. This guide uses token auth, so retrieve `gateway.auth.token`
with `openclaw config get gateway.auth.token` (or generate one with `openclaw doctor --generate-gateway-token`).
If you changed the gateway to password auth, use `gateway.auth.password` / `OPENCLAW_GATEWAY_PASSWORD` instead.
Approve devices with `openclaw devices list` and `openclaw devices approve <requestId>`. When in doubt, use Shelley from your browser!
## Remote Access
Remote access is handled by [exe.dev](https://exe.dev)'s authentication. By
default, HTTP traffic from port 8000 is forwarded to `https://<vm-name>.exe.xyz`
with email auth.
## Updating
```bash
npm i -g openclaw@latest
openclaw doctor
openclaw gateway restart
openclaw health
```
Guide: [Updating](/install/updating)

View file

@ -0,0 +1,504 @@
---
title: Fly.io
summary: "Step-by-step Fly.io deployment for OpenClaw with persistent storage and HTTPS"
read_when:
- Deploying OpenClaw on Fly.io
- Setting up Fly volumes, secrets, and first-run config
---
# Fly.io Deployment
**Goal:** OpenClaw Gateway running on a [Fly.io](https://fly.io) machine with persistent storage, automatic HTTPS, and Discord/channel access.
## What you need
- [flyctl CLI](https://fly.io/docs/hands-on/install-flyctl/) installed
- Fly.io account (free tier works)
- Model auth: API key for your chosen model provider
- Channel credentials: Discord bot token, Telegram token, etc.
## Beginner quick path
1. Clone repo → customize `fly.toml`
2. Create app + volume → set secrets
3. Deploy with `fly deploy`
4. SSH in to create config or use Control UI
<Steps>
<Step title="Create the Fly app">
```bash
# Clone the repo
git clone https://github.com/openclaw/openclaw.git
cd openclaw
# Create a new Fly app (pick your own name)
fly apps create my-openclaw
# Create a persistent volume (1GB is usually enough)
fly volumes create openclaw_data --size 1 --region iad
```
**Tip:** Choose a region close to you. Common options: `lhr` (London), `iad` (Virginia), `sjc` (San Jose).
</Step>
<Step title="Configure fly.toml">
Edit `fly.toml` to match your app name and requirements.
**Security note:** The default config exposes a public URL. For a hardened deployment with no public IP, see [Private Deployment](#private-deployment-hardened) or use `fly.private.toml`.
```toml
app = "my-openclaw" # Your app name
primary_region = "iad"
[build]
dockerfile = "Dockerfile"
[env]
NODE_ENV = "production"
OPENCLAW_PREFER_PNPM = "1"
OPENCLAW_STATE_DIR = "/data"
NODE_OPTIONS = "--max-old-space-size=1536"
[processes]
app = "node dist/index.js gateway --allow-unconfigured --port 3000 --bind lan"
[http_service]
internal_port = 3000
force_https = true
auto_stop_machines = false
auto_start_machines = true
min_machines_running = 1
processes = ["app"]
[[vm]]
size = "shared-cpu-2x"
memory = "2048mb"
[mounts]
source = "openclaw_data"
destination = "/data"
```
**Key settings:**
| Setting | Why |
| ------------------------------ | --------------------------------------------------------------------------- |
| `--bind lan` | Binds to `0.0.0.0` so Fly's proxy can reach the gateway |
| `--allow-unconfigured` | Starts without a config file (you'll create one after) |
| `internal_port = 3000` | Must match `--port 3000` (or `OPENCLAW_GATEWAY_PORT`) for Fly health checks |
| `memory = "2048mb"` | 512MB is too small; 2GB recommended |
| `OPENCLAW_STATE_DIR = "/data"` | Persists state on the volume |
</Step>
<Step title="Set secrets">
```bash
# Required: Gateway token (for non-loopback binding)
fly secrets set OPENCLAW_GATEWAY_TOKEN=$(openssl rand -hex 32)
# Model provider API keys
fly secrets set ANTHROPIC_API_KEY=sk-ant-...
# Optional: Other providers
fly secrets set OPENAI_API_KEY=sk-...
fly secrets set GOOGLE_API_KEY=...
# Channel tokens
fly secrets set DISCORD_BOT_TOKEN=MTQ...
```
**Notes:**
- Non-loopback binds (`--bind lan`) require a valid gateway auth path. This Fly.io example uses `OPENCLAW_GATEWAY_TOKEN`, but `gateway.auth.password` or a correctly configured non-loopback `trusted-proxy` deployment also satisfy the requirement.
- Treat these tokens like passwords.
- **Prefer env vars over config file** for all API keys and tokens. This keeps secrets out of `openclaw.json` where they could be accidentally exposed or logged.
</Step>
<Step title="Deploy">
```bash
fly deploy
```
First deploy builds the Docker image (~2-3 minutes). Subsequent deploys are faster.
After deployment, verify:
```bash
fly status
fly logs
```
You should see:
```
[gateway] listening on ws://0.0.0.0:3000 (PID xxx)
[discord] logged in to discord as xxx
```
</Step>
<Step title="Create config file">
SSH into the machine to create a proper config:
```bash
fly ssh console
```
Create the config directory and file:
```bash
mkdir -p /data
cat > /data/openclaw.json << 'EOF'
{
"agents": {
"defaults": {
"model": {
"primary": "anthropic/claude-opus-4-6",
"fallbacks": ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4"]
},
"maxConcurrent": 4
},
"list": [
{
"id": "main",
"default": true
}
]
},
"auth": {
"profiles": {
"anthropic:default": { "mode": "token", "provider": "anthropic" },
"openai:default": { "mode": "token", "provider": "openai" }
}
},
"bindings": [
{
"agentId": "main",
"match": { "channel": "discord" }
}
],
"channels": {
"discord": {
"enabled": true,
"groupPolicy": "allowlist",
"guilds": {
"YOUR_GUILD_ID": {
"channels": { "general": { "allow": true } },
"requireMention": false
}
}
}
},
"gateway": {
"mode": "local",
"bind": "auto"
},
"meta": {}
}
EOF
```
**Note:** With `OPENCLAW_STATE_DIR=/data`, the config path is `/data/openclaw.json`.
**Note:** The Discord token can come from either:
- Environment variable: `DISCORD_BOT_TOKEN` (recommended for secrets)
- Config file: `channels.discord.token`
If using env var, no need to add token to config. The gateway reads `DISCORD_BOT_TOKEN` automatically.
Restart to apply:
```bash
exit
fly machine restart <machine-id>
```
</Step>
<Step title="Access the Gateway">
### Control UI
Open in browser:
```bash
fly open
```
Or visit `https://my-openclaw.fly.dev/`
Authenticate with the configured shared secret. This guide uses the gateway
token from `OPENCLAW_GATEWAY_TOKEN`; if you switched to password auth, use
that password instead.
### Logs
```bash
fly logs # Live logs
fly logs --no-tail # Recent logs
```
### SSH Console
```bash
fly ssh console
```
</Step>
</Steps>
## Troubleshooting
### "App is not listening on expected address"
The gateway is binding to `127.0.0.1` instead of `0.0.0.0`.
**Fix:** Add `--bind lan` to your process command in `fly.toml`.
### Health checks failing / connection refused
Fly can't reach the gateway on the configured port.
**Fix:** Ensure `internal_port` matches the gateway port (set `--port 3000` or `OPENCLAW_GATEWAY_PORT=3000`).
### OOM / Memory Issues
Container keeps restarting or getting killed. Signs: `SIGABRT`, `v8::internal::Runtime_AllocateInYoungGeneration`, or silent restarts.
**Fix:** Increase memory in `fly.toml`:
```toml
[[vm]]
memory = "2048mb"
```
Or update an existing machine:
```bash
fly machine update <machine-id> --vm-memory 2048 -y
```
**Note:** 512MB is too small. 1GB may work but can OOM under load or with verbose logging. **2GB is recommended.**
### Gateway Lock Issues
Gateway refuses to start with "already running" errors.
This happens when the container restarts but the PID lock file persists on the volume.
**Fix:** Delete the lock file:
```bash
fly ssh console --command "rm -f /data/gateway.*.lock"
fly machine restart <machine-id>
```
The lock file is at `/data/gateway.*.lock` (not in a subdirectory).
### Config Not Being Read
`--allow-unconfigured` only bypasses the startup guard. It does not create or repair `/data/openclaw.json`, so make sure your real config exists and includes `gateway.mode="local"` when you want a normal local gateway start.
Verify the config exists:
```bash
fly ssh console --command "cat /data/openclaw.json"
```
### Writing Config via SSH
The `fly ssh console -C` command doesn't support shell redirection. To write a config file:
```bash
# Use echo + tee (pipe from local to remote)
echo '{"your":"config"}' | fly ssh console -C "tee /data/openclaw.json"
# Or use sftp
fly sftp shell
> put /local/path/config.json /data/openclaw.json
```
**Note:** `fly sftp` may fail if the file already exists. Delete first:
```bash
fly ssh console --command "rm /data/openclaw.json"
```
### State Not Persisting
If you lose auth profiles, channel/provider state, or sessions after a restart,
the state dir is writing to the container filesystem.
**Fix:** Ensure `OPENCLAW_STATE_DIR=/data` is set in `fly.toml` and redeploy.
## Updates
```bash
# Pull latest changes
git pull
# Redeploy
fly deploy
# Check health
fly status
fly logs
```
### Updating Machine Command
If you need to change the startup command without a full redeploy:
```bash
# Get machine ID
fly machines list
# Update command
fly machine update <machine-id> --command "node dist/index.js gateway --port 3000 --bind lan" -y
# Or with memory increase
fly machine update <machine-id> --vm-memory 2048 --command "node dist/index.js gateway --port 3000 --bind lan" -y
```
**Note:** After `fly deploy`, the machine command may reset to what's in `fly.toml`. If you made manual changes, re-apply them after deploy.
## Private Deployment (Hardened)
By default, Fly allocates public IPs, making your gateway accessible at `https://your-app.fly.dev`. This is convenient but means your deployment is discoverable by internet scanners (Shodan, Censys, etc.).
For a hardened deployment with **no public exposure**, use the private template.
### When to use private deployment
- You only make **outbound** calls/messages (no inbound webhooks)
- You use **ngrok or Tailscale** tunnels for any webhook callbacks
- You access the gateway via **SSH, proxy, or WireGuard** instead of browser
- You want the deployment **hidden from internet scanners**
### Setup
Use `fly.private.toml` instead of the standard config:
```bash
# Deploy with private config
fly deploy -c fly.private.toml
```
Or convert an existing deployment:
```bash
# List current IPs
fly ips list -a my-openclaw
# Release public IPs
fly ips release <public-ipv4> -a my-openclaw
fly ips release <public-ipv6> -a my-openclaw
# Switch to private config so future deploys don't re-allocate public IPs
# (remove [http_service] or deploy with the private template)
fly deploy -c fly.private.toml
# Allocate private-only IPv6
fly ips allocate-v6 --private -a my-openclaw
```
After this, `fly ips list` should show only a `private` type IP:
```
VERSION IP TYPE REGION
v6 fdaa:x:x:x:x::x private global
```
### Accessing a private deployment
Since there's no public URL, use one of these methods:
**Option 1: Local proxy (simplest)**
```bash
# Forward local port 3000 to the app
fly proxy 3000:3000 -a my-openclaw
# Then open http://localhost:3000 in browser
```
**Option 2: WireGuard VPN**
```bash
# Create WireGuard config (one-time)
fly wireguard create
# Import to WireGuard client, then access via internal IPv6
# Example: http://[fdaa:x:x:x:x::x]:3000
```
**Option 3: SSH only**
```bash
fly ssh console -a my-openclaw
```
### Webhooks with private deployment
If you need webhook callbacks (Twilio, Telnyx, etc.) without public exposure:
1. **ngrok tunnel** - Run ngrok inside the container or as a sidecar
2. **Tailscale Funnel** - Expose specific paths via Tailscale
3. **Outbound-only** - Some providers (Twilio) work fine for outbound calls without webhooks
Example voice-call config with ngrok:
```json5
{
plugins: {
entries: {
"voice-call": {
enabled: true,
config: {
provider: "twilio",
tunnel: { provider: "ngrok" },
webhookSecurity: {
allowedHosts: ["example.ngrok.app"],
},
},
},
},
},
}
```
The ngrok tunnel runs inside the container and provides a public webhook URL without exposing the Fly app itself. Set `webhookSecurity.allowedHosts` to the public tunnel hostname so forwarded host headers are accepted.
### Security benefits
| Aspect | Public | Private |
| ----------------- | ------------ | ---------- |
| Internet scanners | Discoverable | Hidden |
| Direct attacks | Possible | Blocked |
| Control UI access | Browser | Proxy/VPN |
| Webhook delivery | Direct | Via tunnel |
## Notes
- Fly.io uses **x86 architecture** (not ARM)
- The Dockerfile is compatible with both architectures
- For WhatsApp/Telegram onboarding, use `fly ssh console`
- Persistent data lives on the volume at `/data`
- Signal requires Java + signal-cli; use a custom image and keep memory at 2GB+.
## Cost
With the recommended config (`shared-cpu-2x`, 2GB RAM):
- ~$10-15/month depending on usage
- Free tier includes some allowance
See [Fly.io pricing](https://fly.io/docs/about/pricing/) for details.
## Next steps
- Set up messaging channels: [Channels](/channels)
- Configure the Gateway: [Gateway configuration](/gateway/configuration)
- Keep OpenClaw up to date: [Updating](/install/updating)

View file

@ -0,0 +1,415 @@
---
summary: "Run OpenClaw Gateway 24/7 on a GCP Compute Engine VM (Docker) with durable state"
read_when:
- You want OpenClaw running 24/7 on GCP
- You want a production-grade, always-on Gateway on your own VM
- You want full control over persistence, binaries, and restart behavior
title: "GCP"
---
# OpenClaw on GCP Compute Engine (Docker, Production VPS Guide)
## Goal
Run a persistent OpenClaw Gateway on a GCP Compute Engine VM using Docker, with durable state, baked-in binaries, and safe restart behavior.
If you want "OpenClaw 24/7 for ~$5-12/mo", this is a reliable setup on Google Cloud.
Pricing varies by machine type and region; pick the smallest VM that fits your workload and scale up if you hit OOMs.
## What are we doing (simple terms)?
- Create a GCP project and enable billing
- Create a Compute Engine VM
- Install Docker (isolated app runtime)
- Start the OpenClaw Gateway in Docker
- Persist `~/.openclaw` + `~/.openclaw/workspace` on the host (survives restarts/rebuilds)
- Access the Control UI from your laptop via an SSH tunnel
That mounted `~/.openclaw` state includes `openclaw.json`, per-agent
`agents/<agentId>/agent/auth-profiles.json`, and `.env`.
The Gateway can be accessed via:
- SSH port forwarding from your laptop
- Direct port exposure if you manage firewalling and tokens yourself
This guide uses Debian on GCP Compute Engine.
Ubuntu also works; map packages accordingly.
For the generic Docker flow, see [Docker](/install/docker).
---
## Quick path (experienced operators)
1. Create GCP project + enable Compute Engine API
2. Create Compute Engine VM (e2-small, Debian 12, 20GB)
3. SSH into the VM
4. Install Docker
5. Clone OpenClaw repository
6. Create persistent host directories
7. Configure `.env` and `docker-compose.yml`
8. Bake required binaries, build, and launch
---
## What you need
- GCP account (free tier eligible for e2-micro)
- gcloud CLI installed (or use Cloud Console)
- SSH access from your laptop
- Basic comfort with SSH + copy/paste
- ~20-30 minutes
- Docker and Docker Compose
- Model auth credentials
- Optional provider credentials
- WhatsApp QR
- Telegram bot token
- Gmail OAuth
---
<Steps>
<Step title="Install gcloud CLI (or use Console)">
**Option A: gcloud CLI** (recommended for automation)
Install from [https://cloud.google.com/sdk/docs/install](https://cloud.google.com/sdk/docs/install)
Initialize and authenticate:
```bash
gcloud init
gcloud auth login
```
**Option B: Cloud Console**
All steps can be done via the web UI at [https://console.cloud.google.com](https://console.cloud.google.com)
</Step>
<Step title="Create a GCP project">
**CLI:**
```bash
gcloud projects create my-openclaw-project --name="OpenClaw Gateway"
gcloud config set project my-openclaw-project
```
Enable billing at [https://console.cloud.google.com/billing](https://console.cloud.google.com/billing) (required for Compute Engine).
Enable the Compute Engine API:
```bash
gcloud services enable compute.googleapis.com
```
**Console:**
1. Go to IAM & Admin > Create Project
2. Name it and create
3. Enable billing for the project
4. Navigate to APIs & Services > Enable APIs > search "Compute Engine API" > Enable
</Step>
<Step title="Create the VM">
**Machine types:**
| Type | Specs | Cost | Notes |
| --------- | ------------------------ | ------------------ | -------------------------------------------- |
| e2-medium | 2 vCPU, 4GB RAM | ~$25/mo | Most reliable for local Docker builds |
| e2-small | 2 vCPU, 2GB RAM | ~$12/mo | Minimum recommended for Docker build |
| e2-micro | 2 vCPU (shared), 1GB RAM | Free tier eligible | Often fails with Docker build OOM (exit 137) |
**CLI:**
```bash
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
```
**Console:**
1. Go to Compute Engine > VM instances > Create instance
2. Name: `openclaw-gateway`
3. Region: `us-central1`, Zone: `us-central1-a`
4. Machine type: `e2-small`
5. Boot disk: Debian 12, 20GB
6. Create
</Step>
<Step title="SSH into the VM">
**CLI:**
```bash
gcloud compute ssh openclaw-gateway --zone=us-central1-a
```
**Console:**
Click the "SSH" button next to your VM in the Compute Engine dashboard.
Note: SSH key propagation can take 1-2 minutes after VM creation. If connection is refused, wait and retry.
</Step>
<Step title="Install Docker (on the VM)">
```bash
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
```
Log out and back in for the group change to take effect:
```bash
exit
```
Then SSH back in:
```bash
gcloud compute ssh openclaw-gateway --zone=us-central1-a
```
Verify:
```bash
docker --version
docker compose version
```
</Step>
<Step title="Clone the OpenClaw repository">
```bash
git clone https://github.com/openclaw/openclaw.git
cd openclaw
```
This guide assumes you will build a custom image to guarantee binary persistence.
</Step>
<Step title="Create persistent host directories">
Docker containers are ephemeral.
All long-lived state must live on the host.
```bash
mkdir -p ~/.openclaw
mkdir -p ~/.openclaw/workspace
```
</Step>
<Step title="Configure environment variables">
Create `.env` in the repository root.
```bash
OPENCLAW_IMAGE=openclaw:latest
OPENCLAW_GATEWAY_TOKEN=
OPENCLAW_GATEWAY_BIND=lan
OPENCLAW_GATEWAY_PORT=18789
OPENCLAW_CONFIG_DIR=/home/$USER/.openclaw
OPENCLAW_WORKSPACE_DIR=/home/$USER/.openclaw/workspace
GOG_KEYRING_PASSWORD=
XDG_CONFIG_HOME=/home/node/.openclaw
```
Leave `OPENCLAW_GATEWAY_TOKEN` blank unless you explicitly want to
manage it through `.env`; OpenClaw writes a random gateway token to
config on first start. Generate a keyring password and paste it into
`GOG_KEYRING_PASSWORD`:
```bash
openssl rand -hex 32
```
**Do not commit this file.**
This `.env` file is for container/runtime env such as `OPENCLAW_GATEWAY_TOKEN`.
Stored provider OAuth/API-key auth lives in the mounted
`~/.openclaw/agents/<agentId>/agent/auth-profiles.json`.
</Step>
<Step title="Docker Compose configuration">
Create or update `docker-compose.yml`.
```yaml
services:
openclaw-gateway:
image: ${OPENCLAW_IMAGE}
build: .
restart: unless-stopped
env_file:
- .env
environment:
- HOME=/home/node
- NODE_ENV=production
- TERM=xterm-256color
- OPENCLAW_GATEWAY_BIND=${OPENCLAW_GATEWAY_BIND}
- OPENCLAW_GATEWAY_PORT=${OPENCLAW_GATEWAY_PORT}
- OPENCLAW_GATEWAY_TOKEN=${OPENCLAW_GATEWAY_TOKEN}
- GOG_KEYRING_PASSWORD=${GOG_KEYRING_PASSWORD}
- XDG_CONFIG_HOME=${XDG_CONFIG_HOME}
- PATH=/home/linuxbrew/.linuxbrew/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
volumes:
- ${OPENCLAW_CONFIG_DIR}:/home/node/.openclaw
- ${OPENCLAW_WORKSPACE_DIR}:/home/node/.openclaw/workspace
ports:
# Recommended: keep the Gateway loopback-only on the VM; access via SSH tunnel.
# To expose it publicly, remove the `127.0.0.1:` prefix and firewall accordingly.
- "127.0.0.1:${OPENCLAW_GATEWAY_PORT}:18789"
command:
[
"node",
"dist/index.js",
"gateway",
"--bind",
"${OPENCLAW_GATEWAY_BIND}",
"--port",
"${OPENCLAW_GATEWAY_PORT}",
"--allow-unconfigured",
]
```
`--allow-unconfigured` is only for bootstrap convenience, it is not a replacement for a proper gateway configuration. Still set auth (`gateway.auth.token` or password) and use safe bind settings for your deployment.
</Step>
<Step title="Shared Docker VM runtime steps">
Use the shared runtime guide for the common Docker host flow:
- [Bake required binaries into the image](/install/docker-vm-runtime#bake-required-binaries-into-the-image)
- [Build and launch](/install/docker-vm-runtime#build-and-launch)
- [What persists where](/install/docker-vm-runtime#what-persists-where)
- [Updates](/install/docker-vm-runtime#updates)
</Step>
<Step title="GCP-specific launch notes">
On GCP, if build fails with `Killed` or `exit code 137` during `pnpm install --frozen-lockfile`, the VM is out of memory. Use `e2-small` minimum, or `e2-medium` for more reliable first builds.
When binding to LAN (`OPENCLAW_GATEWAY_BIND=lan`), configure a trusted browser origin before continuing:
```bash
docker compose run --rm openclaw-cli config set gateway.controlUi.allowedOrigins '["http://127.0.0.1:18789"]' --strict-json
```
If you changed the gateway port, replace `18789` with your configured port.
</Step>
<Step title="Access from your laptop">
Create an SSH tunnel to forward the Gateway port:
```bash
gcloud compute ssh openclaw-gateway --zone=us-central1-a -- -L 18789:127.0.0.1:18789
```
Open in your browser:
`http://127.0.0.1:18789/`
Reprint a clean dashboard link:
```bash
docker compose run --rm openclaw-cli dashboard --no-open
```
If the UI prompts for shared-secret auth, paste the configured token or
password into Control UI settings. This Docker flow writes a token by
default; if you switch the container config to password auth, use that
password instead.
If Control UI shows `unauthorized` or `disconnected (1008): pairing required`, approve the browser device:
```bash
docker compose run --rm openclaw-cli devices list
docker compose run --rm openclaw-cli devices approve <requestId>
```
Need the shared persistence and update reference again?
See [Docker VM Runtime](/install/docker-vm-runtime#what-persists-where) and [Docker VM Runtime updates](/install/docker-vm-runtime#updates).
</Step>
</Steps>
---
## Troubleshooting
**SSH connection refused**
SSH key propagation can take 1-2 minutes after VM creation. Wait and retry.
**OS Login issues**
Check your OS Login profile:
```bash
gcloud compute os-login describe-profile
```
Ensure your account has the required IAM permissions (Compute OS Login or Compute OS Admin Login).
**Out of memory (OOM)**
If Docker build fails with `Killed` and `exit code 137`, the VM was OOM-killed. Upgrade to e2-small (minimum) or e2-medium (recommended for reliable local builds):
```bash
# 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
```
---
## Service accounts (security best practice)
For personal use, your default user account works fine.
For automation or CI/CD pipelines, create a dedicated service account with minimal permissions:
1. Create a service account:
```bash
gcloud iam service-accounts create openclaw-deploy \
--display-name="OpenClaw Deployment"
```
2. Grant Compute Instance Admin role (or narrower custom role):
```bash
gcloud projects add-iam-policy-binding my-openclaw-project \
--member="serviceAccount:openclaw-deploy@my-openclaw-project.iam.gserviceaccount.com" \
--role="roles/compute.instanceAdmin.v1"
```
Avoid using the Owner role for automation. Use the principle of least privilege.
See [https://cloud.google.com/iam/docs/understanding-roles](https://cloud.google.com/iam/docs/understanding-roles) for IAM role details.
---
## Next steps
- Set up messaging channels: [Channels](/channels)
- Pair local devices as nodes: [Nodes](/nodes)
- Configure the Gateway: [Gateway configuration](/gateway/configuration)

View file

@ -0,0 +1,262 @@
---
summary: "Run OpenClaw Gateway 24/7 on a cheap Hetzner VPS (Docker) with durable state and baked-in binaries"
read_when:
- You want OpenClaw running 24/7 on a cloud VPS (not your laptop)
- You want a production-grade, always-on Gateway on your own VPS
- You want full control over persistence, binaries, and restart behavior
- You are running OpenClaw in Docker on Hetzner or a similar provider
title: "Hetzner"
---
# OpenClaw on Hetzner (Docker, Production VPS Guide)
## Goal
Run a persistent OpenClaw Gateway on a Hetzner VPS using Docker, with durable state, baked-in binaries, and safe restart behavior.
If you want “OpenClaw 24/7 for ~$5”, this is the simplest reliable setup.
Hetzner pricing changes; pick the smallest Debian/Ubuntu VPS and scale up if you hit OOMs.
Security model reminder:
- Company-shared agents are fine when everyone is in the same trust boundary and the runtime is business-only.
- Keep strict separation: dedicated VPS/runtime + dedicated accounts; no personal Apple/Google/browser/password-manager profiles on that host.
- If users are adversarial to each other, split by gateway/host/OS user.
See [Security](/gateway/security) and [VPS hosting](/vps).
## What are we doing (simple terms)?
- Rent a small Linux server (Hetzner VPS)
- Install Docker (isolated app runtime)
- Start the OpenClaw Gateway in Docker
- Persist `~/.openclaw` + `~/.openclaw/workspace` on the host (survives restarts/rebuilds)
- Access the Control UI from your laptop via an SSH tunnel
That mounted `~/.openclaw` state includes `openclaw.json`, per-agent
`agents/<agentId>/agent/auth-profiles.json`, and `.env`.
The Gateway can be accessed via:
- SSH port forwarding from your laptop
- Direct port exposure if you manage firewalling and tokens yourself
This guide assumes Ubuntu or Debian on Hetzner.
If you are on another Linux VPS, map packages accordingly.
For the generic Docker flow, see [Docker](/install/docker).
---
## Quick path (experienced operators)
1. Provision Hetzner VPS
2. Install Docker
3. Clone OpenClaw repository
4. Create persistent host directories
5. Configure `.env` and `docker-compose.yml`
6. Bake required binaries into the image
7. `docker compose up -d`
8. Verify persistence and Gateway access
---
## What you need
- Hetzner VPS with root access
- SSH access from your laptop
- Basic comfort with SSH + copy/paste
- ~20 minutes
- Docker and Docker Compose
- Model auth credentials
- Optional provider credentials
- WhatsApp QR
- Telegram bot token
- Gmail OAuth
---
<Steps>
<Step title="Provision the VPS">
Create an Ubuntu or Debian VPS in Hetzner.
Connect as root:
```bash
ssh root@YOUR_VPS_IP
```
This guide assumes the VPS is stateful.
Do not treat it as disposable infrastructure.
</Step>
<Step title="Install Docker (on the VPS)">
```bash
apt-get update
apt-get install -y git curl ca-certificates
curl -fsSL https://get.docker.com | sh
```
Verify:
```bash
docker --version
docker compose version
```
</Step>
<Step title="Clone the OpenClaw repository">
```bash
git clone https://github.com/openclaw/openclaw.git
cd openclaw
```
This guide assumes you will build a custom image to guarantee binary persistence.
</Step>
<Step title="Create persistent host directories">
Docker containers are ephemeral.
All long-lived state must live on the host.
```bash
mkdir -p /root/.openclaw/workspace
# Set ownership to the container user (uid 1000):
chown -R 1000:1000 /root/.openclaw
```
</Step>
<Step title="Configure environment variables">
Create `.env` in the repository root.
```bash
OPENCLAW_IMAGE=openclaw:latest
OPENCLAW_GATEWAY_TOKEN=
OPENCLAW_GATEWAY_BIND=lan
OPENCLAW_GATEWAY_PORT=18789
OPENCLAW_CONFIG_DIR=/root/.openclaw
OPENCLAW_WORKSPACE_DIR=/root/.openclaw/workspace
GOG_KEYRING_PASSWORD=
XDG_CONFIG_HOME=/home/node/.openclaw
```
Leave `OPENCLAW_GATEWAY_TOKEN` blank unless you explicitly want to
manage it through `.env`; OpenClaw writes a random gateway token to
config on first start. Generate a keyring password and paste it into
`GOG_KEYRING_PASSWORD`:
```bash
openssl rand -hex 32
```
**Do not commit this file.**
This `.env` file is for container/runtime env such as `OPENCLAW_GATEWAY_TOKEN`.
Stored provider OAuth/API-key auth lives in the mounted
`~/.openclaw/agents/<agentId>/agent/auth-profiles.json`.
</Step>
<Step title="Docker Compose configuration">
Create or update `docker-compose.yml`.
```yaml
services:
openclaw-gateway:
image: ${OPENCLAW_IMAGE}
build: .
restart: unless-stopped
env_file:
- .env
environment:
- HOME=/home/node
- NODE_ENV=production
- TERM=xterm-256color
- OPENCLAW_GATEWAY_BIND=${OPENCLAW_GATEWAY_BIND}
- OPENCLAW_GATEWAY_PORT=${OPENCLAW_GATEWAY_PORT}
- OPENCLAW_GATEWAY_TOKEN=${OPENCLAW_GATEWAY_TOKEN}
- GOG_KEYRING_PASSWORD=${GOG_KEYRING_PASSWORD}
- XDG_CONFIG_HOME=${XDG_CONFIG_HOME}
- PATH=/home/linuxbrew/.linuxbrew/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
volumes:
- ${OPENCLAW_CONFIG_DIR}:/home/node/.openclaw
- ${OPENCLAW_WORKSPACE_DIR}:/home/node/.openclaw/workspace
ports:
# Recommended: keep the Gateway loopback-only on the VPS; access via SSH tunnel.
# To expose it publicly, remove the `127.0.0.1:` prefix and firewall accordingly.
- "127.0.0.1:${OPENCLAW_GATEWAY_PORT}:18789"
command:
[
"node",
"dist/index.js",
"gateway",
"--bind",
"${OPENCLAW_GATEWAY_BIND}",
"--port",
"${OPENCLAW_GATEWAY_PORT}",
"--allow-unconfigured",
]
```
`--allow-unconfigured` is only for bootstrap convenience, it is not a replacement for a proper gateway configuration. Still set auth (`gateway.auth.token` or password) and use safe bind settings for your deployment.
</Step>
<Step title="Shared Docker VM runtime steps">
Use the shared runtime guide for the common Docker host flow:
- [Bake required binaries into the image](/install/docker-vm-runtime#bake-required-binaries-into-the-image)
- [Build and launch](/install/docker-vm-runtime#build-and-launch)
- [What persists where](/install/docker-vm-runtime#what-persists-where)
- [Updates](/install/docker-vm-runtime#updates)
</Step>
<Step title="Hetzner-specific access">
After the shared build and launch steps, tunnel from your laptop:
```bash
ssh -N -L 18789:127.0.0.1:18789 root@YOUR_VPS_IP
```
Open:
`http://127.0.0.1:18789/`
Paste the configured shared secret. This guide uses the gateway token by
default; if you switched to password auth, use that password instead.
</Step>
</Steps>
The shared persistence map lives in [Docker VM Runtime](/install/docker-vm-runtime#what-persists-where).
## Infrastructure as Code (Terraform)
For teams preferring infrastructure-as-code workflows, a community-maintained Terraform setup provides:
- Modular Terraform configuration with remote state management
- Automated provisioning via cloud-init
- Deployment scripts (bootstrap, deploy, backup/restore)
- Security hardening (firewall, UFW, SSH-only access)
- SSH tunnel configuration for gateway access
**Repositories:**
- Infrastructure: [openclaw-terraform-hetzner](https://github.com/andreesg/openclaw-terraform-hetzner)
- Docker config: [openclaw-docker-config](https://github.com/andreesg/openclaw-docker-config)
This approach complements the Docker setup above with reproducible deployments, version-controlled infrastructure, and automated disaster recovery.
> **Note:** Community-maintained. For issues or contributions, see the repository links above.
## Next steps
- Set up messaging channels: [Channels](/channels)
- Configure the Gateway: [Gateway configuration](/gateway/configuration)
- Keep OpenClaw up to date: [Updating](/install/updating)

View file

@ -0,0 +1,94 @@
---
summary: "Host OpenClaw on Hostinger"
read_when:
- Setting up OpenClaw on Hostinger
- Looking for a managed VPS for OpenClaw
- Using Hostinger 1-Click OpenClaw
title: "Hostinger"
---
# Hostinger
Run a persistent OpenClaw Gateway on [Hostinger](https://www.hostinger.com/openclaw) via a **1-Click** managed deployment or a **VPS** install.
## Prerequisites
- Hostinger account ([signup](https://www.hostinger.com/openclaw))
- About 5-10 minutes
## Option A: 1-Click OpenClaw
The fastest way to get started. Hostinger handles infrastructure, Docker, and automatic updates.
<Steps>
<Step title="Purchase and launch">
1. From the [Hostinger OpenClaw page](https://www.hostinger.com/openclaw), choose a Managed OpenClaw plan and complete checkout.
<Note>
During checkout you can select **Ready-to-Use AI** credits that are pre-purchased and integrated instantly inside OpenClaw -- no external accounts or API keys from other providers needed. You can start chatting right away. Alternatively, provide your own key from Anthropic, OpenAI, Google Gemini, or xAI during setup.
</Note>
</Step>
<Step title="Select a messaging channel">
Choose one or more channels to connect:
- **WhatsApp** -- scan the QR code shown in the setup wizard.
- **Telegram** -- paste the bot token from [BotFather](https://t.me/BotFather).
</Step>
<Step title="Complete installation">
Click **Finish** to deploy the instance. Once ready, access the OpenClaw dashboard from **OpenClaw Overview** in hPanel.
</Step>
</Steps>
## Option B: OpenClaw on VPS
More control over your server. Hostinger deploys OpenClaw via Docker on your VPS and you manage it through the **Docker Manager** in hPanel.
<Steps>
<Step title="Purchase a VPS">
1. From the [Hostinger OpenClaw page](https://www.hostinger.com/openclaw), choose an OpenClaw on VPS plan and complete checkout.
<Note>
You can select **Ready-to-Use AI** credits during checkout -- these are pre-purchased and integrated instantly inside OpenClaw, so you can start chatting without any external accounts or API keys from other providers.
</Note>
</Step>
<Step title="Configure OpenClaw">
Once the VPS is provisioned, fill in the configuration fields:
- **Gateway token** -- auto-generated; save it for later use.
- **WhatsApp number** -- your number with country code (optional).
- **Telegram bot token** -- from [BotFather](https://t.me/BotFather) (optional).
- **API keys** -- only needed if you did not select Ready-to-Use AI credits during checkout.
</Step>
<Step title="Start OpenClaw">
Click **Deploy**. Once running, open the OpenClaw dashboard from the hPanel by clicking on **Open**.
</Step>
</Steps>
Logs, restarts, and updates are managed directly from the Docker Manager interface in hPanel. To update, press on **Update** in Docker Manager and that will pull the latest image.
## Verify your setup
Send "Hi" to your assistant on the channel you connected. OpenClaw will reply and walk you through initial preferences.
## Troubleshooting
**Dashboard not loading** -- Wait a few minutes for the container to finish provisioning. Check the Docker Manager logs in hPanel.
**Docker container keeps restarting** -- Open Docker Manager logs and look for configuration errors (missing tokens, invalid API keys).
**Telegram bot not responding** -- Send your pairing code message from Telegram directly as a message inside your OpenClaw chat to complete the connection.
## Next steps
- [Channels](/channels) -- connect Telegram, WhatsApp, Discord, and more
- [Gateway configuration](/gateway/configuration) -- all config optionss

View file

@ -0,0 +1,212 @@
---
summary: "Install OpenClaw — installer script, npm/pnpm/bun, from source, Docker, and more"
read_when:
- You need an install method other than the Getting Started quickstart
- You want to deploy to a cloud platform
- You need to update, migrate, or uninstall
title: "Install"
---
# Install
## Recommended: installer script
The fastest way to install. It detects your OS, installs Node if needed, installs OpenClaw, and launches onboarding.
<Tabs>
<Tab title="macOS / Linux / WSL2">
```bash
curl -fsSL https://openclaw.ai/install.sh | bash
```
</Tab>
<Tab title="Windows (PowerShell)">
```powershell
iwr -useb https://openclaw.ai/install.ps1 | iex
```
</Tab>
</Tabs>
To install without running onboarding:
<Tabs>
<Tab title="macOS / Linux / WSL2">
```bash
curl -fsSL https://openclaw.ai/install.sh | bash -s -- --no-onboard
```
</Tab>
<Tab title="Windows (PowerShell)">
```powershell
& ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -NoOnboard
```
</Tab>
</Tabs>
For all flags and CI/automation options, see [Installer internals](/install/installer).
## System requirements
- **Node 24** (recommended) or Node 22.14+ — the installer script handles this automatically
- **macOS, Linux, or Windows** — both native Windows and WSL2 are supported; WSL2 is more stable. See [Windows](/platforms/windows).
- `pnpm` is only needed if you build from source
## Alternative install methods
### Local prefix installer (`install-cli.sh`)
Use this when you want OpenClaw and Node kept under a local prefix such as
`~/.openclaw`, without depending on a system-wide Node install:
```bash
curl -fsSL https://openclaw.ai/install-cli.sh | bash
```
It supports npm installs by default, plus git-checkout installs under the same
prefix flow. Full reference: [Installer internals](/install/installer#install-clish).
### npm, pnpm, or bun
If you already manage Node yourself:
<Tabs>
<Tab title="npm">
```bash
npm install -g openclaw@latest
openclaw onboard --install-daemon
```
</Tab>
<Tab title="pnpm">
```bash
pnpm add -g openclaw@latest
pnpm approve-builds -g
openclaw onboard --install-daemon
```
<Note>
pnpm requires explicit approval for packages with build scripts. Run `pnpm approve-builds -g` after the first install.
</Note>
</Tab>
<Tab title="bun">
```bash
bun add -g openclaw@latest
openclaw onboard --install-daemon
```
<Note>
Bun is supported for the global CLI install path. For the Gateway runtime, Node remains the recommended daemon runtime.
</Note>
</Tab>
</Tabs>
<Accordion title="Troubleshooting: sharp build errors (npm)">
If `sharp` fails due to a globally installed libvips:
```bash
SHARP_IGNORE_GLOBAL_LIBVIPS=1 npm install -g openclaw@latest
```
</Accordion>
### From source
For contributors or anyone who wants to run from a local checkout:
```bash
git clone https://github.com/openclaw/openclaw.git
cd openclaw
pnpm install && pnpm build && pnpm ui:build
pnpm link --global
openclaw onboard --install-daemon
```
Or skip the link and use `pnpm openclaw ...` from inside the repo. See [Setup](/start/setup) for full development workflows.
### Install from GitHub main
```bash
npm install -g github:openclaw/openclaw#main
```
### Containers and package managers
<CardGroup cols={2}>
<Card title="Docker" href="/install/docker" icon="container">
Containerized or headless deployments.
</Card>
<Card title="Podman" href="/install/podman" icon="container">
Rootless container alternative to Docker.
</Card>
<Card title="Nix" href="/install/nix" icon="snowflake">
Declarative install via Nix flake.
</Card>
<Card title="Ansible" href="/install/ansible" icon="server">
Automated fleet provisioning.
</Card>
<Card title="Bun" href="/install/bun" icon="zap">
CLI-only usage via the Bun runtime.
</Card>
</CardGroup>
## Verify the install
```bash
openclaw --version # confirm the CLI is available
openclaw doctor # check for config issues
openclaw gateway status # verify the Gateway is running
```
If you want managed startup after install:
- macOS: LaunchAgent via `openclaw onboard --install-daemon` or `openclaw gateway install`
- Linux/WSL2: systemd user service via the same commands
- Native Windows: Scheduled Task first, with a per-user Startup-folder login item fallback if task creation is denied
## Hosting and deployment
Deploy OpenClaw on a cloud server or VPS:
<CardGroup cols={3}>
<Card title="VPS" href="/vps">Any Linux VPS</Card>
<Card title="Docker VM" href="/install/docker-vm-runtime">Shared Docker steps</Card>
<Card title="Kubernetes" href="/install/kubernetes">K8s</Card>
<Card title="Fly.io" href="/install/fly">Fly.io</Card>
<Card title="Hetzner" href="/install/hetzner">Hetzner</Card>
<Card title="GCP" href="/install/gcp">Google Cloud</Card>
<Card title="Azure" href="/install/azure">Azure</Card>
<Card title="Railway" href="/install/railway">Railway</Card>
<Card title="Render" href="/install/render">Render</Card>
<Card title="Northflank" href="/install/northflank">Northflank</Card>
</CardGroup>
## Update, migrate, or uninstall
<CardGroup cols={3}>
<Card title="Updating" href="/install/updating" icon="refresh-cw">
Keep OpenClaw up to date.
</Card>
<Card title="Migrating" href="/install/migrating" icon="arrow-right">
Move to a new machine.
</Card>
<Card title="Uninstall" href="/install/uninstall" icon="trash-2">
Remove OpenClaw completely.
</Card>
</CardGroup>
## Troubleshooting: `openclaw` not found
If the install succeeded but `openclaw` is not found in your terminal:
```bash
node -v # Node installed?
npm prefix -g # Where are global packages?
echo "$PATH" # Is the global bin dir in PATH?
```
If `$(npm prefix -g)/bin` is not in your `$PATH`, add it to your shell startup file (`~/.zshrc` or `~/.bashrc`):
```bash
export PATH="$(npm prefix -g)/bin:$PATH"
```
Then open a new terminal. See [Node setup](/install/node) for more details.

View file

@ -0,0 +1,443 @@
---
summary: "How the installer scripts work (install.sh, install-cli.sh, install.ps1), flags, and automation"
read_when:
- You want to understand `openclaw.ai/install.sh`
- You want to automate installs (CI / headless)
- You want to install from a GitHub checkout
title: "Installer Internals"
---
# Installer internals
OpenClaw ships three installer scripts, served from `openclaw.ai`.
| Script | Platform | What it does |
| ---------------------------------- | -------------------- | -------------------------------------------------------------------------------------------------------------- |
| [`install.sh`](#installsh) | macOS / Linux / WSL | Installs Node if needed, installs OpenClaw via npm (default) or git, and can run onboarding. |
| [`install-cli.sh`](#install-clish) | macOS / Linux / WSL | Installs Node + OpenClaw into a local prefix (`~/.openclaw`) with npm or git checkout modes. No root required. |
| [`install.ps1`](#installps1) | Windows (PowerShell) | Installs Node if needed, installs OpenClaw via npm (default) or git, and can run onboarding. |
## Quick commands
<Tabs>
<Tab title="install.sh">
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash
```
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --help
```
</Tab>
<Tab title="install-cli.sh">
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install-cli.sh | bash
```
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install-cli.sh | bash -s -- --help
```
</Tab>
<Tab title="install.ps1">
```powershell
iwr -useb https://openclaw.ai/install.ps1 | iex
```
```powershell
& ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -Tag beta -NoOnboard -DryRun
```
</Tab>
</Tabs>
<Note>
If install succeeds but `openclaw` is not found in a new terminal, see [Node.js troubleshooting](/install/node#troubleshooting).
</Note>
---
<a id="installsh"></a>
## install.sh
<Tip>
Recommended for most interactive installs on macOS/Linux/WSL.
</Tip>
### Flow (install.sh)
<Steps>
<Step title="Detect OS">
Supports macOS and Linux (including WSL). If macOS is detected, installs Homebrew if missing.
</Step>
<Step title="Ensure Node.js 24 by default">
Checks Node version and installs Node 24 if needed (Homebrew on macOS, NodeSource setup scripts on Linux apt/dnf/yum). OpenClaw still supports Node 22 LTS, currently `22.14+`, for compatibility.
</Step>
<Step title="Ensure Git">
Installs Git if missing.
</Step>
<Step title="Install OpenClaw">
- `npm` method (default): global npm install
- `git` method: clone/update repo, install deps with pnpm, build, then install wrapper at `~/.local/bin/openclaw`
</Step>
<Step title="Post-install tasks">
- Refreshes a loaded gateway service best-effort (`openclaw gateway install --force`, then restart)
- Runs `openclaw doctor --non-interactive` on upgrades and git installs (best effort)
- Attempts onboarding when appropriate (TTY available, onboarding not disabled, and bootstrap/config checks pass)
- Defaults `SHARP_IGNORE_GLOBAL_LIBVIPS=1`
</Step>
</Steps>
### Source checkout detection
If run inside an OpenClaw checkout (`package.json` + `pnpm-workspace.yaml`), the script offers:
- use checkout (`git`), or
- use global install (`npm`)
If no TTY is available and no install method is set, it defaults to `npm` and warns.
The script exits with code `2` for invalid method selection or invalid `--install-method` values.
### Examples (install.sh)
<Tabs>
<Tab title="Default">
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash
```
</Tab>
<Tab title="Skip onboarding">
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --no-onboard
```
</Tab>
<Tab title="Git install">
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --install-method git
```
</Tab>
<Tab title="GitHub main via npm">
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --version main
```
</Tab>
<Tab title="Dry run">
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --dry-run
```
</Tab>
</Tabs>
<AccordionGroup>
<Accordion title="Flags reference">
| Flag | Description |
| ------------------------------------- | ---------------------------------------------------------- |
| `--install-method npm\|git` | Choose install method (default: `npm`). Alias: `--method` |
| `--npm` | Shortcut for npm method |
| `--git` | Shortcut for git method. Alias: `--github` |
| `--version <version\|dist-tag\|spec>` | npm version, dist-tag, or package spec (default: `latest`) |
| `--beta` | Use beta dist-tag if available, else fallback to `latest` |
| `--git-dir <path>` | Checkout directory (default: `~/openclaw`). Alias: `--dir` |
| `--no-git-update` | Skip `git pull` for existing checkout |
| `--no-prompt` | Disable prompts |
| `--no-onboard` | Skip onboarding |
| `--onboard` | Enable onboarding |
| `--dry-run` | Print actions without applying changes |
| `--verbose` | Enable debug output (`set -x`, npm notice-level logs) |
| `--help` | Show usage (`-h`) |
</Accordion>
<Accordion title="Environment variables reference">
| Variable | Description |
| ------------------------------------------------------- | --------------------------------------------- |
| `OPENCLAW_INSTALL_METHOD=git\|npm` | Install method |
| `OPENCLAW_VERSION=latest\|next\|main\|<semver>\|<spec>` | npm version, dist-tag, or package spec |
| `OPENCLAW_BETA=0\|1` | Use beta if available |
| `OPENCLAW_GIT_DIR=<path>` | Checkout directory |
| `OPENCLAW_GIT_UPDATE=0\|1` | Toggle git updates |
| `OPENCLAW_NO_PROMPT=1` | Disable prompts |
| `OPENCLAW_NO_ONBOARD=1` | Skip onboarding |
| `OPENCLAW_DRY_RUN=1` | Dry run mode |
| `OPENCLAW_VERBOSE=1` | Debug mode |
| `OPENCLAW_NPM_LOGLEVEL=error\|warn\|notice` | npm log level |
| `SHARP_IGNORE_GLOBAL_LIBVIPS=0\|1` | Control sharp/libvips behavior (default: `1`) |
</Accordion>
</AccordionGroup>
---
<a id="install-clish"></a>
## install-cli.sh
<Info>
Designed for environments where you want everything under a local prefix
(default `~/.openclaw`) and no system Node dependency. Supports npm installs
by default, plus git-checkout installs under the same prefix flow.
</Info>
### Flow (install-cli.sh)
<Steps>
<Step title="Install local Node runtime">
Downloads a pinned supported Node LTS tarball (the version is embedded in the script and updated independently) to `<prefix>/tools/node-v<version>` and verifies SHA-256.
</Step>
<Step title="Ensure Git">
If Git is missing, attempts install via apt/dnf/yum on Linux or Homebrew on macOS.
</Step>
<Step title="Install OpenClaw under prefix">
- `npm` method (default): installs under the prefix with npm, then writes wrapper to `<prefix>/bin/openclaw`
- `git` method: clones/updates a checkout (default `~/openclaw`) and still writes the wrapper to `<prefix>/bin/openclaw`
</Step>
<Step title="Refresh loaded gateway service">
If a gateway service is already loaded from that same prefix, the script runs
`openclaw gateway install --force`, then `openclaw gateway restart`, and
probes gateway health best-effort.
</Step>
</Steps>
### Examples (install-cli.sh)
<Tabs>
<Tab title="Default">
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install-cli.sh | bash
```
</Tab>
<Tab title="Custom prefix + version">
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install-cli.sh | bash -s -- --prefix /opt/openclaw --version latest
```
</Tab>
<Tab title="Git install">
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install-cli.sh | bash -s -- --install-method git --git-dir ~/openclaw
```
</Tab>
<Tab title="Automation JSON output">
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install-cli.sh | bash -s -- --json --prefix /opt/openclaw
```
</Tab>
<Tab title="Run onboarding">
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install-cli.sh | bash -s -- --onboard
```
</Tab>
</Tabs>
<AccordionGroup>
<Accordion title="Flags reference">
| Flag | Description |
| --------------------------- | ------------------------------------------------------------------------------- |
| `--prefix <path>` | Install prefix (default: `~/.openclaw`) |
| `--install-method npm\|git` | Choose install method (default: `npm`). Alias: `--method` |
| `--npm` | Shortcut for npm method |
| `--git`, `--github` | Shortcut for git method |
| `--git-dir <path>` | Git checkout directory (default: `~/openclaw`). Alias: `--dir` |
| `--version <ver>` | OpenClaw version or dist-tag (default: `latest`) |
| `--node-version <ver>` | Node version (default: `22.22.0`) |
| `--json` | Emit NDJSON events |
| `--onboard` | Run `openclaw onboard` after install |
| `--no-onboard` | Skip onboarding (default) |
| `--set-npm-prefix` | On Linux, force npm prefix to `~/.npm-global` if current prefix is not writable |
| `--help` | Show usage (`-h`) |
</Accordion>
<Accordion title="Environment variables reference">
| Variable | Description |
| ------------------------------------------- | --------------------------------------------- |
| `OPENCLAW_PREFIX=<path>` | Install prefix |
| `OPENCLAW_INSTALL_METHOD=git\|npm` | Install method |
| `OPENCLAW_VERSION=<ver>` | OpenClaw version or dist-tag |
| `OPENCLAW_NODE_VERSION=<ver>` | Node version |
| `OPENCLAW_GIT_DIR=<path>` | Git checkout directory for git installs |
| `OPENCLAW_GIT_UPDATE=0\|1` | Toggle git updates for existing checkouts |
| `OPENCLAW_NO_ONBOARD=1` | Skip onboarding |
| `OPENCLAW_NPM_LOGLEVEL=error\|warn\|notice` | npm log level |
| `SHARP_IGNORE_GLOBAL_LIBVIPS=0\|1` | Control sharp/libvips behavior (default: `1`) |
</Accordion>
</AccordionGroup>
---
<a id="installps1"></a>
## install.ps1
### Flow (install.ps1)
<Steps>
<Step title="Ensure PowerShell + Windows environment">
Requires PowerShell 5+.
</Step>
<Step title="Ensure Node.js 24 by default">
If missing, attempts install via winget, then Chocolatey, then Scoop. Node 22 LTS, currently `22.14+`, remains supported for compatibility.
</Step>
<Step title="Install OpenClaw">
- `npm` method (default): global npm install using selected `-Tag`
- `git` method: clone/update repo, install/build with pnpm, and install wrapper at `%USERPROFILE%\.local\bin\openclaw.cmd`
</Step>
<Step title="Post-install tasks">
- Adds needed bin directory to user PATH when possible
- Refreshes a loaded gateway service best-effort (`openclaw gateway install --force`, then restart)
- Runs `openclaw doctor --non-interactive` on upgrades and git installs (best effort)
</Step>
</Steps>
### Examples (install.ps1)
<Tabs>
<Tab title="Default">
```powershell
iwr -useb https://openclaw.ai/install.ps1 | iex
```
</Tab>
<Tab title="Git install">
```powershell
& ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -InstallMethod git
```
</Tab>
<Tab title="GitHub main via npm">
```powershell
& ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -Tag main
```
</Tab>
<Tab title="Custom git directory">
```powershell
& ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -InstallMethod git -GitDir "C:\openclaw"
```
</Tab>
<Tab title="Dry run">
```powershell
& ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -DryRun
```
</Tab>
<Tab title="Debug trace">
```powershell
# install.ps1 has no dedicated -Verbose flag yet.
Set-PSDebug -Trace 1
& ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -NoOnboard
Set-PSDebug -Trace 0
```
</Tab>
</Tabs>
<AccordionGroup>
<Accordion title="Flags reference">
| Flag | Description |
| --------------------------- | ---------------------------------------------------------- |
| `-InstallMethod npm\|git` | Install method (default: `npm`) |
| `-Tag <tag\|version\|spec>` | npm dist-tag, version, or package spec (default: `latest`) |
| `-GitDir <path>` | Checkout directory (default: `%USERPROFILE%\openclaw`) |
| `-NoOnboard` | Skip onboarding |
| `-NoGitUpdate` | Skip `git pull` |
| `-DryRun` | Print actions only |
</Accordion>
<Accordion title="Environment variables reference">
| Variable | Description |
| ---------------------------------- | ------------------ |
| `OPENCLAW_INSTALL_METHOD=git\|npm` | Install method |
| `OPENCLAW_GIT_DIR=<path>` | Checkout directory |
| `OPENCLAW_NO_ONBOARD=1` | Skip onboarding |
| `OPENCLAW_GIT_UPDATE=0` | Disable git pull |
| `OPENCLAW_DRY_RUN=1` | Dry run mode |
</Accordion>
</AccordionGroup>
<Note>
If `-InstallMethod git` is used and Git is missing, the script exits and prints the Git for Windows link.
</Note>
---
## CI and automation
Use non-interactive flags/env vars for predictable runs.
<Tabs>
<Tab title="install.sh (non-interactive npm)">
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --no-prompt --no-onboard
```
</Tab>
<Tab title="install.sh (non-interactive git)">
```bash
OPENCLAW_INSTALL_METHOD=git OPENCLAW_NO_PROMPT=1 \
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash
```
</Tab>
<Tab title="install-cli.sh (JSON)">
```bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install-cli.sh | bash -s -- --json --prefix /opt/openclaw
```
</Tab>
<Tab title="install.ps1 (skip onboarding)">
```powershell
& ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -NoOnboard
```
</Tab>
</Tabs>
---
## Troubleshooting
<AccordionGroup>
<Accordion title="Why is Git required?">
Git is required for `git` install method. For `npm` installs, Git is still checked/installed to avoid `spawn git ENOENT` failures when dependencies use git URLs.
</Accordion>
<Accordion title="Why does npm hit EACCES on Linux?">
Some Linux setups point npm global prefix to root-owned paths. `install.sh` can switch prefix to `~/.npm-global` and append PATH exports to shell rc files (when those files exist).
</Accordion>
<Accordion title="sharp/libvips issues">
The scripts default `SHARP_IGNORE_GLOBAL_LIBVIPS=1` to avoid sharp building against system libvips. To override:
```bash
SHARP_IGNORE_GLOBAL_LIBVIPS=0 curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash
```
</Accordion>
<Accordion title='Windows: "npm error spawn git / ENOENT"'>
Install Git for Windows, reopen PowerShell, rerun installer.
</Accordion>
<Accordion title='Windows: "openclaw is not recognized"'>
Run `npm config get prefix` and add that directory to your user PATH (no `\bin` suffix needed on Windows), then reopen PowerShell.
</Accordion>
<Accordion title="Windows: how to get verbose installer output">
`install.ps1` does not currently expose a `-Verbose` switch.
Use PowerShell tracing for script-level diagnostics:
```powershell
Set-PSDebug -Trace 1
& ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -NoOnboard
Set-PSDebug -Trace 0
```
</Accordion>
<Accordion title="openclaw not found after install">
Usually a PATH issue. See [Node.js troubleshooting](/install/node#troubleshooting).
</Accordion>
</AccordionGroup>

View file

@ -0,0 +1,192 @@
---
summary: "Deploy OpenClaw Gateway to a Kubernetes cluster with Kustomize"
read_when:
- You want to run OpenClaw on a Kubernetes cluster
- You want to test OpenClaw in a Kubernetes environment
title: "Kubernetes"
---
# OpenClaw on Kubernetes
A minimal starting point for running OpenClaw on Kubernetes — not a production-ready deployment. It covers the core resources and is meant to be adapted to your environment.
## Why not Helm?
OpenClaw is a single container with some config files. The interesting customization is in agent content (markdown files, skills, config overrides), not infrastructure templating. Kustomize handles overlays without the overhead of a Helm chart. If your deployment grows more complex, a Helm chart can be layered on top of these manifests.
## What you need
- A running Kubernetes cluster (AKS, EKS, GKE, k3s, kind, OpenShift, etc.)
- `kubectl` connected to your cluster
- An API key for at least one model provider
## Quick start
```bash
# Replace with your provider: ANTHROPIC, GEMINI, OPENAI, or OPENROUTER
export <PROVIDER>_API_KEY="..."
./scripts/k8s/deploy.sh
kubectl port-forward svc/openclaw 18789:18789 -n openclaw
open http://localhost:18789
```
Retrieve the configured shared secret for the Control UI. This deploy script
creates token auth by default:
```bash
kubectl get secret openclaw-secrets -n openclaw -o jsonpath='{.data.OPENCLAW_GATEWAY_TOKEN}' | base64 -d
```
For local debugging, `./scripts/k8s/deploy.sh --show-token` prints the token after deploy.
## Local testing with Kind
If you don't have a cluster, create one locally with [Kind](https://kind.sigs.k8s.io/):
```bash
./scripts/k8s/create-kind.sh # auto-detects docker or podman
./scripts/k8s/create-kind.sh --delete # tear down
```
Then deploy as usual with `./scripts/k8s/deploy.sh`.
## Step by step
### 1) Deploy
**Option A** — API key in environment (one step):
```bash
# Replace with your provider: ANTHROPIC, GEMINI, OPENAI, or OPENROUTER
export <PROVIDER>_API_KEY="..."
./scripts/k8s/deploy.sh
```
The script creates a Kubernetes Secret with the API key and an auto-generated gateway token, then deploys. If the Secret already exists, it preserves the current gateway token and any provider keys not being changed.
**Option B** — create the secret separately:
```bash
export <PROVIDER>_API_KEY="..."
./scripts/k8s/deploy.sh --create-secret
./scripts/k8s/deploy.sh
```
Use `--show-token` with either command if you want the token printed to stdout for local testing.
### 2) Access the gateway
```bash
kubectl port-forward svc/openclaw 18789:18789 -n openclaw
open http://localhost:18789
```
## What gets deployed
```
Namespace: openclaw (configurable via OPENCLAW_NAMESPACE)
├── Deployment/openclaw # Single pod, init container + gateway
├── Service/openclaw # ClusterIP on port 18789
├── PersistentVolumeClaim # 10Gi for agent state and config
├── ConfigMap/openclaw-config # openclaw.json + AGENTS.md
└── Secret/openclaw-secrets # Gateway token + API keys
```
## Customization
### Agent instructions
Edit the `AGENTS.md` in `scripts/k8s/manifests/configmap.yaml` and redeploy:
```bash
./scripts/k8s/deploy.sh
```
### Gateway config
Edit `openclaw.json` in `scripts/k8s/manifests/configmap.yaml`. See [Gateway configuration](/gateway/configuration) for the full reference.
### Add providers
Re-run with additional keys exported:
```bash
export ANTHROPIC_API_KEY="..."
export OPENAI_API_KEY="..."
./scripts/k8s/deploy.sh --create-secret
./scripts/k8s/deploy.sh
```
Existing provider keys stay in the Secret unless you overwrite them.
Or patch the Secret directly:
```bash
kubectl patch secret openclaw-secrets -n openclaw \
-p '{"stringData":{"<PROVIDER>_API_KEY":"..."}}'
kubectl rollout restart deployment/openclaw -n openclaw
```
### Custom namespace
```bash
OPENCLAW_NAMESPACE=my-namespace ./scripts/k8s/deploy.sh
```
### Custom image
Edit the `image` field in `scripts/k8s/manifests/deployment.yaml`:
```yaml
image: ghcr.io/openclaw/openclaw:latest # or pin to a specific version from https://github.com/openclaw/openclaw/releases
```
### Expose beyond port-forward
The default manifests bind the gateway to loopback inside the pod. That works with `kubectl port-forward`, but it does not work with a Kubernetes `Service` or Ingress path that needs to reach the pod IP.
If you want to expose the gateway through an Ingress or load balancer:
- Change the gateway bind in `scripts/k8s/manifests/configmap.yaml` from `loopback` to a non-loopback bind that matches your deployment model
- Keep gateway auth enabled and use a proper TLS-terminated entrypoint
- Configure the Control UI for remote access using the supported web security model (for example HTTPS/Tailscale Serve and explicit allowed origins when needed)
## Re-deploy
```bash
./scripts/k8s/deploy.sh
```
This applies all manifests and restarts the pod to pick up any config or secret changes.
## Teardown
```bash
./scripts/k8s/deploy.sh --delete
```
This deletes the namespace and all resources in it, including the PVC.
## Architecture notes
- The gateway binds to loopback inside the pod by default, so the included setup is for `kubectl port-forward`
- No cluster-scoped resources — everything lives in a single namespace
- Security: `readOnlyRootFilesystem`, `drop: ALL` capabilities, non-root user (UID 1000)
- The default config keeps the Control UI on the safer local-access path: loopback bind plus `kubectl port-forward` to `http://127.0.0.1:18789`
- If you move beyond localhost access, use the supported remote model: HTTPS/Tailscale plus the appropriate gateway bind and Control UI origin settings
- Secrets are generated in a temp directory and applied directly to the cluster — no secret material is written to the repo checkout
## File structure
```
scripts/k8s/
├── deploy.sh # Creates namespace + secret, deploys via kustomize
├── create-kind.sh # Local Kind cluster (auto-detects docker/podman)
└── manifests/
├── kustomization.yaml # Kustomize base
├── configmap.yaml # openclaw.json + AGENTS.md
├── deployment.yaml # Pod spec with security hardening
├── pvc.yaml # 10Gi persistent storage
└── service.yaml # ClusterIP on 18789
```

View file

@ -0,0 +1,281 @@
---
summary: "Run OpenClaw in a sandboxed macOS VM (local or hosted) when you need isolation or iMessage"
read_when:
- You want OpenClaw isolated from your main macOS environment
- You want iMessage integration (BlueBubbles) in a sandbox
- You want a resettable macOS environment you can clone
- You want to compare local vs hosted macOS VM options
title: "macOS VMs"
---
# OpenClaw on macOS VMs (Sandboxing)
## Recommended default (most users)
- **Small Linux VPS** for an always-on Gateway and low cost. See [VPS hosting](/vps).
- **Dedicated hardware** (Mac mini or Linux box) if you want full control and a **residential IP** for browser automation. Many sites block data center IPs, so local browsing often works better.
- **Hybrid:** keep the Gateway on a cheap VPS, and connect your Mac as a **node** when you need browser/UI automation. See [Nodes](/nodes) and [Gateway remote](/gateway/remote).
Use a macOS VM when you specifically need macOS-only capabilities (iMessage/BlueBubbles) or want strict isolation from your daily Mac.
## macOS VM options
### Local VM on your Apple Silicon Mac (Lume)
Run OpenClaw in a sandboxed macOS VM on your existing Apple Silicon Mac using [Lume](https://cua.ai/docs/lume).
This gives you:
- Full macOS environment in isolation (your host stays clean)
- iMessage support via BlueBubbles (impossible on Linux/Windows)
- Instant reset by cloning VMs
- No extra hardware or cloud costs
### Hosted Mac providers (cloud)
If you want macOS in the cloud, hosted Mac providers work too:
- [MacStadium](https://www.macstadium.com/) (hosted Macs)
- Other hosted Mac vendors also work; follow their VM + SSH docs
Once you have SSH access to a macOS VM, continue at step 6 below.
---
## Quick path (Lume, experienced users)
1. Install Lume
2. `lume create openclaw --os macos --ipsw latest`
3. Complete Setup Assistant, enable Remote Login (SSH)
4. `lume run openclaw --no-display`
5. SSH in, install OpenClaw, configure channels
6. Done
---
## What you need (Lume)
- Apple Silicon Mac (M1/M2/M3/M4)
- macOS Sequoia or later on the host
- ~60 GB free disk space per VM
- ~20 minutes
---
## 1) Install Lume
```bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/trycua/cua/main/libs/lume/scripts/install.sh)"
```
If `~/.local/bin` isn't in your PATH:
```bash
echo 'export PATH="$PATH:$HOME/.local/bin"' >> ~/.zshrc && source ~/.zshrc
```
Verify:
```bash
lume --version
```
Docs: [Lume Installation](https://cua.ai/docs/lume/guide/getting-started/installation)
---
## 2) Create the macOS VM
```bash
lume create openclaw --os macos --ipsw latest
```
This downloads macOS and creates the VM. A VNC window opens automatically.
Note: The download can take a while depending on your connection.
---
## 3) Complete Setup Assistant
In the VNC window:
1. Select language and region
2. Skip Apple ID (or sign in if you want iMessage later)
3. Create a user account (remember the username and password)
4. Skip all optional features
After setup completes, enable SSH:
1. Open System Settings → General → Sharing
2. Enable "Remote Login"
---
## 4) Get the VM IP address
```bash
lume get openclaw
```
Look for the IP address (usually `192.168.64.x`).
---
## 5) SSH into the VM
```bash
ssh youruser@192.168.64.X
```
Replace `youruser` with the account you created, and the IP with your VM's IP.
---
## 6) Install OpenClaw
Inside the VM:
```bash
npm install -g openclaw@latest
openclaw onboard --install-daemon
```
Follow the onboarding prompts to set up your model provider (Anthropic, OpenAI, etc.).
---
## 7) Configure channels
Edit the config file:
```bash
nano ~/.openclaw/openclaw.json
```
Add your channels:
```json5
{
channels: {
whatsapp: {
dmPolicy: "allowlist",
allowFrom: ["+15551234567"],
},
telegram: {
botToken: "YOUR_BOT_TOKEN",
},
},
}
```
Then login to WhatsApp (scan QR):
```bash
openclaw channels login
```
---
## 8) Run the VM headlessly
Stop the VM and restart without display:
```bash
lume stop openclaw
lume run openclaw --no-display
```
The VM runs in the background. OpenClaw's daemon keeps the gateway running.
To check status:
```bash
ssh youruser@192.168.64.X "openclaw status"
```
---
## Bonus: iMessage integration
This is the killer feature of running on macOS. Use [BlueBubbles](https://bluebubbles.app) to add iMessage to OpenClaw.
Inside the VM:
1. Download BlueBubbles from bluebubbles.app
2. Sign in with your Apple ID
3. Enable the Web API and set a password
4. Point BlueBubbles webhooks at your gateway (example: `https://your-gateway-host:3000/bluebubbles-webhook?password=<password>`)
Add to your OpenClaw config:
```json5
{
channels: {
bluebubbles: {
serverUrl: "http://localhost:1234",
password: "your-api-password",
webhookPath: "/bluebubbles-webhook",
},
},
}
```
Restart the gateway. Now your agent can send and receive iMessages.
Full setup details: [BlueBubbles channel](/channels/bluebubbles)
---
## Save a golden image
Before customizing further, snapshot your clean state:
```bash
lume stop openclaw
lume clone openclaw openclaw-golden
```
Reset anytime:
```bash
lume stop openclaw && lume delete openclaw
lume clone openclaw-golden openclaw
lume run openclaw --no-display
```
---
## Running 24/7
Keep the VM running by:
- Keeping your Mac plugged in
- Disabling sleep in System Settings → Energy Saver
- Using `caffeinate` if needed
For true always-on, consider a dedicated Mac mini or a small VPS. See [VPS hosting](/vps).
---
## Troubleshooting
| Problem | Solution |
| ------------------------ | ---------------------------------------------------------------------------------- |
| Can't SSH into VM | Check "Remote Login" is enabled in VM's System Settings |
| VM IP not showing | Wait for VM to fully boot, run `lume get openclaw` again |
| Lume command not found | Add `~/.local/bin` to your PATH |
| WhatsApp QR not scanning | Ensure you're logged into the VM (not host) when running `openclaw channels login` |
---
## Related docs
- [VPS hosting](/vps)
- [Nodes](/nodes)
- [Gateway remote](/gateway/remote)
- [BlueBubbles channel](/channels/bluebubbles)
- [Lume Quickstart](https://cua.ai/docs/lume/guide/getting-started/quickstart)
- [Lume CLI Reference](https://cua.ai/docs/lume/reference/cli-reference)
- [Unattended VM Setup](https://cua.ai/docs/lume/guide/fundamentals/unattended-setup) (advanced)
- [Docker Sandboxing](/install/docker) (alternative isolation approach)

View file

@ -0,0 +1,349 @@
---
summary: "How OpenClaw upgrades the previous Matrix plugin in place, including encrypted-state recovery limits and manual recovery steps."
read_when:
- Upgrading an existing Matrix installation
- Migrating encrypted Matrix history and device state
title: "Matrix migration"
---
# Matrix migration
This page covers upgrades from the previous public `matrix` plugin to the current implementation.
For most users, the upgrade is in place:
- the plugin stays `@openclaw/matrix`
- the channel stays `matrix`
- your config stays under `channels.matrix`
- cached credentials stay under `~/.openclaw/credentials/matrix/`
- runtime state stays under `~/.openclaw/matrix/`
You do not need to rename config keys or reinstall the plugin under a new name.
## What the migration does automatically
When the gateway starts, and when you run [`openclaw doctor --fix`](/gateway/doctor), OpenClaw tries to repair old Matrix state automatically.
Before any actionable Matrix migration step mutates on-disk state, OpenClaw creates or reuses a focused recovery snapshot.
When you use `openclaw update`, the exact trigger depends on how OpenClaw is installed:
- source installs run `openclaw doctor --fix` during the update flow, then restart the gateway by default
- package-manager installs update the package, run a non-interactive doctor pass, then rely on the default gateway restart so startup can finish Matrix migration
- if you use `openclaw update --no-restart`, startup-backed Matrix migration is deferred until you later run `openclaw doctor --fix` and restart the gateway
Automatic migration covers:
- creating or reusing a pre-migration snapshot under `~/Backups/openclaw-migrations/`
- reusing your cached Matrix credentials
- keeping the same account selection and `channels.matrix` config
- moving the oldest flat Matrix sync store into the current account-scoped location
- moving the oldest flat Matrix crypto store into the current account-scoped location when the target account can be resolved safely
- extracting a previously saved Matrix room-key backup decryption key from the old rust crypto store, when that key exists locally
- reusing the most complete existing token-hash storage root for the same Matrix account, homeserver, and user when the access token changes later
- scanning sibling token-hash storage roots for pending encrypted-state restore metadata when the Matrix access token changed but the account/device identity stayed the same
- restoring backed-up room keys into the new crypto store on the next Matrix startup
Snapshot details:
- OpenClaw writes a marker file at `~/.openclaw/matrix/migration-snapshot.json` after a successful snapshot so later startup and repair passes can reuse the same archive.
- These automatic Matrix migration snapshots back up config + state only (`includeWorkspace: false`).
- If Matrix only has warning-only migration state, for example because `userId` or `accessToken` is still missing, OpenClaw does not create the snapshot yet because no Matrix mutation is actionable.
- If the snapshot step fails, OpenClaw skips Matrix migration for that run instead of mutating state without a recovery point.
About multi-account upgrades:
- the oldest flat Matrix store (`~/.openclaw/matrix/bot-storage.json` and `~/.openclaw/matrix/crypto/`) came from a single-store layout, so OpenClaw can only migrate it into one resolved Matrix account target
- already account-scoped legacy Matrix stores are detected and prepared per configured Matrix account
## What the migration cannot do automatically
The previous public Matrix plugin did **not** automatically create Matrix room-key backups. It persisted local crypto state and requested device verification, but it did not guarantee that your room keys were backed up to the homeserver.
That means some encrypted installs can only be migrated partially.
OpenClaw cannot automatically recover:
- local-only room keys that were never backed up
- encrypted state when the target Matrix account cannot be resolved yet because `homeserver`, `userId`, or `accessToken` are still unavailable
- automatic migration of one shared flat Matrix store when multiple Matrix accounts are configured but `channels.matrix.defaultAccount` is not set
- custom plugin path installs that are pinned to a repo path instead of the standard Matrix package
- a missing recovery key when the old store had backed-up keys but did not keep the decryption key locally
Current warning scope:
- custom Matrix plugin path installs are surfaced by both gateway startup and `openclaw doctor`
If your old installation had local-only encrypted history that was never backed up, some older encrypted messages may remain unreadable after the upgrade.
## Recommended upgrade flow
1. Update OpenClaw and the Matrix plugin normally.
Prefer plain `openclaw update` without `--no-restart` so startup can finish the Matrix migration immediately.
2. Run:
```bash
openclaw doctor --fix
```
If Matrix has actionable migration work, doctor will create or reuse the pre-migration snapshot first and print the archive path.
3. Start or restart the gateway.
4. Check current verification and backup state:
```bash
openclaw matrix verify status
openclaw matrix verify backup status
```
5. If OpenClaw tells you a recovery key is needed, run:
```bash
openclaw matrix verify backup restore --recovery-key "<your-recovery-key>"
```
6. If this device is still unverified, run:
```bash
openclaw matrix verify device "<your-recovery-key>"
```
7. If you are intentionally abandoning unrecoverable old history and want a fresh backup baseline for future messages, run:
```bash
openclaw matrix verify backup reset --yes
```
8. If no server-side key backup exists yet, create one for future recoveries:
```bash
openclaw matrix verify bootstrap
```
## How encrypted migration works
Encrypted migration is a two-stage process:
1. Startup or `openclaw doctor --fix` creates or reuses the pre-migration snapshot if encrypted migration is actionable.
2. Startup or `openclaw doctor --fix` inspects the old Matrix crypto store through the active Matrix plugin install.
3. If a backup decryption key is found, OpenClaw writes it into the new recovery-key flow and marks room-key restore as pending.
4. On the next Matrix startup, OpenClaw restores backed-up room keys into the new crypto store automatically.
If the old store reports room keys that were never backed up, OpenClaw warns instead of pretending recovery succeeded.
## Common messages and what they mean
### Upgrade and detection messages
`Matrix plugin upgraded in place.`
- Meaning: the old on-disk Matrix state was detected and migrated into the current layout.
- What to do: nothing unless the same output also includes warnings.
`Matrix migration snapshot created before applying Matrix upgrades.`
- Meaning: OpenClaw created a recovery archive before mutating Matrix state.
- What to do: keep the printed archive path until you confirm migration succeeded.
`Matrix migration snapshot reused before applying Matrix upgrades.`
- Meaning: OpenClaw found an existing Matrix migration snapshot marker and reused that archive instead of creating a duplicate backup.
- What to do: keep the printed archive path until you confirm migration succeeded.
`Legacy Matrix state detected at ... but channels.matrix is not configured yet.`
- Meaning: old Matrix state exists, but OpenClaw cannot map it to a current Matrix account because Matrix is not configured.
- What to do: configure `channels.matrix`, then rerun `openclaw doctor --fix` or restart the gateway.
`Legacy Matrix state detected at ... but the new account-scoped target could not be resolved yet (need homeserver, userId, and access token for channels.matrix...).`
- Meaning: OpenClaw found old state, but it still cannot determine the exact current account/device root.
- What to do: start the gateway once with a working Matrix login, or rerun `openclaw doctor --fix` after cached credentials exist.
`Legacy Matrix state detected at ... but multiple Matrix accounts are configured and channels.matrix.defaultAccount is not set.`
- Meaning: OpenClaw found one shared flat Matrix store, but it refuses to guess which named Matrix account should receive it.
- What to do: set `channels.matrix.defaultAccount` to the intended account, then rerun `openclaw doctor --fix` or restart the gateway.
`Matrix legacy sync store not migrated because the target already exists (...)`
- Meaning: the new account-scoped location already has a sync or crypto store, so OpenClaw did not overwrite it automatically.
- What to do: verify that the current account is the correct one before manually removing or moving the conflicting target.
`Failed migrating Matrix legacy sync store (...)` or `Failed migrating Matrix legacy crypto store (...)`
- Meaning: OpenClaw tried to move old Matrix state but the filesystem operation failed.
- What to do: inspect filesystem permissions and disk state, then rerun `openclaw doctor --fix`.
`Legacy Matrix encrypted state detected at ... but channels.matrix is not configured yet.`
- Meaning: OpenClaw found an old encrypted Matrix store, but there is no current Matrix config to attach it to.
- What to do: configure `channels.matrix`, then rerun `openclaw doctor --fix` or restart the gateway.
`Legacy Matrix encrypted state detected at ... but the account-scoped target could not be resolved yet (need homeserver, userId, and access token for channels.matrix...).`
- Meaning: the encrypted store exists, but OpenClaw cannot safely decide which current account/device it belongs to.
- What to do: start the gateway once with a working Matrix login, or rerun `openclaw doctor --fix` after cached credentials are available.
`Legacy Matrix encrypted state detected at ... but multiple Matrix accounts are configured and channels.matrix.defaultAccount is not set.`
- Meaning: OpenClaw found one shared flat legacy crypto store, but it refuses to guess which named Matrix account should receive it.
- What to do: set `channels.matrix.defaultAccount` to the intended account, then rerun `openclaw doctor --fix` or restart the gateway.
`Matrix migration warnings are present, but no on-disk Matrix mutation is actionable yet. No pre-migration snapshot was needed.`
- Meaning: OpenClaw detected old Matrix state, but the migration is still blocked on missing identity or credential data.
- What to do: finish Matrix login or config setup, then rerun `openclaw doctor --fix` or restart the gateway.
`Legacy Matrix encrypted state was detected, but the Matrix plugin helper is unavailable. Install or repair @openclaw/matrix so OpenClaw can inspect the old rust crypto store before upgrading.`
- Meaning: OpenClaw found old encrypted Matrix state, but it could not load the helper entrypoint from the Matrix plugin that normally inspects that store.
- What to do: reinstall or repair the Matrix plugin (`openclaw plugins install @openclaw/matrix`, or `openclaw plugins install ./path/to/local/matrix-plugin` for a repo checkout), then rerun `openclaw doctor --fix` or restart the gateway.
`Matrix plugin helper path is unsafe: ... Reinstall @openclaw/matrix and try again.`
- Meaning: OpenClaw found a helper file path that escapes the plugin root or fails plugin boundary checks, so it refused to import it.
- What to do: reinstall the Matrix plugin from a trusted path, then rerun `openclaw doctor --fix` or restart the gateway.
`- Failed creating a Matrix migration snapshot before repair: ...`
`- Skipping Matrix migration changes for now. Resolve the snapshot failure, then rerun "openclaw doctor --fix".`
- Meaning: OpenClaw refused to mutate Matrix state because it could not create the recovery snapshot first.
- What to do: resolve the backup error, then rerun `openclaw doctor --fix` or restart the gateway.
`Failed migrating legacy Matrix client storage: ...`
- Meaning: the Matrix client-side fallback found old flat storage, but the move failed. OpenClaw now aborts that fallback instead of silently starting with a fresh store.
- What to do: inspect filesystem permissions or conflicts, keep the old state intact, and retry after fixing the error.
`Matrix is installed from a custom path: ...`
- Meaning: Matrix is pinned to a path install, so mainline updates do not automatically replace it with the repo's standard Matrix package.
- What to do: reinstall with `openclaw plugins install @openclaw/matrix` when you want to return to the default Matrix plugin.
### Encrypted-state recovery messages
`matrix: restored X/Y room key(s) from legacy encrypted-state backup`
- Meaning: backed-up room keys were restored successfully into the new crypto store.
- What to do: usually nothing.
`matrix: N legacy local-only room key(s) were never backed up and could not be restored automatically`
- Meaning: some old room keys existed only in the old local store and had never been uploaded to Matrix backup.
- What to do: expect some old encrypted history to remain unavailable unless you can recover those keys manually from another verified client.
`Legacy Matrix encrypted state for account "..." has backed-up room keys, but no local backup decryption key was found. Ask the operator to run "openclaw matrix verify backup restore --recovery-key <key>" after upgrade if they have the recovery key.`
- Meaning: backup exists, but OpenClaw could not recover the recovery key automatically.
- What to do: run `openclaw matrix verify backup restore --recovery-key "<your-recovery-key>"`.
`Failed inspecting legacy Matrix encrypted state for account "..." (...): ...`
- Meaning: OpenClaw found the old encrypted store, but it could not inspect it safely enough to prepare recovery.
- What to do: rerun `openclaw doctor --fix`. If it repeats, keep the old state directory intact and recover using another verified Matrix client plus `openclaw matrix verify backup restore --recovery-key "<your-recovery-key>"`.
`Legacy Matrix backup key was found for account "...", but .../recovery-key.json already contains a different recovery key. Leaving the existing file unchanged.`
- Meaning: OpenClaw detected a backup key conflict and refused to overwrite the current recovery-key file automatically.
- What to do: verify which recovery key is correct before retrying any restore command.
`Legacy Matrix encrypted state for account "..." cannot be fully converted automatically because the old rust crypto store does not expose all local room keys for export.`
- Meaning: this is the hard limit of the old storage format.
- What to do: backed-up keys can still be restored, but local-only encrypted history may remain unavailable.
`matrix: failed restoring room keys from legacy encrypted-state backup: ...`
- Meaning: the new plugin attempted restore but Matrix returned an error.
- What to do: run `openclaw matrix verify backup status`, then retry with `openclaw matrix verify backup restore --recovery-key "<your-recovery-key>"` if needed.
### Manual recovery messages
`Backup key is not loaded on this device. Run 'openclaw matrix verify backup restore' to load it and restore old room keys.`
- Meaning: OpenClaw knows you should have a backup key, but it is not active on this device.
- What to do: run `openclaw matrix verify backup restore`, or pass `--recovery-key` if needed.
`Store a recovery key with 'openclaw matrix verify device <key>', then run 'openclaw matrix verify backup restore'.`
- Meaning: this device does not currently have the recovery key stored.
- What to do: verify the device with your recovery key first, then restore the backup.
`Backup key mismatch on this device. Re-run 'openclaw matrix verify device <key>' with the matching recovery key.`
- Meaning: the stored key does not match the active Matrix backup.
- What to do: rerun `openclaw matrix verify device "<your-recovery-key>"` with the correct key.
If you accept losing unrecoverable old encrypted history, you can instead reset the
current backup baseline with `openclaw matrix verify backup reset --yes`. When the
stored backup secret is broken, that reset may also recreate secret storage so the
new backup key can load correctly after restart.
`Backup trust chain is not verified on this device. Re-run 'openclaw matrix verify device <key>'.`
- Meaning: the backup exists, but this device does not trust the cross-signing chain strongly enough yet.
- What to do: rerun `openclaw matrix verify device "<your-recovery-key>"`.
`Matrix recovery key is required`
- Meaning: you tried a recovery step without supplying a recovery key when one was required.
- What to do: rerun the command with your recovery key.
`Invalid Matrix recovery key: ...`
- Meaning: the provided key could not be parsed or did not match the expected format.
- What to do: retry with the exact recovery key from your Matrix client or recovery-key file.
`Matrix device is still unverified after applying recovery key. Verify your recovery key and ensure cross-signing is available.`
- Meaning: the key was applied, but the device still could not complete verification.
- What to do: confirm you used the correct key and that cross-signing is available on the account, then retry.
`Matrix key backup is not active on this device after loading from secret storage.`
- Meaning: secret storage did not produce an active backup session on this device.
- What to do: verify the device first, then recheck with `openclaw matrix verify backup status`.
`Matrix crypto backend cannot load backup keys from secret storage. Verify this device with 'openclaw matrix verify device <key>' first.`
- Meaning: this device cannot restore from secret storage until device verification is complete.
- What to do: run `openclaw matrix verify device "<your-recovery-key>"` first.
### Custom plugin install messages
`Matrix is installed from a custom path that no longer exists: ...`
- Meaning: your plugin install record points at a local path that is gone.
- What to do: reinstall with `openclaw plugins install @openclaw/matrix`, or if you are running from a repo checkout, `openclaw plugins install ./path/to/local/matrix-plugin`.
## If encrypted history still does not come back
Run these checks in order:
```bash
openclaw matrix verify status --verbose
openclaw matrix verify backup status --verbose
openclaw matrix verify backup restore --recovery-key "<your-recovery-key>" --verbose
```
If the backup restores successfully but some old rooms are still missing history, those missing keys were probably never backed up by the previous plugin.
## If you want to start fresh for future messages
If you accept losing unrecoverable old encrypted history and only want a clean backup baseline going forward, run these commands in order:
```bash
openclaw matrix verify backup reset --yes
openclaw matrix verify backup status --verbose
openclaw matrix verify status
```
If the device is still unverified after that, finish verification from your Matrix client by comparing the SAS emoji or decimal codes and confirming that they match.
## Related pages
- [Matrix](/channels/matrix)
- [Doctor](/gateway/doctor)
- [Migrating](/install/migrating)
- [Plugins](/tools/plugin)

View file

@ -0,0 +1,112 @@
---
summary: "Move (migrate) an OpenClaw install from one machine to another"
read_when:
- You are moving OpenClaw to a new laptop/server
- You want to preserve sessions, auth, and channel logins (WhatsApp, etc.)
title: "Migration Guide"
---
# Migrating OpenClaw to a New Machine
This guide moves an OpenClaw gateway to a new machine without redoing onboarding.
## What Gets Migrated
When you copy the **state directory** (`~/.openclaw/` by default) and your **workspace**, you preserve:
- **Config** -- `openclaw.json` and all gateway settings
- **Auth** -- per-agent `auth-profiles.json` (API keys + OAuth), plus any channel/provider state under `credentials/`
- **Sessions** -- conversation history and agent state
- **Channel state** -- WhatsApp login, Telegram session, etc.
- **Workspace files** -- `MEMORY.md`, `USER.md`, skills, and prompts
<Tip>
Run `openclaw status` on the old machine to confirm your state directory path.
Custom profiles use `~/.openclaw-<profile>/` or a path set via `OPENCLAW_STATE_DIR`.
</Tip>
## Migration Steps
<Steps>
<Step title="Stop the gateway and back up">
On the **old** machine, stop the gateway so files are not changing mid-copy, then archive:
```bash
openclaw gateway stop
cd ~
tar -czf openclaw-state.tgz .openclaw
```
If you use multiple profiles (e.g. `~/.openclaw-work`), archive each separately.
</Step>
<Step title="Install OpenClaw on the new machine">
[Install](/install) the CLI (and Node if needed) on the new machine.
It is fine if onboarding creates a fresh `~/.openclaw/` -- you will overwrite it next.
</Step>
<Step title="Copy state directory and workspace">
Transfer the archive via `scp`, `rsync -a`, or an external drive, then extract:
```bash
cd ~
tar -xzf openclaw-state.tgz
```
Ensure hidden directories were included and file ownership matches the user that will run the gateway.
</Step>
<Step title="Run doctor and verify">
On the new machine, run [Doctor](/gateway/doctor) to apply config migrations and repair services:
```bash
openclaw doctor
openclaw gateway restart
openclaw status
```
</Step>
</Steps>
## Common Pitfalls
<AccordionGroup>
<Accordion title="Profile or state-dir mismatch">
If the old gateway used `--profile` or `OPENCLAW_STATE_DIR` and the new one does not,
channels will appear logged out and sessions will be empty.
Launch the gateway with the **same** profile or state-dir you migrated, then rerun `openclaw doctor`.
</Accordion>
<Accordion title="Copying only openclaw.json">
The config file alone is not enough. Model auth profiles live under
`agents/<agentId>/agent/auth-profiles.json`, and channel/provider state still
lives under `credentials/`. Always migrate the **entire** state directory.
</Accordion>
<Accordion title="Permissions and ownership">
If you copied as root or switched users, the gateway may fail to read credentials.
Ensure the state directory and workspace are owned by the user running the gateway.
</Accordion>
<Accordion title="Remote mode">
If your UI points at a **remote** gateway, the remote host owns sessions and workspace.
Migrate the gateway host itself, not your local laptop. See [FAQ](/help/faq#where-things-live-on-disk).
</Accordion>
<Accordion title="Secrets in backups">
The state directory contains auth profiles, channel credentials, and other
provider state.
Store backups encrypted, avoid insecure transfer channels, and rotate keys if you suspect exposure.
</Accordion>
</AccordionGroup>
## Verification Checklist
On the new machine, confirm:
- [ ] `openclaw status` shows the gateway running
- [ ] Channels are still connected (no re-pairing needed)
- [ ] The dashboard opens and shows existing sessions
- [ ] Workspace files (memory, configs) are present

View file

@ -0,0 +1,89 @@
---
summary: "Install OpenClaw declaratively with Nix"
read_when:
- You want reproducible, rollback-able installs
- You're already using Nix/NixOS/Home Manager
- You want everything pinned and managed declaratively
title: "Nix"
---
# Nix Installation
Install OpenClaw declaratively with **[nix-openclaw](https://github.com/openclaw/nix-openclaw)** -- a batteries-included Home Manager module.
<Info>
The [nix-openclaw](https://github.com/openclaw/nix-openclaw) repo is the source of truth for Nix installation. This page is a quick overview.
</Info>
## What You Get
- Gateway + macOS app + tools (whisper, spotify, cameras) -- all pinned
- Launchd service that survives reboots
- Plugin system with declarative config
- Instant rollback: `home-manager switch --rollback`
## Quick Start
<Steps>
<Step title="Install Determinate Nix">
If Nix is not already installed, follow the [Determinate Nix installer](https://github.com/DeterminateSystems/nix-installer) instructions.
</Step>
<Step title="Create a local flake">
Use the agent-first template from the nix-openclaw repo:
```bash
mkdir -p ~/code/openclaw-local
# Copy templates/agent-first/flake.nix from the nix-openclaw repo
```
</Step>
<Step title="Configure secrets">
Set up your messaging bot token and model provider API key. Plain files at `~/.secrets/` work fine.
</Step>
<Step title="Fill in template placeholders and switch">
```bash
home-manager switch
```
</Step>
<Step title="Verify">
Confirm the launchd service is running and your bot responds to messages.
</Step>
</Steps>
See the [nix-openclaw README](https://github.com/openclaw/nix-openclaw) for full module options and examples.
## Nix Mode Runtime Behavior
When `OPENCLAW_NIX_MODE=1` is set (automatic with nix-openclaw), OpenClaw enters a deterministic mode that disables auto-install flows.
You can also set it manually:
```bash
export OPENCLAW_NIX_MODE=1
```
On macOS, the GUI app does not automatically inherit shell environment variables. Enable Nix mode via defaults instead:
```bash
defaults write ai.openclaw.mac openclaw.nixMode -bool true
```
### What changes in Nix mode
- Auto-install and self-mutation flows are disabled
- Missing dependencies surface Nix-specific remediation messages
- UI surfaces a read-only Nix mode banner
### Config and state paths
OpenClaw reads JSON5 config from `OPENCLAW_CONFIG_PATH` and stores mutable data in `OPENCLAW_STATE_DIR`. When running under Nix, set these explicitly to Nix-managed locations so runtime state and config stay out of the immutable store.
| Variable | Default |
| ---------------------- | --------------------------------------- |
| `OPENCLAW_HOME` | `HOME` / `USERPROFILE` / `os.homedir()` |
| `OPENCLAW_STATE_DIR` | `~/.openclaw` |
| `OPENCLAW_CONFIG_PATH` | `$OPENCLAW_STATE_DIR/openclaw.json` |
## Related
- [nix-openclaw](https://github.com/openclaw/nix-openclaw) -- full setup guide
- [Wizard](/start/wizard) -- non-Nix CLI setup
- [Docker](/install/docker) -- containerized setup

View file

@ -0,0 +1,144 @@
---
title: "Node.js"
summary: "Install and configure Node.js for OpenClaw — version requirements, install options, and PATH troubleshooting"
read_when:
- "You need to install Node.js before installing OpenClaw"
- "You installed OpenClaw but `openclaw` is command not found"
- "npm install -g fails with permissions or PATH issues"
---
# Node.js
OpenClaw requires **Node 22.14 or newer**. **Node 24 is the default and recommended runtime** for installs, CI, and release workflows. Node 22 remains supported via the active LTS line. The [installer script](/install#alternative-install-methods) will detect and install Node automatically — this page is for when you want to set up Node yourself and make sure everything is wired up correctly (versions, PATH, global installs).
## Check your version
```bash
node -v
```
If this prints `v24.x.x` or higher, you're on the recommended default. If it prints `v22.14.x` or higher, you're on the supported Node 22 LTS path, but we still recommend upgrading to Node 24 when convenient. If Node isn't installed or the version is too old, pick an install method below.
## Install Node
<Tabs>
<Tab title="macOS">
**Homebrew** (recommended):
```bash
brew install node
```
Or download the macOS installer from [nodejs.org](https://nodejs.org/).
</Tab>
<Tab title="Linux">
**Ubuntu / Debian:**
```bash
curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
sudo apt-get install -y nodejs
```
**Fedora / RHEL:**
```bash
sudo dnf install nodejs
```
Or use a version manager (see below).
</Tab>
<Tab title="Windows">
**winget** (recommended):
```powershell
winget install OpenJS.NodeJS.LTS
```
**Chocolatey:**
```powershell
choco install nodejs-lts
```
Or download the Windows installer from [nodejs.org](https://nodejs.org/).
</Tab>
</Tabs>
<Accordion title="Using a version manager (nvm, fnm, mise, asdf)">
Version managers let you switch between Node versions easily. Popular options:
- [**fnm**](https://github.com/Schniz/fnm) — fast, cross-platform
- [**nvm**](https://github.com/nvm-sh/nvm) — widely used on macOS/Linux
- [**mise**](https://mise.jdx.dev/) — polyglot (Node, Python, Ruby, etc.)
Example with fnm:
```bash
fnm install 24
fnm use 24
```
<Warning>
Make sure your version manager is initialized in your shell startup file (`~/.zshrc` or `~/.bashrc`). If it isn't, `openclaw` may not be found in new terminal sessions because the PATH won't include Node's bin directory.
</Warning>
</Accordion>
## Troubleshooting
### `openclaw: command not found`
This almost always means npm's global bin directory isn't on your PATH.
<Steps>
<Step title="Find your global npm prefix">
```bash
npm prefix -g
```
</Step>
<Step title="Check if it's on your PATH">
```bash
echo "$PATH"
```
Look for `<npm-prefix>/bin` (macOS/Linux) or `<npm-prefix>` (Windows) in the output.
</Step>
<Step title="Add it to your shell startup file">
<Tabs>
<Tab title="macOS / Linux">
Add to `~/.zshrc` or `~/.bashrc`:
```bash
export PATH="$(npm prefix -g)/bin:$PATH"
```
Then open a new terminal (or run `rehash` in zsh / `hash -r` in bash).
</Tab>
<Tab title="Windows">
Add the output of `npm prefix -g` to your system PATH via Settings → System → Environment Variables.
</Tab>
</Tabs>
</Step>
</Steps>
### Permission errors on `npm install -g` (Linux)
If you see `EACCES` errors, switch npm's global prefix to a user-writable directory:
```bash
mkdir -p "$HOME/.npm-global"
npm config set prefix "$HOME/.npm-global"
export PATH="$HOME/.npm-global/bin:$PATH"
```
Add the `export PATH=...` line to your `~/.bashrc` or `~/.zshrc` to make it permanent.
## Related
- [Install Overview](/install) — all installation methods
- [Updating](/install/updating) — keeping OpenClaw up to date
- [Getting Started](/start/getting-started) — first steps after install

View file

@ -0,0 +1,42 @@
---
summary: "Deploy OpenClaw on Northflank with one-click template"
read_when:
- Deploying OpenClaw to Northflank
- You want a one-click cloud deploy with browser-based Control UI
title: "Northflank"
---
Deploy OpenClaw on Northflank with a one-click template and access it through the web Control UI.
This is the easiest "no terminal on the server" path: Northflank runs the Gateway for you.
## How to get started
1. Click [Deploy OpenClaw](https://northflank.com/stacks/deploy-openclaw) to open the template.
2. Create an [account on Northflank](https://app.northflank.com/signup) if you don't already have one.
3. Click **Deploy OpenClaw now**.
4. Set the required environment variable: `OPENCLAW_GATEWAY_TOKEN` (use a strong random value).
5. Click **Deploy stack** to build and run the OpenClaw template.
6. Wait for the deployment to complete, then click **View resources**.
7. Open the OpenClaw service.
8. Open the public OpenClaw URL at `/openclaw` and connect using the configured shared secret. This template uses `OPENCLAW_GATEWAY_TOKEN` by default; if you replace it with password auth, use that password instead.
## What you get
- Hosted OpenClaw Gateway + Control UI
- Persistent storage via Northflank Volume (`/data`) so `openclaw.json`,
per-agent `auth-profiles.json`, channel/provider state, sessions, and
workspace survive redeploys
## Connect a channel
Use the Control UI at `/openclaw` or run `openclaw onboard` via SSH for channel setup instructions:
- [Telegram](/channels/telegram) (fastest — just a bot token)
- [Discord](/channels/discord)
- [All channels](/channels)
## Next steps
- Set up messaging channels: [Channels](/channels)
- Configure the Gateway: [Gateway configuration](/gateway/configuration)
- Keep OpenClaw up to date: [Updating](/install/updating)

View file

@ -0,0 +1,158 @@
---
summary: "Host OpenClaw on Oracle Cloud's Always Free ARM tier"
read_when:
- Setting up OpenClaw on Oracle Cloud
- Looking for free VPS hosting for OpenClaw
- Want 24/7 OpenClaw on a small server
title: "Oracle Cloud"
---
# Oracle Cloud
Run a persistent OpenClaw Gateway on Oracle Cloud's **Always Free** ARM tier (up to 4 OCPU, 24 GB RAM, 200 GB storage) at no cost.
## Prerequisites
- Oracle Cloud account ([signup](https://www.oracle.com/cloud/free/)) -- see [community signup guide](https://gist.github.com/rssnyder/51e3cfedd730e7dd5f4a816143b25dbd) if you hit issues
- Tailscale account (free at [tailscale.com](https://tailscale.com))
- An SSH key pair
- About 30 minutes
## Setup
<Steps>
<Step title="Create an OCI instance">
1. Log into [Oracle Cloud Console](https://cloud.oracle.com/).
2. Navigate to **Compute > Instances > Create Instance**.
3. Configure:
- **Name:** `openclaw`
- **Image:** Ubuntu 24.04 (aarch64)
- **Shape:** `VM.Standard.A1.Flex` (Ampere ARM)
- **OCPUs:** 2 (or up to 4)
- **Memory:** 12 GB (or up to 24 GB)
- **Boot volume:** 50 GB (up to 200 GB free)
- **SSH key:** Add your public key
4. Click **Create** and note the public IP address.
<Tip>
If instance creation fails with "Out of capacity", try a different availability domain or retry later. Free tier capacity is limited.
</Tip>
</Step>
<Step title="Connect and update the system">
```bash
ssh ubuntu@YOUR_PUBLIC_IP
sudo apt update && sudo apt upgrade -y
sudo apt install -y build-essential
```
`build-essential` is required for ARM compilation of some dependencies.
</Step>
<Step title="Configure user and hostname">
```bash
sudo hostnamectl set-hostname openclaw
sudo passwd ubuntu
sudo loginctl enable-linger ubuntu
```
Enabling linger keeps user services running after logout.
</Step>
<Step title="Install Tailscale">
```bash
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up --ssh --hostname=openclaw
```
From now on, connect via Tailscale: `ssh ubuntu@openclaw`.
</Step>
<Step title="Install OpenClaw">
```bash
curl -fsSL https://openclaw.ai/install.sh | bash
source ~/.bashrc
```
When prompted "How do you want to hatch your bot?", select **Do this later**.
</Step>
<Step title="Configure the gateway">
Use token auth with Tailscale Serve for secure remote access.
```bash
openclaw config set gateway.bind loopback
openclaw config set gateway.auth.mode token
openclaw doctor --generate-gateway-token
openclaw config set gateway.tailscale.mode serve
openclaw config set gateway.trustedProxies '["127.0.0.1"]'
systemctl --user restart openclaw-gateway.service
```
`gateway.trustedProxies=["127.0.0.1"]` here is only for the local Tailscale Serve proxy's forwarded-IP/local-client handling. It is **not** `gateway.auth.mode: "trusted-proxy"`. Diff viewer routes keep fail-closed behavior in this setup: raw `127.0.0.1` viewer requests without forwarded proxy headers can return `Diff not found`. Use `mode=file` / `mode=both` for attachments, or intentionally enable remote viewers and set `plugins.entries.diffs.config.viewerBaseUrl` (or pass a proxy `baseUrl`) if you need shareable viewer links.
</Step>
<Step title="Lock down VCN security">
Block all traffic except Tailscale at the network edge:
1. Go to **Networking > Virtual Cloud Networks** in the OCI Console.
2. Click your VCN, then **Security Lists > Default Security List**.
3. **Remove** all ingress rules except `0.0.0.0/0 UDP 41641` (Tailscale).
4. Keep default egress rules (allow all outbound).
This blocks SSH on port 22, HTTP, HTTPS, and everything else at the network edge. You can only connect via Tailscale from this point on.
</Step>
<Step title="Verify">
```bash
openclaw --version
systemctl --user status openclaw-gateway.service
tailscale serve status
curl http://localhost:18789
```
Access the Control UI from any device on your tailnet:
```
https://openclaw.<tailnet-name>.ts.net/
```
Replace `<tailnet-name>` with your tailnet name (visible in `tailscale status`).
</Step>
</Steps>
## Fallback: SSH tunnel
If Tailscale Serve is not working, use an SSH tunnel from your local machine:
```bash
ssh -L 18789:127.0.0.1:18789 ubuntu@openclaw
```
Then open `http://localhost:18789`.
## Troubleshooting
**Instance creation fails ("Out of capacity")** -- Free tier ARM instances are popular. Try a different availability domain or retry during off-peak hours.
**Tailscale will not connect** -- Run `sudo tailscale up --ssh --hostname=openclaw --reset` to re-authenticate.
**Gateway will not start** -- Run `openclaw doctor --non-interactive` and check logs with `journalctl --user -u openclaw-gateway.service -n 50`.
**ARM binary issues** -- Most npm packages work on ARM64. For native binaries, look for `linux-arm64` or `aarch64` releases. Verify architecture with `uname -m`.
## Next steps
- [Channels](/channels) -- connect Telegram, WhatsApp, Discord, and more
- [Gateway configuration](/gateway/configuration) -- all config options
- [Updating](/install/updating) -- keep OpenClaw up to date

View file

@ -0,0 +1,210 @@
---
summary: "Run OpenClaw in a rootless Podman container"
read_when:
- You want a containerized gateway with Podman instead of Docker
title: "Podman"
---
# Podman
Run the OpenClaw Gateway in a rootless Podman container, managed by your current non-root user.
The intended model is:
- Podman runs the gateway container.
- Your host `openclaw` CLI is the control plane.
- Persistent state lives on the host under `~/.openclaw` by default.
- Day-to-day management uses `openclaw --container <name> ...` instead of `sudo -u openclaw`, `podman exec`, or a separate service user.
## Prerequisites
- **Podman** in rootless mode
- **OpenClaw CLI** installed on the host
- **Optional:** `systemd --user` if you want Quadlet-managed auto-start
- **Optional:** `sudo` only if you want `loginctl enable-linger "$(whoami)"` for boot persistence on a headless host
## Quick start
<Steps>
<Step title="One-time setup">
From the repo root, run `./scripts/podman/setup.sh`.
</Step>
<Step title="Start the Gateway container">
Start the container with `./scripts/run-openclaw-podman.sh launch`.
</Step>
<Step title="Run onboarding inside the container">
Run `./scripts/run-openclaw-podman.sh launch setup`, then open `http://127.0.0.1:18789/`.
</Step>
<Step title="Manage the running container from the host CLI">
Set `OPENCLAW_CONTAINER=openclaw`, then use normal `openclaw` commands from the host.
</Step>
</Steps>
Setup details:
- `./scripts/podman/setup.sh` builds `openclaw:local` in your rootless Podman store by default, or uses `OPENCLAW_IMAGE` / `OPENCLAW_PODMAN_IMAGE` if you set one.
- It creates `~/.openclaw/openclaw.json` with `gateway.mode: "local"` if missing.
- It creates `~/.openclaw/.env` with `OPENCLAW_GATEWAY_TOKEN` if missing.
- For manual launches, the helper reads only a small allowlist of Podman-related keys from `~/.openclaw/.env` and passes explicit runtime env vars to the container; it does not hand the full env file to Podman.
Quadlet-managed setup:
```bash
./scripts/podman/setup.sh --quadlet
```
Quadlet is a Linux-only option because it depends on systemd user services.
You can also set `OPENCLAW_PODMAN_QUADLET=1`.
Optional build/setup env vars:
- `OPENCLAW_IMAGE` or `OPENCLAW_PODMAN_IMAGE` -- use an existing/pulled image instead of building `openclaw:local`
- `OPENCLAW_DOCKER_APT_PACKAGES` -- install extra apt packages during image build
- `OPENCLAW_EXTENSIONS` -- pre-install extension dependencies at build time
Container start:
```bash
./scripts/run-openclaw-podman.sh launch
```
The script starts the container as your current uid/gid with `--userns=keep-id` and bind-mounts your OpenClaw state into the container.
Onboarding:
```bash
./scripts/run-openclaw-podman.sh launch setup
```
Then open `http://127.0.0.1:18789/` and use the token from `~/.openclaw/.env`.
Host CLI default:
```bash
export OPENCLAW_CONTAINER=openclaw
```
Then commands such as these will run inside that container automatically:
```bash
openclaw dashboard --no-open
openclaw gateway status --deep # includes extra service scan
openclaw doctor
openclaw channels login
```
On macOS, Podman machine may make the browser appear non-local to the gateway.
If the Control UI reports device-auth errors after launch, use the Tailscale guidance in
[Podman + Tailscale](#podman--tailscale).
<a id="podman--tailscale"></a>
## Podman + Tailscale
For HTTPS or remote browser access, follow the main Tailscale docs.
Podman-specific note:
- Keep the Podman publish host at `127.0.0.1`.
- Prefer host-managed `tailscale serve` over `openclaw gateway --tailscale serve`.
- On macOS, if local browser device-auth context is unreliable, use Tailscale access instead of ad hoc local tunnel workarounds.
See:
- [Tailscale](/gateway/tailscale)
- [Control UI](/web/control-ui)
## Systemd (Quadlet, optional)
If you ran `./scripts/podman/setup.sh --quadlet`, setup installs a Quadlet file at:
```bash
~/.config/containers/systemd/openclaw.container
```
Useful commands:
- **Start:** `systemctl --user start openclaw.service`
- **Stop:** `systemctl --user stop openclaw.service`
- **Status:** `systemctl --user status openclaw.service`
- **Logs:** `journalctl --user -u openclaw.service -f`
After editing the Quadlet file:
```bash
systemctl --user daemon-reload
systemctl --user restart openclaw.service
```
For boot persistence on SSH/headless hosts, enable lingering for your current user:
```bash
sudo loginctl enable-linger "$(whoami)"
```
## Config, env, and storage
- **Config dir:** `~/.openclaw`
- **Workspace dir:** `~/.openclaw/workspace`
- **Token file:** `~/.openclaw/.env`
- **Launch helper:** `./scripts/run-openclaw-podman.sh`
The launch script and Quadlet bind-mount host state into the container:
- `OPENCLAW_CONFIG_DIR` -> `/home/node/.openclaw`
- `OPENCLAW_WORKSPACE_DIR` -> `/home/node/.openclaw/workspace`
By default those are host directories, not anonymous container state, so
`openclaw.json`, per-agent `auth-profiles.json`, channel/provider state,
sessions, and workspace survive container replacement.
The Podman setup also seeds `gateway.controlUi.allowedOrigins` for `127.0.0.1` and `localhost` on the published gateway port so the local dashboard works with the container's non-loopback bind.
Useful env vars for the manual launcher:
- `OPENCLAW_PODMAN_CONTAINER` -- container name (`openclaw` by default)
- `OPENCLAW_PODMAN_IMAGE` / `OPENCLAW_IMAGE` -- image to run
- `OPENCLAW_PODMAN_GATEWAY_HOST_PORT` -- host port mapped to container `18789`
- `OPENCLAW_PODMAN_BRIDGE_HOST_PORT` -- host port mapped to container `18790`
- `OPENCLAW_PODMAN_PUBLISH_HOST` -- host interface for published ports; default is `127.0.0.1`
- `OPENCLAW_GATEWAY_BIND` -- gateway bind mode inside the container; default is `lan`
- `OPENCLAW_PODMAN_USERNS` -- `keep-id` (default), `auto`, or `host`
The manual launcher reads `~/.openclaw/.env` before finalizing container/image defaults, so you can persist these there.
If you use a non-default `OPENCLAW_CONFIG_DIR` or `OPENCLAW_WORKSPACE_DIR`, set the same variables for both `./scripts/podman/setup.sh` and later `./scripts/run-openclaw-podman.sh launch` commands. The repo-local launcher does not persist custom path overrides across shells.
Quadlet note:
- The generated Quadlet service intentionally keeps a fixed, hardened default shape: `127.0.0.1` published ports, `--bind lan` inside the container, and `keep-id` user namespace.
- It pins `OPENCLAW_NO_RESPAWN=1`, `Restart=on-failure`, and `TimeoutStartSec=300`.
- It publishes both `127.0.0.1:18789:18789` (gateway) and `127.0.0.1:18790:18790` (bridge).
- It reads `~/.openclaw/.env` as a runtime `EnvironmentFile` for values such as `OPENCLAW_GATEWAY_TOKEN`, but it does not consume the manual launcher's Podman-specific override allowlist.
- If you need custom publish ports, publish host, or other container-run flags, use the manual launcher or edit `~/.config/containers/systemd/openclaw.container` directly, then reload and restart the service.
## Useful commands
- **Container logs:** `podman logs -f openclaw`
- **Stop container:** `podman stop openclaw`
- **Remove container:** `podman rm -f openclaw`
- **Open dashboard URL from host CLI:** `openclaw dashboard --no-open`
- **Health/status via host CLI:** `openclaw gateway status --deep` (RPC probe + extra
service scan)
## Troubleshooting
- **Permission denied (EACCES) on config or workspace:** The container runs with `--userns=keep-id` and `--user <your uid>:<your gid>` by default. Ensure the host config/workspace paths are owned by your current user.
- **Gateway start blocked (missing `gateway.mode=local`):** Ensure `~/.openclaw/openclaw.json` exists and sets `gateway.mode="local"`. `scripts/podman/setup.sh` creates this if missing.
- **Container CLI commands hit the wrong target:** Use `openclaw --container <name> ...` explicitly, or export `OPENCLAW_CONTAINER=<name>` in your shell.
- **`openclaw update` fails with `--container`:** Expected. Rebuild/pull the image, then restart the container or the Quadlet service.
- **Quadlet service does not start:** Run `systemctl --user daemon-reload`, then `systemctl --user start openclaw.service`. On headless systems you may also need `sudo loginctl enable-linger "$(whoami)"`.
- **SELinux blocks bind mounts:** Leave the default mount behavior alone; the launcher auto-adds `:Z` on Linux when SELinux is enforcing or permissive.
## Related
- [Docker](/install/docker)
- [Gateway background process](/gateway/background-process)
- [Gateway troubleshooting](/gateway/troubleshooting)

View file

@ -0,0 +1,90 @@
---
summary: "Deploy OpenClaw on Railway with one-click template"
read_when:
- Deploying OpenClaw to Railway
- You want a one-click cloud deploy with browser-based Control UI
title: "Railway"
---
Deploy OpenClaw on Railway with a one-click template and access it through the web Control UI.
This is the easiest "no terminal on the server" path: Railway runs the Gateway for you.
## Quick checklist (new users)
1. Click **Deploy on Railway** (below).
2. Add a **Volume** mounted at `/data`.
3. Set the required **Variables** (at least `OPENCLAW_GATEWAY_PORT` and `OPENCLAW_GATEWAY_TOKEN`).
4. Enable **HTTP Proxy** on port `8080`.
5. Open `https://<your-railway-domain>/openclaw` and connect using the configured shared secret. This template uses `OPENCLAW_GATEWAY_TOKEN` by default; if you replace it with password auth, use that password instead.
## One-click deploy
<a href="https://railway.com/deploy/clawdbot-railway-template" target="_blank" rel="noreferrer">
Deploy on Railway
</a>
After deploy, find your public URL in **Railway → your service → Settings → Domains**.
Railway will either:
- give you a generated domain (often `https://<something>.up.railway.app`), or
- use your custom domain if you attached one.
Then open:
- `https://<your-railway-domain>/openclaw` — Control UI
## What you get
- Hosted OpenClaw Gateway + Control UI
- Persistent storage via Railway Volume (`/data`) so `openclaw.json`,
per-agent `auth-profiles.json`, channel/provider state, sessions, and
workspace survive redeploys
## Required Railway settings
### Public Networking
Enable **HTTP Proxy** for the service.
- Port: `8080`
### Volume (required)
Attach a volume mounted at:
- `/data`
### Variables
Set these variables on the service:
- `OPENCLAW_GATEWAY_PORT=8080` (required — must match the port in Public Networking)
- `OPENCLAW_GATEWAY_TOKEN` (required; treat as an admin secret)
- `OPENCLAW_STATE_DIR=/data/.openclaw` (recommended)
- `OPENCLAW_WORKSPACE_DIR=/data/workspace` (recommended)
## Connect a channel
Use the Control UI at `/openclaw` or run `openclaw onboard` via Railway's shell for channel setup instructions:
- [Telegram](/channels/telegram) (fastest — just a bot token)
- [Discord](/channels/discord)
- [All channels](/channels)
## Backups & migration
Export your state, config, auth profiles, and workspace:
```bash
openclaw backup create
```
This creates a portable backup archive with OpenClaw state plus any configured
workspace. See [Backup](/cli/backup) for details.
## Next steps
- Set up messaging channels: [Channels](/channels)
- Configure the Gateway: [Gateway configuration](/gateway/configuration)
- Keep OpenClaw up to date: [Updating](/install/updating)

View file

@ -0,0 +1,159 @@
---
summary: "Host OpenClaw on a Raspberry Pi for always-on self-hosting"
read_when:
- Setting up OpenClaw on a Raspberry Pi
- Running OpenClaw on ARM devices
- Building a cheap always-on personal AI
title: "Raspberry Pi"
---
# Raspberry Pi
Run a persistent, always-on OpenClaw Gateway on a Raspberry Pi. Since the Pi is just the gateway (models run in the cloud via API), even a modest Pi handles the workload well.
## Prerequisites
- Raspberry Pi 4 or 5 with 2 GB+ RAM (4 GB recommended)
- MicroSD card (16 GB+) or USB SSD (better performance)
- Official Pi power supply
- Network connection (Ethernet or WiFi)
- 64-bit Raspberry Pi OS (required -- do not use 32-bit)
- About 30 minutes
## Setup
<Steps>
<Step title="Flash the OS">
Use **Raspberry Pi OS Lite (64-bit)** -- no desktop needed for a headless server.
1. Download [Raspberry Pi Imager](https://www.raspberrypi.com/software/).
2. Choose OS: **Raspberry Pi OS Lite (64-bit)**.
3. In the settings dialog, pre-configure:
- Hostname: `gateway-host`
- Enable SSH
- Set username and password
- Configure WiFi (if not using Ethernet)
4. Flash to your SD card or USB drive, insert it, and boot the Pi.
</Step>
<Step title="Connect via SSH">
```bash
ssh user@gateway-host
```
</Step>
<Step title="Update the system">
```bash
sudo apt update && sudo apt upgrade -y
sudo apt install -y git curl build-essential
# Set timezone (important for cron and reminders)
sudo timedatectl set-timezone America/Chicago
```
</Step>
<Step title="Install Node.js 24">
```bash
curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
sudo apt install -y nodejs
node --version
```
</Step>
<Step title="Add swap (important for 2 GB or less)">
```bash
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
# Reduce swappiness for low-RAM devices
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
```
</Step>
<Step title="Install OpenClaw">
```bash
curl -fsSL https://openclaw.ai/install.sh | bash
```
</Step>
<Step title="Run onboarding">
```bash
openclaw onboard --install-daemon
```
Follow the wizard. API keys are recommended over OAuth for headless devices. Telegram is the easiest channel to start with.
</Step>
<Step title="Verify">
```bash
openclaw status
systemctl --user status openclaw-gateway.service
journalctl --user -u openclaw-gateway.service -f
```
</Step>
<Step title="Access the Control UI">
On your computer, get a dashboard URL from the Pi:
```bash
ssh user@gateway-host 'openclaw dashboard --no-open'
```
Then create an SSH tunnel in another terminal:
```bash
ssh -N -L 18789:127.0.0.1:18789 user@gateway-host
```
Open the printed URL in your local browser. For always-on remote access, see [Tailscale integration](/gateway/tailscale).
</Step>
</Steps>
## Performance tips
**Use a USB SSD** -- SD cards are slow and wear out. A USB SSD dramatically improves performance. See the [Pi USB boot guide](https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#usb-mass-storage-boot).
**Enable module compile cache** -- Speeds up repeated CLI invocations on lower-power Pi hosts:
```bash
grep -q 'NODE_COMPILE_CACHE=/var/tmp/openclaw-compile-cache' ~/.bashrc || cat >> ~/.bashrc <<'EOF' # pragma: allowlist secret
export NODE_COMPILE_CACHE=/var/tmp/openclaw-compile-cache
mkdir -p /var/tmp/openclaw-compile-cache
export OPENCLAW_NO_RESPAWN=1
EOF
source ~/.bashrc
```
**Reduce memory usage** -- For headless setups, free GPU memory and disable unused services:
```bash
echo 'gpu_mem=16' | sudo tee -a /boot/config.txt
sudo systemctl disable bluetooth
```
## Troubleshooting
**Out of memory** -- Verify swap is active with `free -h`. Disable unused services (`sudo systemctl disable cups bluetooth avahi-daemon`). Use API-based models only.
**Slow performance** -- Use a USB SSD instead of an SD card. Check for CPU throttling with `vcgencmd get_throttled` (should return `0x0`).
**Service will not start** -- Check logs with `journalctl --user -u openclaw-gateway.service --no-pager -n 100` and run `openclaw doctor --non-interactive`. If this is a headless Pi, also verify lingering is enabled: `sudo loginctl enable-linger "$(whoami)"`.
**ARM binary issues** -- If a skill fails with "exec format error", check whether the binary has an ARM64 build. Verify architecture with `uname -m` (should show `aarch64`).
**WiFi drops** -- Disable WiFi power management: `sudo iwconfig wlan0 power off`.
## Next steps
- [Channels](/channels) -- connect Telegram, WhatsApp, Discord, and more
- [Gateway configuration](/gateway/configuration) -- all config options
- [Updating](/install/updating) -- keep OpenClaw up to date

View file

@ -0,0 +1,165 @@
---
summary: "Deploy OpenClaw on Render with Infrastructure-as-Code"
read_when:
- Deploying OpenClaw to Render
- You want a declarative cloud deploy with Render Blueprints
title: "Render"
---
Deploy OpenClaw on Render using Infrastructure as Code. The included `render.yaml` Blueprint defines your entire stack declaratively, service, disk, environment variables, so you can deploy with a single click and version your infrastructure alongside your code.
## Prerequisites
- A [Render account](https://render.com) (free tier available)
- An API key from your preferred [model provider](/providers)
## Deploy with a Render Blueprint
[Deploy to Render](https://render.com/deploy?repo=https://github.com/openclaw/openclaw)
Clicking this link will:
1. Create a new Render service from the `render.yaml` Blueprint at the root of this repo.
2. Build the Docker image and deploy
Once deployed, your service URL follows the pattern `https://<service-name>.onrender.com`.
## Understanding the Blueprint
Render Blueprints are YAML files that define your infrastructure. The `render.yaml` in this
repository configures everything needed to run OpenClaw:
```yaml
services:
- type: web
name: openclaw
runtime: docker
plan: starter
healthCheckPath: /health
envVars:
- key: OPENCLAW_GATEWAY_PORT
value: "8080"
- key: OPENCLAW_STATE_DIR
value: /data/.openclaw
- key: OPENCLAW_WORKSPACE_DIR
value: /data/workspace
- key: OPENCLAW_GATEWAY_TOKEN
generateValue: true # auto-generates a secure token
disk:
name: openclaw-data
mountPath: /data
sizeGB: 1
```
Key Blueprint features used:
| Feature | Purpose |
| --------------------- | ---------------------------------------------------------- |
| `runtime: docker` | Builds from the repo's Dockerfile |
| `healthCheckPath` | Render monitors `/health` and restarts unhealthy instances |
| `generateValue: true` | Auto-generates a cryptographically secure value |
| `disk` | Persistent storage that survives redeploys |
## Choosing a plan
| Plan | Spin-down | Disk | Best for |
| --------- | ----------------- | ------------- | ----------------------------- |
| Free | After 15 min idle | Not available | Testing, demos |
| Starter | Never | 1GB+ | Personal use, small teams |
| Standard+ | Never | 1GB+ | Production, multiple channels |
The Blueprint defaults to `starter`. To use free tier, change `plan: free` in
your fork's `render.yaml` (but note: no persistent disk means OpenClaw state
resets on each deploy).
## After deployment
### Access the Control UI
The web dashboard is available at `https://<your-service>.onrender.com/`.
Connect using the configured shared secret. This deploy template auto-generates
`OPENCLAW_GATEWAY_TOKEN` (find it in **Dashboard → your service →
Environment**); if you replace it with password auth, use that password
instead.
## Render Dashboard features
### Logs
View real-time logs in **Dashboard → your service → Logs**. Filter by:
- Build logs (Docker image creation)
- Deploy logs (service startup)
- Runtime logs (application output)
### Shell access
For debugging, open a shell session via **Dashboard → your service → Shell**. The persistent disk is mounted at `/data`.
### Environment variables
Modify variables in **Dashboard → your service → Environment**. Changes trigger an automatic redeploy.
### Auto-deploy
If you use the original OpenClaw repository, Render will not auto-deploy your OpenClaw. To update it, run a manual Blueprint sync from the dashboard.
## Custom domain
1. Go to **Dashboard → your service → Settings → Custom Domains**
2. Add your domain
3. Configure DNS as instructed (CNAME to `*.onrender.com`)
4. Render provisions a TLS certificate automatically
## Scaling
Render supports horizontal and vertical scaling:
- **Vertical**: Change the plan to get more CPU/RAM
- **Horizontal**: Increase instance count (Standard plan and above)
For OpenClaw, vertical scaling is usually sufficient. Horizontal scaling requires sticky sessions or external state management.
## Backups and migration
Export your state, config, auth profiles, and workspace at any time using the
shell access in the Render Dashboard:
```bash
openclaw backup create
```
This creates a portable backup archive with OpenClaw state plus any configured
workspace. See [Backup](/cli/backup) for details.
## Troubleshooting
### Service will not start
Check the deploy logs in the Render Dashboard. Common issues:
- Missing `OPENCLAW_GATEWAY_TOKEN` — verify it is set in **Dashboard → Environment**
- Port mismatch — ensure `OPENCLAW_GATEWAY_PORT=8080` is set so the gateway binds to the port Render expects
### Slow cold starts (free tier)
Free tier services spin down after 15 minutes of inactivity. The first request after spin-down takes a few seconds while the container starts. Upgrade to Starter plan for always-on.
### Data loss after redeploy
This happens on free tier (no persistent disk). Upgrade to a paid plan, or
regularly export a full backup via `openclaw backup create` in the Render shell.
### Health check failures
Render expects a 200 response from `/health` within 30 seconds. If builds succeed but deploys fail, the service may be taking too long to start. Check:
- Build logs for errors
- Whether the container runs locally with `docker build && docker run`
## Next steps
- Set up messaging channels: [Channels](/channels)
- Configure the Gateway: [Gateway configuration](/gateway/configuration)
- Keep OpenClaw up to date: [Updating](/install/updating)

View file

@ -0,0 +1,128 @@
---
summary: "Uninstall OpenClaw completely (CLI, service, state, workspace)"
read_when:
- You want to remove OpenClaw from a machine
- The gateway service is still running after uninstall
title: "Uninstall"
---
# Uninstall
Two paths:
- **Easy path** if `openclaw` is still installed.
- **Manual service removal** if the CLI is gone but the service is still running.
## Easy path (CLI still installed)
Recommended: use the built-in uninstaller:
```bash
openclaw uninstall
```
Non-interactive (automation / npx):
```bash
openclaw uninstall --all --yes --non-interactive
npx -y openclaw uninstall --all --yes --non-interactive
```
Manual steps (same result):
1. Stop the gateway service:
```bash
openclaw gateway stop
```
2. Uninstall the gateway service (launchd/systemd/schtasks):
```bash
openclaw gateway uninstall
```
3. Delete state + config:
```bash
rm -rf "${OPENCLAW_STATE_DIR:-$HOME/.openclaw}"
```
If you set `OPENCLAW_CONFIG_PATH` to a custom location outside the state dir, delete that file too.
4. Delete your workspace (optional, removes agent files):
```bash
rm -rf ~/.openclaw/workspace
```
5. Remove the CLI install (pick the one you used):
```bash
npm rm -g openclaw
pnpm remove -g openclaw
bun remove -g openclaw
```
6. If you installed the macOS app:
```bash
rm -rf /Applications/OpenClaw.app
```
Notes:
- If you used profiles (`--profile` / `OPENCLAW_PROFILE`), repeat step 3 for each state dir (defaults are `~/.openclaw-<profile>`).
- In remote mode, the state dir lives on the **gateway host**, so run steps 1-4 there too.
## Manual service removal (CLI not installed)
Use this if the gateway service keeps running but `openclaw` is missing.
### macOS (launchd)
Default label is `ai.openclaw.gateway` (or `ai.openclaw.<profile>`; legacy `com.openclaw.*` may still exist):
```bash
launchctl bootout gui/$UID/ai.openclaw.gateway
rm -f ~/Library/LaunchAgents/ai.openclaw.gateway.plist
```
If you used a profile, replace the label and plist name with `ai.openclaw.<profile>`. Remove any legacy `com.openclaw.*` plists if present.
### Linux (systemd user unit)
Default unit name is `openclaw-gateway.service` (or `openclaw-gateway-<profile>.service`):
```bash
systemctl --user disable --now openclaw-gateway.service
rm -f ~/.config/systemd/user/openclaw-gateway.service
systemctl --user daemon-reload
```
### Windows (Scheduled Task)
Default task name is `OpenClaw Gateway` (or `OpenClaw Gateway (<profile>)`).
The task script lives under your state dir.
```powershell
schtasks /Delete /F /TN "OpenClaw Gateway"
Remove-Item -Force "$env:USERPROFILE\.openclaw\gateway.cmd"
```
If you used a profile, delete the matching task name and `~\.openclaw-<profile>\gateway.cmd`.
## Normal install vs source checkout
### Normal install (install.sh / npm / pnpm / bun)
If you used `https://openclaw.ai/install.sh` or `install.ps1`, the CLI was installed with `npm install -g openclaw@latest`.
Remove it with `npm rm -g openclaw` (or `pnpm remove -g` / `bun remove -g` if you installed that way).
### Source checkout (git clone)
If you run from a repo checkout (`git clone` + `openclaw ...` / `bun run openclaw ...`):
1. Uninstall the gateway service **before** deleting the repo (use the easy path above or manual service removal).
2. Delete the repo directory.
3. Remove state + workspace as shown above.

View file

@ -0,0 +1,143 @@
---
summary: "Updating OpenClaw safely (global install or source), plus rollback strategy"
read_when:
- Updating OpenClaw
- Something breaks after an update
title: "Updating"
---
# Updating
Keep OpenClaw up to date.
## Recommended: `openclaw update`
The fastest way to update. It detects your install type (npm or git), fetches the latest version, runs `openclaw doctor`, and restarts the gateway.
```bash
openclaw update
```
To switch channels or target a specific version:
```bash
openclaw update --channel beta
openclaw update --tag main
openclaw update --dry-run # preview without applying
```
`--channel beta` prefers beta, but the runtime falls back to stable/latest when
the beta tag is missing or older than the latest stable release. Use `--tag beta`
if you want the raw npm beta dist-tag for a one-off package update.
See [Development channels](/install/development-channels) for channel semantics.
## Alternative: re-run the installer
```bash
curl -fsSL https://openclaw.ai/install.sh | bash
```
Add `--no-onboard` to skip onboarding. For source installs, pass `--install-method git --no-onboard`.
## Alternative: manual npm, pnpm, or bun
```bash
npm i -g openclaw@latest
```
```bash
pnpm add -g openclaw@latest
```
```bash
bun add -g openclaw@latest
```
## Auto-updater
The auto-updater is off by default. Enable it in `~/.openclaw/openclaw.json`:
```json5
{
update: {
channel: "stable",
auto: {
enabled: true,
stableDelayHours: 6,
stableJitterHours: 12,
betaCheckIntervalHours: 1,
},
},
}
```
| Channel | Behavior |
| -------- | ------------------------------------------------------------------------------------------------------------- |
| `stable` | Waits `stableDelayHours`, then applies with deterministic jitter across `stableJitterHours` (spread rollout). |
| `beta` | Checks every `betaCheckIntervalHours` (default: hourly) and applies immediately. |
| `dev` | No automatic apply. Use `openclaw update` manually. |
The gateway also logs an update hint on startup (disable with `update.checkOnStart: false`).
## After updating
<Steps>
### Run doctor
```bash
openclaw doctor
```
Migrates config, audits DM policies, and checks gateway health. Details: [Doctor](/gateway/doctor)
### Restart the gateway
```bash
openclaw gateway restart
```
### Verify
```bash
openclaw health
```
</Steps>
## Rollback
### Pin a version (npm)
```bash
npm i -g openclaw@<version>
openclaw doctor
openclaw gateway restart
```
Tip: `npm view openclaw version` shows the current published version.
### Pin a commit (source)
```bash
git fetch origin
git checkout "$(git rev-list -n 1 --before=\"2026-01-01\" origin/main)"
pnpm install && pnpm build
openclaw gateway restart
```
To return to latest: `git checkout main && git pull`.
## If you are stuck
- Run `openclaw doctor` again and read the output carefully.
- For `openclaw update --channel dev` on source checkouts, the updater auto-bootstraps `pnpm` when needed. If you see a pnpm/corepack bootstrap error, install `pnpm` manually (or re-enable `corepack`) and rerun the update.
- Check: [Troubleshooting](/gateway/troubleshooting)
- Ask in Discord: [https://discord.gg/clawd](https://discord.gg/clawd)
## Related
- [Install Overview](/install) — all installation methods
- [Doctor](/gateway/doctor) — health checks after updates
- [Migrating](/install/migrating) — major version migration guides