Vendor OpenClaw source as Adolf fork baseline
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled
Adolf is a fork/vendored clone of github.com/openclaw/openclaw (v2026.6.11), free to diverge. Tree copied sans upstream .git; upstream remote added for future syncs. Node pinned to 24 (.nvmrc); engines already require >=22.19. Preserves docs/ARCHITECTURE.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
This commit is contained in:
225
docs/install/ansible.md
Normal file
225
docs/install/ansible.md
Normal file
@@ -0,0 +1,225 @@
|
||||
---
|
||||
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"
|
||||
---
|
||||
|
||||
Deploy OpenClaw to production servers with **[openclaw-ansible](https://github.com/openclaw/openclaw-ansible)**, an automated installer with a 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 reachable)
|
||||
- Tailscale VPN for remote access without exposing services publicly
|
||||
- Docker for isolated sandbox containers with localhost-only bindings
|
||||
- Systemd integration with hardening, auto-starting on boot
|
||||
- One-command setup
|
||||
|
||||
## Quick start
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/openclaw/openclaw-ansible/main/install.sh | bash
|
||||
```
|
||||
|
||||
## What gets installed
|
||||
|
||||
1. Tailscale (mesh VPN for secure remote access)
|
||||
2. UFW firewall (SSH + Tailscale ports only)
|
||||
3. Docker CE + Compose V2 (default agent sandbox backend)
|
||||
4. Node.js and pnpm (OpenClaw requires Node 22.19+ or 23.11+; Node 24 is recommended)
|
||||
5. OpenClaw, installed host-based, not containerized
|
||||
6. A systemd service with security hardening
|
||||
|
||||
<Note>
|
||||
The gateway runs directly on the host, not in Docker. Agent sandboxing is
|
||||
optional; this playbook installs Docker because it is the default sandbox
|
||||
backend. See [Sandboxing](/gateway/sandboxing) for other backends.
|
||||
</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.
|
||||
</Step>
|
||||
<Step title="Connect messaging channels">
|
||||
Log in to WhatsApp, Telegram, Discord, or Signal:
|
||||
```bash
|
||||
openclaw channels login --channel <name>
|
||||
```
|
||||
</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
|
||||
|
||||
# Channel login (run as openclaw user)
|
||||
sudo -i -u openclaw
|
||||
openclaw channels login --channel <name>
|
||||
```
|
||||
|
||||
## Security architecture
|
||||
|
||||
Four-layer defense model:
|
||||
|
||||
1. Firewall (UFW): only SSH (22) and Tailscale (41641/udp) exposed publicly
|
||||
2. VPN (Tailscale): gateway reachable only via the VPN mesh
|
||||
3. Docker isolation: `DOCKER-USER` iptables chain prevents external port exposure
|
||||
4. Systemd hardening: `NoNewPrivileges`, `PrivateTmp`, unprivileged user
|
||||
|
||||
Verify your external attack surface:
|
||||
|
||||
```bash
|
||||
nmap -p- YOUR_SERVER_IP
|
||||
```
|
||||
|
||||
Only port 22 (SSH) should be open. Gateway and Docker stay locked down.
|
||||
|
||||
Docker is installed for agent sandboxes (isolated tool execution), not for running the gateway. See [Multi-Agent Sandbox and Tools](/tools/multi-agent-sandbox-tools) for sandbox configuration.
|
||||
|
||||
## Manual installation
|
||||
|
||||
<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
|
||||
```
|
||||
|
||||
Or run the playbook directly and then run the setup script manually:
|
||||
```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 flow.
|
||||
|
||||
To re-run the playbook (for example, after 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">
|
||||
- Connect via Tailscale VPN first; the gateway is only reachable that way by design.
|
||||
- SSH (port 22) is always allowed.
|
||||
|
||||
</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 the sandbox image if missing (requires a source checkout)
|
||||
cd /opt/openclaw/openclaw
|
||||
sudo -u openclaw ./scripts/sandbox-setup.sh
|
||||
# For npm installs without a source checkout, see
|
||||
# https://docs.openclaw.ai/gateway/sandboxing#images-and-setup
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="Channel login fails">
|
||||
Make sure you are running as the `openclaw` user:
|
||||
```bash
|
||||
sudo -i -u openclaw
|
||||
openclaw channels login --channel <name>
|
||||
```
|
||||
</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
|
||||
316
docs/install/azure.md
Normal file
316
docs/install/azure.md
Normal file
@@ -0,0 +1,316 @@
|
||||
---
|
||||
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"
|
||||
---
|
||||
|
||||
Set up an Azure Linux VM with the Azure CLI, apply Network Security Group (NSG) hardening, configure Azure Bastion for SSH access, and install OpenClaw.
|
||||
|
||||
## What you will do
|
||||
|
||||
- Create Azure networking (VNet, subnets, NSG) and compute resources with the Azure CLI
|
||||
- Apply NSG 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))
|
||||
- An SSH key pair (this guide covers generating one if needed)
|
||||
- About 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 an SSH key">
|
||||
Use your existing public key if you have one:
|
||||
|
||||
```bash
|
||||
SSH_PUB_KEY="$(cat ~/.ssh/id_ed25519.pub)"
|
||||
```
|
||||
|
||||
Otherwise, 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
|
||||
```
|
||||
|
||||
- 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 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
|
||||
```
|
||||
|
||||
Rules evaluate 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: this exact 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 gets no public IP. SSH access goes 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 a per-NIC NSG since the subnet-level NSG already handles security.
|
||||
|
||||
To pin a specific Ubuntu image version instead of `latest`, list available versions first:
|
||||
|
||||
```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 gives managed SSH access without exposing a public IP on the VM. The Standard SKU with tunneling enabled 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 and dependencies if not already present, installs OpenClaw, and launches onboarding. See [Install](/install) for details.
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Verify the gateway">
|
||||
After onboarding completes:
|
||||
|
||||
```bash
|
||||
openclaw gateway status
|
||||
```
|
||||
|
||||
If your organization already has GitHub Copilot licenses, you can choose the GitHub Copilot provider during onboarding instead of a separate model API key. See [GitHub Copilot provider](/providers/github-copilot).
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Cost considerations
|
||||
|
||||
Approximate monthly costs (verify current pricing in the Azure Pricing Calculator, since rates vary by region and change over time):
|
||||
|
||||
- Azure Bastion Standard SKU: roughly $140/month
|
||||
- VM (`Standard_B2as_v2`): roughly $55/month
|
||||
|
||||
To reduce costs:
|
||||
|
||||
- Deallocate the VM when not in use. This stops compute billing (disk charges remain). The gateway is unreachable while deallocated.
|
||||
|
||||
```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 again; it is the largest cost component and provisions in a few minutes.
|
||||
- Use the Basic Bastion SKU (roughly $38/month) if you only need Portal-based SSH and do not need CLI tunneling (`az network bastion ssh`).
|
||||
|
||||
## Cleanup
|
||||
|
||||
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)
|
||||
- More detail on Azure deployment with the GitHub Copilot model provider: [OpenClaw on Azure with GitHub Copilot](https://github.com/johnsonshi/openclaw-azure-github-copilot)
|
||||
|
||||
## Related
|
||||
|
||||
- [Install overview](/install)
|
||||
- [GCP](/install/gcp)
|
||||
- [DigitalOcean](/install/digitalocean)
|
||||
59
docs/install/bun.md
Normal file
59
docs/install/bun.md
Normal file
@@ -0,0 +1,59 @@
|
||||
---
|
||||
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)"
|
||||
---
|
||||
|
||||
<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 ignores 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:
|
||||
|
||||
- `baileys` `preinstall`: checks Node major >= 20 (OpenClaw requires Node 22.19+ or 23.11+, with Node 24 recommended)
|
||||
- `protobufjs` `postinstall`: emits warnings about incompatible version schemes (no build artifacts)
|
||||
|
||||
If you hit a runtime issue that needs these scripts, trust them explicitly:
|
||||
|
||||
```sh
|
||||
bun pm trust baileys protobufjs
|
||||
```
|
||||
|
||||
## Caveats
|
||||
|
||||
Some package scripts hardcode `pnpm` internally (for example `check:docs`, `ui:*`, `protocol:check`). Running them via `bun run` still shells out to `pnpm`, so just run those via `pnpm` directly.
|
||||
|
||||
## Related
|
||||
|
||||
- [Install overview](/install)
|
||||
- [Node.js](/install/node)
|
||||
- [Updating](/install/updating)
|
||||
113
docs/install/clawdock.md
Normal file
113
docs/install/clawdock.md
Normal file
@@ -0,0 +1,113 @@
|
||||
---
|
||||
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 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
|
||||
|
||||
```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 current `scripts/clawdock/clawdock-helpers.sh` path; the old raw GitHub path was removed.
|
||||
|
||||
The helpers auto-detect your OpenClaw checkout on first use (checking common paths like `~/openclaw`, `~/projects/openclaw`) and cache the result in `~/.clawdock/config`. Set `CLAWDOCK_DIR` yourself if your checkout lives elsewhere.
|
||||
|
||||
## 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` | Write the gateway token into the container config |
|
||||
| `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 |
|
||||
| `clawdock-help` | List all ClawDock commands |
|
||||
|
||||
## 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 reads two separate `.env` files, matching the split described in [Docker](/install/docker):
|
||||
|
||||
- The project `.env` next to `docker-compose.yml`: Docker-specific values like image name, ports, and `OPENCLAW_GATEWAY_TOKEN`. `clawdock-token` reads the token from here.
|
||||
- `~/.openclaw/.env` (mounted into the container): env-backed secrets OpenClaw itself manages, alongside `openclaw.json` and `agents/<agentId>/agent/auth-profiles.json`.
|
||||
|
||||
`clawdock-fix-token` copies the token from the project `.env` into the container's `gateway.remote.token` and `gateway.auth.token` config values and restarts the gateway.
|
||||
|
||||
Use `clawdock-show-config` to inspect `openclaw.json` and both `.env` files quickly; it redacts `.env` values in its printed output.
|
||||
|
||||
## Related
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Docker" href="/install/docker" icon="docker">
|
||||
Canonical Docker install for OpenClaw.
|
||||
</Card>
|
||||
<Card title="Docker VM runtime" href="/install/docker-vm-runtime" icon="cube">
|
||||
Docker-managed VM runtime for hardened isolation.
|
||||
</Card>
|
||||
<Card title="Updating" href="/install/updating" icon="arrow-up-right-from-square">
|
||||
Updating the OpenClaw package and managed services.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
160
docs/install/development-channels.md
Normal file
160
docs/install/development-channels.md
Normal file
@@ -0,0 +1,160 @@
|
||||
---
|
||||
summary: "Stable, extended-stable, beta, and dev channels: semantics, switching, pinning, and tagging"
|
||||
read_when:
|
||||
- You want to switch between stable/extended-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"
|
||||
---
|
||||
|
||||
OpenClaw ships four update channels:
|
||||
|
||||
- **stable**: npm dist-tag `latest`. Recommended for most users.
|
||||
- **extended-stable**: npm dist-tag `extended-stable`. A net-new, trailing
|
||||
supported-month package channel. It is package-only and foreground-only in
|
||||
this release.
|
||||
- **beta**: npm dist-tag `beta`. Falls back to `latest` when `beta` is missing
|
||||
or older than the current stable release.
|
||||
- **dev**: moving head of `main` (git). npm dist-tag `dev` when published. `main`
|
||||
is for experimentation and active development; it may contain incomplete
|
||||
features or breaking changes. Do not run it for production gateways.
|
||||
|
||||
Stable builds usually ship to **beta** first, get vetted there, then get
|
||||
promoted to **latest** without a version bump. Maintainers can also publish
|
||||
directly to `latest`. Dist-tags are the source of truth for npm installs.
|
||||
|
||||
## Switching channels
|
||||
|
||||
```bash
|
||||
openclaw update --channel stable
|
||||
openclaw update --channel extended-stable
|
||||
openclaw update --channel beta
|
||||
openclaw update --channel dev
|
||||
```
|
||||
|
||||
`--channel` persists the choice to `update.channel` in config and drives both
|
||||
install paths:
|
||||
|
||||
| Channel | npm/package installs | git installs |
|
||||
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `stable` | dist-tag `latest` | latest stable git tag (excludes `-alpha.N`, `-beta.N`, `-rc.N`, `-dev.N`, `-next.N`, `-preview.N`, `-canary.N`, `-nightly.N`, and other named prerelease suffixes) |
|
||||
| `extended-stable` | resolves the public npm `extended-stable` selector, verifies the exact selected package, and installs that exact version. Fails closed with no fallback to `latest`, `beta`, or `dev`. | unsupported: OpenClaw leaves the checkout unchanged and asks you to use a package installation |
|
||||
| `beta` | dist-tag `beta`, falling back to `latest` when `beta` is missing or older | latest beta git tag, falling back to the latest stable git tag when beta is missing or older |
|
||||
| `dev` | dist-tag `dev` (rare; most dev users run git installs) | fetches, rebases the checkout on the upstream `main` branch, builds, and reinstalls the global CLI |
|
||||
|
||||
For `dev` git installs, the default checkout is `~/openclaw` (or
|
||||
`$OPENCLAW_HOME/openclaw` when `OPENCLAW_HOME` is set); override with
|
||||
`OPENCLAW_GIT_DIR`.
|
||||
|
||||
<Tip>
|
||||
To keep stable and dev in parallel, use two separate checkouts and point each gateway at its own.
|
||||
</Tip>
|
||||
|
||||
## One-off version or tag targeting
|
||||
|
||||
Use `--tag` to target a specific dist-tag, version, or package spec for a
|
||||
single update **without** changing the 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
|
||||
|
||||
# Switch to the moving GitHub main checkout (persistent)
|
||||
openclaw update --channel dev
|
||||
|
||||
# Install a specific npm package spec
|
||||
openclaw update --tag openclaw@2026.4.1-beta.1
|
||||
|
||||
# Install from GitHub main once without persisting the channel
|
||||
openclaw update --tag main
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- `--tag` applies to **package (npm) installs only**; git installs ignore it.
|
||||
- The tag is not persisted; the next `openclaw update` uses the configured
|
||||
channel.
|
||||
- `--tag main` maps to the npm-compatible spec `github:openclaw/openclaw#main`
|
||||
for that one run. For a persistent moving `main` install, use
|
||||
`openclaw update --channel dev` (package installs switch to a git checkout)
|
||||
or reinstall with the installer's git method:
|
||||
`curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method git --version main`.
|
||||
The npm install path rejects GitHub/git source targets outright and points
|
||||
you at the git method instead.
|
||||
- Downgrade protection: if the target version is older than the current
|
||||
version, OpenClaw prompts for confirmation (skip with `--yes`).
|
||||
- Extended-stable always uses its verified exact package target. It is not a
|
||||
one-off alias for `--tag extended-stable`, and `--tag` cannot be combined
|
||||
with an effective extended-stable channel.
|
||||
- `--channel beta` differs from `--tag beta`: the channel flow can fall back
|
||||
to stable/latest when beta is missing or older, while `--tag beta` always
|
||||
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 reports the effective channel, target version, planned actions,
|
||||
and whether a downgrade confirmation would be required.
|
||||
|
||||
## Plugins and channels
|
||||
|
||||
Switching channels with `openclaw update` also syncs plugin sources:
|
||||
|
||||
- `dev` switches installed plugins that have a bundled counterpart back to
|
||||
their bundled (git checkout) source.
|
||||
- `stable` and `beta` restore npm-installed or ClawHub-installed plugin
|
||||
packages.
|
||||
- `extended-stable` currently uses the existing stable/latest plugin line
|
||||
after the core package succeeds. Official plugin `@extended-stable`
|
||||
selectors are not queried yet.
|
||||
- npm-installed plugins are updated after the core update completes.
|
||||
|
||||
## Checking current status
|
||||
|
||||
```bash
|
||||
openclaw update status
|
||||
```
|
||||
|
||||
Shows the active channel (with the source that decided it: config, git tag,
|
||||
git branch, installed version, or default), install kind (git or package),
|
||||
current version, and update availability.
|
||||
|
||||
## Tagging best practices
|
||||
|
||||
- Tag releases you want git checkouts to land on: `vYYYY.M.PATCH` for stable,
|
||||
`vYYYY.M.PATCH-beta.N` for beta. Named prerelease suffixes such as
|
||||
`-alpha.N`, `-rc.N`, and `-next.N` are not stable or beta targets.
|
||||
- Legacy numeric stable tags such as `vYYYY.M.PATCH-1` and `v1.0.1-1` are still
|
||||
recognized as stable git tags for compatibility.
|
||||
- `vYYYY.M.PATCH.beta.N` (dot-separated) is also recognized for compatibility;
|
||||
prefer `-beta.N`.
|
||||
- Keep tags immutable: never move or reuse a tag.
|
||||
- npm dist-tags remain the source of truth for npm installs:
|
||||
- `latest` -> stable
|
||||
- `extended-stable` -> trailing supported-month package release
|
||||
- `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 fine:
|
||||
|
||||
- The git tag and npm dist-tag can still publish on their own.
|
||||
- Call out "no macOS build for this beta" in release notes or changelog.
|
||||
|
||||
## Related
|
||||
|
||||
- [Updating](/install/updating)
|
||||
- [Installer internals](/install/installer)
|
||||
174
docs/install/digitalocean.md
Normal file
174
docs/install/digitalocean.md
Normal file
@@ -0,0 +1,174 @@
|
||||
---
|
||||
summary: "Host OpenClaw on a DigitalOcean Droplet"
|
||||
read_when:
|
||||
- Setting up OpenClaw on DigitalOcean
|
||||
- Looking for a simple paid VPS for OpenClaw
|
||||
title: "DigitalOcean"
|
||||
---
|
||||
|
||||
Run a persistent OpenClaw Gateway on a DigitalOcean Droplet (~$6/month for the 1 GB Basic plan).
|
||||
|
||||
DigitalOcean is a straightforward paid VPS path. For cheaper or free options:
|
||||
|
||||
- [Hetzner](/install/hetzner) -- more cores/RAM per dollar.
|
||||
- [Oracle Cloud](/install/oracle) -- Always Free ARM tier (up to 4 OCPU, 24 GB RAM), but signup can be finicky and it is ARM-only.
|
||||
|
||||
## 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
|
||||
|
||||
# Create the non-root user that will own OpenClaw state and services.
|
||||
adduser openclaw
|
||||
usermod -aG sudo openclaw
|
||||
loginctl enable-linger openclaw
|
||||
|
||||
su - openclaw
|
||||
openclaw --version
|
||||
```
|
||||
|
||||
Use the root shell only for system bootstrap. Run OpenClaw commands as the non-root `openclaw` user so state lives under `/home/openclaw/.openclaw/` and the Gateway installs as that user's systemd `--user` service.
|
||||
|
||||
</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 user service).
|
||||
|
||||
</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 | sudo sh
|
||||
sudo tailscale up
|
||||
openclaw config set gateway.tailscale.mode serve
|
||||
openclaw gateway restart
|
||||
```
|
||||
|
||||
Then open `https://<magicdns>/` from any device on your tailnet.
|
||||
|
||||
Tailscale Serve authenticates Control UI and WebSocket traffic via tailnet identity headers, which assumes the gateway host itself is trusted. HTTP API endpoints still follow the gateway's normal auth mode (token/password) regardless. To require explicit shared-secret credentials over Serve, set `gateway.auth.allowTailscale: false` and use `gateway.auth.mode: "token"` or `"password"`.
|
||||
|
||||
**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>
|
||||
|
||||
## Persistence and backups
|
||||
|
||||
OpenClaw state lives under:
|
||||
|
||||
- `~/.openclaw/` -- `openclaw.json`, channel/provider credentials, per-agent `auth-profiles.json`, and session data.
|
||||
- `~/.openclaw/workspace/` -- the agent workspace (SOUL.md, memory, artifacts).
|
||||
|
||||
These survive Droplet reboots. To take a portable snapshot:
|
||||
|
||||
```bash
|
||||
openclaw backup create
|
||||
```
|
||||
|
||||
DigitalOcean snapshots back up the whole Droplet; `openclaw backup create` is portable across hosts.
|
||||
|
||||
## 1 GB RAM tips
|
||||
|
||||
The $6 Droplet only has 1 GB RAM. To keep things smooth:
|
||||
|
||||
- Make sure the swap step above is in `/etc/fstab` so it survives reboots.
|
||||
- Prefer API-based models (Claude, GPT) over local ones -- local LLM inference does not fit in 1 GB.
|
||||
- Set `agents.defaults.model.primary` to a smaller model if you hit OOMs on large prompts.
|
||||
- Monitor with `free -h` and `htop`.
|
||||
|
||||
## 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, switch to 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
|
||||
|
||||
## Related
|
||||
|
||||
- [Install overview](/install)
|
||||
- [Fly.io](/install/fly)
|
||||
- [Hetzner](/install/hetzner)
|
||||
- [VPS hosting](/vps)
|
||||
148
docs/install/docker-vm-runtime.md
Normal file
148
docs/install/docker-vm-runtime.md
Normal file
@@ -0,0 +1,148 @@
|
||||
---
|
||||
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"
|
||||
---
|
||||
|
||||
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 is lost on restart. Bake every external binary a skill needs into
|
||||
the image at build time.
|
||||
|
||||
The examples below cover three binaries only, alphabetically:
|
||||
|
||||
- `gog` (from `gogcli`) for Gmail access
|
||||
- `goplaces` for Google Places
|
||||
- `wacli` for WhatsApp
|
||||
|
||||
These are examples, not a complete list. Install as many binaries as your
|
||||
skills need using the same pattern. When you add a skill that needs a new
|
||||
binary later:
|
||||
|
||||
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 (gogcli — installs as `gog`)
|
||||
# Copy the current Linux asset URL from https://github.com/steipete/gogcli/releases
|
||||
RUN curl -L https://github.com/steipete/gogcli/releases/latest/download/gogcli_linux_amd64.tar.gz \
|
||||
| tar -xzO gog > /usr/local/bin/gog; \
|
||||
chmod +x /usr/local/bin/gog
|
||||
|
||||
# Example binary 2: Google Places CLI
|
||||
# Copy the current Linux asset URL from https://github.com/steipete/goplaces/releases
|
||||
RUN curl -L https://github.com/steipete/goplaces/releases/latest/download/goplaces_linux_amd64.tar.gz \
|
||||
| tar -xzO goplaces > /usr/local/bin/goplaces; \
|
||||
chmod +x /usr/local/bin/goplaces
|
||||
|
||||
# Example binary 3: WhatsApp CLI
|
||||
# Copy the current Linux asset URL from https://github.com/steipete/wacli/releases
|
||||
RUN curl -L https://github.com/steipete/wacli/releases/latest/download/wacli-linux-amd64.tar.gz \
|
||||
| tar -xzO wacli > /usr/local/bin/wacli; \
|
||||
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 URLs above are examples. For ARM-based VMs, choose the `arm64` assets. For reproducible builds, pin versioned release URLs.
|
||||
</Note>
|
||||
|
||||
## Build and launch
|
||||
|
||||
```bash
|
||||
docker compose build
|
||||
docker compose up -d openclaw-gateway
|
||||
```
|
||||
|
||||
If the 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:
|
||||
|
||||
```text
|
||||
/usr/local/bin/gog
|
||||
/usr/local/bin/goplaces
|
||||
/usr/local/bin/wacli
|
||||
```
|
||||
|
||||
Verify the gateway is up:
|
||||
|
||||
```bash
|
||||
docker compose logs -f openclaw-gateway
|
||||
curl -fsS http://127.0.0.1:18789/healthz
|
||||
```
|
||||
|
||||
`/healthz` returning a 200 response confirms the gateway process is listening and healthy; the built-in image `HEALTHCHECK` polls the same endpoint.
|
||||
|
||||
## 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` |
|
||||
| Channel/provider creds | `/home/node/.openclaw/credentials/` | Host volume mount | Channel and provider credential material |
|
||||
| Model auth profiles | `/home/node/.openclaw/agents/` | Host volume mount | `agents/<agentId>/agent/auth-profiles.json` (OAuth, API keys) |
|
||||
| Legacy OAuth key file | `/home/node/.config/openclaw/` | Host volume mount | Read-only compat for pre-migration OAuth sidecars; `openclaw doctor --fix` migrates these into `auth-profiles.json` |
|
||||
| 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` |
|
||||
| Plugin packages | `/home/node/.openclaw/npm`, `/home/node/.openclaw/git` | Host volume mount | Downloadable plugin package roots |
|
||||
| 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
|
||||
```
|
||||
|
||||
## Related
|
||||
|
||||
- [Docker](/install/docker)
|
||||
- [Podman](/install/podman)
|
||||
- [ClawDock](/install/clawdock)
|
||||
524
docs/install/docker.md
Normal file
524
docs/install/docker.md
Normal file
@@ -0,0 +1,524 @@
|
||||
---
|
||||
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 is **optional**. Use it for an isolated, throwaway gateway environment or a host without local installs. If you already develop on your own machine, use the normal install flow instead.
|
||||
|
||||
The default sandbox backend uses Docker when `agents.defaults.sandbox` is enabled, but sandboxing is off by default and does not require the gateway itself to run in Docker. SSH and OpenShell sandbox backends are also available; 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
|
||||
- On a VPS/public host, review [Security hardening for network exposure](/gateway/security), especially the Docker `DOCKER-USER` firewall chain
|
||||
|
||||
## Containerized gateway
|
||||
|
||||
<Steps>
|
||||
<Step title="Build the image">
|
||||
From the repo root:
|
||||
|
||||
```bash
|
||||
./scripts/docker/setup.sh
|
||||
```
|
||||
|
||||
This builds the gateway image locally as `openclaw:local`. 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 first to the [GitHub Container Registry](https://github.com/openclaw/openclaw/pkgs/container/openclaw). GHCR is the primary registry for release automation, pinned deployments, and provenance checks. The same release publishes a Docker Hub mirror at `openclaw/openclaw`:
|
||||
|
||||
```bash
|
||||
export OPENCLAW_IMAGE="openclaw/openclaw:latest"
|
||||
./scripts/docker/setup.sh
|
||||
```
|
||||
|
||||
Use `ghcr.io/openclaw/openclaw` or `openclaw/openclaw` and avoid unofficial mirrors, which don't share OpenClaw's release timing or retention policy. Official tags: `main`, `latest`, `<version>` (e.g. `2026.2.26`), and beta tags such as `2026.2.26-beta.1` (betas never move `latest`/`main`). The default `main`/`latest`/`<version>` image bundles the `codex` and `diagnostics-otel` plugins. A `-browser` variant (e.g. `latest-browser`) also ships with Chromium baked in, useful for the [sandboxed browser](/gateway/sandboxing#sandboxed-browser) tool without a first-run Playwright install.
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Airgapped rerun">
|
||||
On offline hosts, transfer and load the image first:
|
||||
|
||||
```bash
|
||||
docker load -i openclaw-image.tar
|
||||
export OPENCLAW_IMAGE="ghcr.io/openclaw/openclaw:latest"
|
||||
./scripts/docker/setup.sh --offline
|
||||
```
|
||||
|
||||
`--offline` verifies `OPENCLAW_IMAGE` already exists locally, disables implicit Compose pulls/builds, then runs the normal flow: `.env` sync, permission fixes, onboarding, gateway config sync, Compose startup.
|
||||
|
||||
If `OPENCLAW_SANDBOX=1`, offline setup also checks the configured default and per-agent sandbox images on the daemon behind `OPENCLAW_DOCKER_SOCKET`, including the browser-contract label on Docker-backed browser images. If a required image is missing or stale, setup exits without changing sandbox config rather than reporting a broken success.
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Complete onboarding">
|
||||
The setup script runs onboarding automatically:
|
||||
|
||||
- prompts for provider API keys
|
||||
- generates a gateway token and writes it to `.env`
|
||||
- creates the auth-profile secret key directory
|
||||
- starts the gateway via Docker Compose
|
||||
|
||||
Pre-start onboarding and config writes run through `openclaw-gateway` directly (with `--no-deps --entrypoint node`), since `openclaw-cli` shares the gateway's network namespace and only works once the gateway container exists.
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Open the Control UI">
|
||||
Open `http://127.0.0.1:18789/` and paste the token written to `.env` into Settings. If you switched the container 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)">
|
||||
```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
|
||||
|
||||
```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 after any `docker-compose.override.yml` you maintain yourself, e.g. `-f docker-compose.yml -f docker-compose.override.yml -f docker-compose.extra.yml`.
|
||||
</Note>
|
||||
|
||||
### Environment variables
|
||||
|
||||
Optional variables accepted by `scripts/docker/setup.sh` (and, for the gateway container, by `docker-compose.yml` directly):
|
||||
|
||||
| Variable | Purpose |
|
||||
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
|
||||
| `OPENCLAW_IMAGE` | Use a remote image instead of building locally |
|
||||
| `OPENCLAW_IMAGE_APT_PACKAGES` | Install extra apt packages during build (space-separated). Legacy alias: `OPENCLAW_DOCKER_APT_PACKAGES` |
|
||||
| `OPENCLAW_IMAGE_PIP_PACKAGES` | Install extra Python packages during build (space-separated) |
|
||||
| `OPENCLAW_EXTENSIONS` | Pre-install plugin dependencies at build time (comma- or space-separated ids) |
|
||||
| `OPENCLAW_DOCKER_BUILD_NODE_OPTIONS` | Override the local source-build Node options (default `--max-old-space-size=8192`) |
|
||||
| `OPENCLAW_DOCKER_BUILD_TSDOWN_MAX_OLD_SPACE_MB` | Override the local source-build tsdown heap in MB |
|
||||
| `OPENCLAW_DOCKER_BUILD_SKIP_DTS` | Skip declaration output during runtime-only local image builds (default `1`) |
|
||||
| `OPENCLAW_INSTALL_BROWSER` | Bake Chromium + Xvfb into the image at build time |
|
||||
| `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_SKIP_ONBOARDING` | Skip the interactive onboarding step (`1`, `true`, `yes`, `on`) |
|
||||
| `OPENCLAW_DOCKER_SOCKET` | Override the Docker socket path |
|
||||
| `OPENCLAW_DISABLE_BONJOUR` | Force Bonjour/mDNS advertising on (`0`) or off (`1`); see [Bonjour / mDNS](#bonjour--mdns) |
|
||||
| `OPENCLAW_DISABLE_BUNDLED_SOURCE_OVERLAYS` | Disable bundled plugin source bind-mount overlays |
|
||||
| `OTEL_EXPORTER_OTLP_ENDPOINT` | Shared OTLP/HTTP collector endpoint for OpenTelemetry export |
|
||||
| `OTEL_EXPORTER_OTLP_*_ENDPOINT` | Signal-specific OTLP endpoints for traces, metrics, or logs |
|
||||
| `OTEL_EXPORTER_OTLP_PROTOCOL` | OTLP protocol override. Only `http/protobuf` is supported today |
|
||||
| `OTEL_SERVICE_NAME` | Service name used for OpenTelemetry resources |
|
||||
| `OTEL_SEMCONV_STABILITY_OPT_IN` | Opt in to latest experimental GenAI semantic attributes |
|
||||
| `OPENCLAW_OTEL_PRELOADED` | Skip starting a second OpenTelemetry SDK when one is preloaded |
|
||||
|
||||
The official image ships no Homebrew. During onboarding, OpenClaw hides brew-only skill dependency installers in a Linux container without `brew`; provide those dependencies through a custom image or install manually. Use `OPENCLAW_IMAGE_APT_PACKAGES` for Debian-packaged dependencies and `OPENCLAW_IMAGE_PIP_PACKAGES` for Python dependencies (runs `python3 -m pip install --break-system-packages` at build time, so pin versions and use only indexes you trust).
|
||||
|
||||
If Docker reports `ResourceExhausted`, `cannot allocate memory`, or aborts during `tsdown`, increase the Docker builder memory limit or retry with smaller explicit heaps:
|
||||
|
||||
```bash
|
||||
OPENCLAW_DOCKER_BUILD_NODE_OPTIONS=--max-old-space-size=4096 OPENCLAW_DOCKER_BUILD_TSDOWN_MAX_OLD_SPACE_MB=4096
|
||||
```
|
||||
|
||||
To test bundled plugin source against a packaged image, mount one plugin source directory over its packaged source path, e.g. `OPENCLAW_EXTRA_MOUNTS=/path/to/fork/extensions/synology-chat:/app/extensions/synology-chat:ro`. That overrides the matching compiled `/app/dist/extensions/synology-chat` bundle for the same plugin id.
|
||||
|
||||
### Observability
|
||||
|
||||
OpenTelemetry export is outbound from the Gateway container to your OTLP collector; it needs no published Docker port. To include the bundled exporter in a locally built image:
|
||||
|
||||
```bash
|
||||
export OPENCLAW_EXTENSIONS="diagnostics-otel"
|
||||
export OTEL_EXPORTER_OTLP_ENDPOINT="http://otel-collector:4318"
|
||||
export OTEL_SERVICE_NAME="openclaw-gateway"
|
||||
./scripts/docker/setup.sh
|
||||
```
|
||||
|
||||
Official prebuilt images already bundle `diagnostics-otel`; install `clawhub:@openclaw/diagnostics-otel` yourself only if you removed it. To enable export, allow and enable the `diagnostics-otel` plugin in config, then set `diagnostics.otel.enabled=true` (see the full example in [OpenTelemetry export](/gateway/opentelemetry)). Collector auth headers go through `diagnostics.otel.headers`, not Docker environment variables.
|
||||
|
||||
Prometheus metrics reuse the already-published Gateway port. Install `clawhub:@openclaw/diagnostics-prometheus`, enable the `diagnostics-prometheus` plugin, then scrape:
|
||||
|
||||
```text
|
||||
http://<gateway-host>:18789/api/diagnostics/prometheus
|
||||
```
|
||||
|
||||
The route is protected by Gateway authentication; don't expose a separate public `/metrics` port or unauthenticated reverse-proxy path. See [Prometheus metrics](/gateway/prometheus).
|
||||
|
||||
### 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 image's built-in `HEALTHCHECK` pings `/healthz`; repeated failures mark the container `unhealthy` so orchestrators 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 `http://127.0.0.1:18789` on the host 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>
|
||||
|
||||
### Host local providers
|
||||
|
||||
Inside the container, `127.0.0.1` is the container itself, not the host. Use `host.docker.internal` for providers running on the host:
|
||||
|
||||
| Provider | Host default URL | Docker setup URL |
|
||||
| --------- | ------------------------ | ----------------------------------- |
|
||||
| LM Studio | `http://127.0.0.1:1234` | `http://host.docker.internal:1234` |
|
||||
| Ollama | `http://127.0.0.1:11434` | `http://host.docker.internal:11434` |
|
||||
|
||||
The bundled setup uses those URLs as LM Studio/Ollama onboarding defaults, and `docker-compose.yml` maps `host.docker.internal` to the host gateway on Linux Docker Engine (Docker Desktop provides the same alias on macOS/Windows). Host services must listen on an address Docker can reach:
|
||||
|
||||
```bash
|
||||
lms server start --port 1234 --bind 0.0.0.0
|
||||
OLLAMA_HOST=0.0.0.0:11434 ollama serve
|
||||
```
|
||||
|
||||
Using your own Compose file or `docker run`? Add the same mapping yourself, e.g. `--add-host=host.docker.internal:host-gateway`.
|
||||
|
||||
### Claude CLI backend in Docker
|
||||
|
||||
The official image does not pre-install Claude Code. Install and log in inside the container's `node` user, then persist that container home so image upgrades don't erase the binary or auth state.
|
||||
|
||||
For a new install, enable a persistent `/home/node` volume before running setup:
|
||||
|
||||
```bash
|
||||
export OPENCLAW_IMAGE="ghcr.io/openclaw/openclaw:latest"
|
||||
export OPENCLAW_HOME_VOLUME="openclaw_home"
|
||||
./scripts/docker/setup.sh
|
||||
```
|
||||
|
||||
For an existing install, stop the stack and reload the current `.env` values first — the setup script always rewrites `.env` from the current shell and defaults, it doesn't read the file on its own:
|
||||
|
||||
```bash
|
||||
set -a
|
||||
. ./.env
|
||||
set +a
|
||||
export OPENCLAW_HOME_VOLUME="${OPENCLAW_HOME_VOLUME:-openclaw_home}"
|
||||
./scripts/docker/setup.sh
|
||||
```
|
||||
|
||||
If `.env` contains values your shell can't source, re-export what you rely on manually first (`OPENCLAW_IMAGE`, ports, bind mode, custom paths, `OPENCLAW_EXTRA_MOUNTS`, sandbox, skip-onboarding). The generated overlay mounts the home volume for both `openclaw-gateway` and `openclaw-cli`; run the remaining commands with that overlay (and `docker-compose.override.yml` first, if you use one):
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.yml -f docker-compose.extra.yml run --rm \
|
||||
--entrypoint sh openclaw-cli -lc \
|
||||
'curl -fsSL https://claude.ai/install.sh | bash'
|
||||
```
|
||||
|
||||
The native installer writes `claude` to `/home/node/.local/bin/claude`. Point OpenClaw at that path:
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.yml -f docker-compose.extra.yml run --rm \
|
||||
openclaw-cli config set \
|
||||
agents.defaults.cliBackends.claude-cli.command \
|
||||
/home/node/.local/bin/claude
|
||||
```
|
||||
|
||||
Log in and verify from the same persisted home:
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.yml -f docker-compose.extra.yml run --rm \
|
||||
--entrypoint /home/node/.local/bin/claude openclaw-cli auth login
|
||||
docker compose -f docker-compose.yml -f docker-compose.extra.yml run --rm \
|
||||
--entrypoint /home/node/.local/bin/claude openclaw-cli auth status --text
|
||||
docker compose -f docker-compose.yml -f docker-compose.extra.yml run --rm \
|
||||
openclaw-cli models auth login \
|
||||
--provider anthropic --method cli --set-default
|
||||
docker compose -f docker-compose.yml -f docker-compose.extra.yml run --rm \
|
||||
openclaw-cli models list --provider anthropic
|
||||
```
|
||||
|
||||
Then use the bundled `claude-cli` backend:
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.yml -f docker-compose.extra.yml run --rm \
|
||||
openclaw-cli agent \
|
||||
--agent main \
|
||||
--model claude-cli/claude-sonnet-4-6 \
|
||||
--message "Say hello from Docker Claude CLI"
|
||||
```
|
||||
|
||||
`OPENCLAW_HOME_VOLUME` persists the native install under `/home/node/.local/bin` and `/home/node/.local/share/claude`, plus Claude Code settings/auth under `/home/node/.claude` and `/home/node/.claude.json`. Persisting only `/home/node/.openclaw` is not enough; if you use `OPENCLAW_EXTRA_MOUNTS` instead of a home volume, mount all of those Claude paths into both services.
|
||||
|
||||
<Note>
|
||||
For shared production automation or predictable Anthropic billing, prefer the Anthropic API-key path. Claude CLI reuse follows Claude Code's installed version, account login, billing, and update behavior.
|
||||
</Note>
|
||||
|
||||
### Bonjour / mDNS
|
||||
|
||||
Docker bridge networking usually doesn't forward Bonjour/mDNS multicast (`224.0.0.251:5353`) reliably. When `OPENCLAW_DISABLE_BONJOUR` is unset, the bundled Bonjour plugin auto-disables LAN advertising once it detects it's running in a container, so it won't crash-loop retrying multicast the bridge drops. Set `OPENCLAW_DISABLE_BONJOUR=1` to force it off regardless of detection, or `0` to force it on (only on host networking, macvlan, or another network where mDNS multicast is known to work).
|
||||
|
||||
Use the published Gateway URL, Tailscale, or wide-area DNS-SD for Docker hosts otherwise. See [Bonjour discovery](/gateway/bonjour) for gotchas and troubleshooting.
|
||||
|
||||
### Storage and persistence
|
||||
|
||||
Docker Compose bind-mounts `OPENCLAW_CONFIG_DIR` to `/home/node/.openclaw`, `OPENCLAW_WORKSPACE_DIR` to `/home/node/.openclaw/workspace`, and `OPENCLAW_AUTH_PROFILE_SECRET_DIR` to `/home/node/.config/openclaw`, so those paths survive container replacement. When a variable is unset, `docker-compose.yml` falls back under `${HOME}`, or `/tmp` if `HOME` itself is missing, so `docker compose up` never emits an empty-source volume spec on bare environments.
|
||||
|
||||
That mounted config directory holds:
|
||||
|
||||
- `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`
|
||||
|
||||
The auth-profile secret directory stores the local encryption key for OAuth-backed auth profile token material. Keep it with your Docker host state, but separate from `OPENCLAW_CONFIG_DIR`.
|
||||
|
||||
Installed downloadable plugins store package state under the mounted OpenClaw home, so install records and package roots survive container replacement; gateway startup does not regenerate bundled-plugin dependency trees.
|
||||
|
||||
For full VM persistence details, see [Docker VM Runtime - What persists where](/install/docker-vm-runtime#what-persists-where).
|
||||
|
||||
**Disk growth hotspots:** `media/`, session JSONL files, the shared SQLite state database, installed plugin package roots, and rolling file logs under `/tmp/openclaw/`.
|
||||
|
||||
### Shell helpers (optional)
|
||||
|
||||
For shorter day-to-day commands, install [ClawDock](/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 from the older `scripts/shell-helpers/clawdock-helpers.sh` path, rerun the command above so your local helper tracks the current location. Then use `clawdock-start`, `clawdock-stop`, `clawdock-dashboard`, etc. (run `clawdock-help` for the full list).
|
||||
|
||||
<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 can't complete, it resets `agents.defaults.sandbox.mode` to `off`. Codex code mode is disabled for turns where the OpenClaw sandbox is active (see [Sandboxing § Docker backend](/gateway/sandboxing#docker-backend)); never mount the host Docker socket into agent sandbox containers.
|
||||
|
||||
</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 both `openclaw-gateway` and `openclaw-cli`.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Docker Desktop DNS failures in openclaw-cli">
|
||||
Some Docker Desktop setups fail DNS lookups from the shared-network `openclaw-cli` sidecar after `NET_RAW` is dropped, showing up as `EAI_AGAIN` during npm-backed commands like `openclaw plugins install`. Keep the default hardened compose file for normal operation. The override below restores default capabilities for the `openclaw-cli` container only — use it for the one-off command that needs registry access, not as your default invocation:
|
||||
|
||||
```bash
|
||||
printf '%s\n' \
|
||||
'services:' \
|
||||
' openclaw-cli:' \
|
||||
' cap_drop: !reset []' \
|
||||
> docker-compose.cli-no-dropped-caps.local.yml
|
||||
|
||||
docker compose -f docker-compose.yml -f docker-compose.cli-no-dropped-caps.local.yml run --rm openclaw-cli plugins install <package>
|
||||
```
|
||||
|
||||
If you already created a long-running `openclaw-cli` container, recreate it with the same override — `docker compose exec`/`docker exec` can't change Linux capabilities on an already-created container.
|
||||
|
||||
</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
|
||||
```
|
||||
|
||||
The same mismatch can show up as `blocked plugin candidate: suspicious ownership (... uid=1000, expected uid=0 or root)` followed by `plugin present but blocked` — the process uid and the mounted plugin directory owner disagree. Prefer running as the default uid 1000 and fixing the bind mount ownership. Only chown `/path/to/openclaw-config/npm` to `root:root` if you intentionally run OpenClaw as root long term.
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Faster rebuilds">
|
||||
Order your Dockerfile so dependency layers are cached, avoiding a `pnpm install` rerun 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_IMAGE_APT_PACKAGES="git curl jq"`
|
||||
3. **Bake Python deps**: `export OPENCLAW_IMAGE_PIP_PACKAGES="requests==2.32.5 humanize==4.14.0"`
|
||||
4. **Bake Playwright Chromium**: `export OPENCLAW_INSTALL_BROWSER=1`, or use the official `-browser` image tag
|
||||
5. **Or install Playwright browsers into a persisted volume**:
|
||||
```bash
|
||||
docker compose run --rm openclaw-cli \
|
||||
node /app/node_modules/playwright-core/cli.js install chromium
|
||||
```
|
||||
6. **Persist browser downloads**: use `OPENCLAW_HOME_VOLUME` or `OPENCLAW_EXTRA_MOUNTS`. OpenClaw auto-detects the image's Playwright-managed Chromium on Linux.
|
||||
|
||||
</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 runtime image uses `node:24-bookworm-slim` and runs `tini` as PID 1 so zombie processes are reaped and signals handled correctly in long-running containers. It publishes OCI base-image annotations including `org.opencontainers.image.base.name` and `org.opencontainers.image.source`. Dependabot refreshes the pinned Node base digest; release builds don't run a separate distro upgrade layer. 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 with the Docker backend, the gateway runs agent tool execution (shell, file read/write, etc.) inside isolated Docker containers while the gateway itself stays on the host — a hard wall around untrusted or multi-tenant agent sessions without containerizing the whole 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:
|
||||
|
||||
- [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 (from a source checkout):
|
||||
|
||||
```bash
|
||||
scripts/sandbox-setup.sh
|
||||
```
|
||||
|
||||
For npm installs without a source checkout, see [Sandboxing § Images and setup](/gateway/sandboxing#images-and-setup) for inline `docker build` commands.
|
||||
|
||||
## 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) (source checkout) or the inline `docker build` command from [Sandboxing § Images and setup](/gateway/sandboxing#images-and-setup) (npm install), 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
|
||||
198
docs/install/exe-dev.md
Normal file
198
docs/install/exe-dev.md
Normal file
@@ -0,0 +1,198 @@
|
||||
---
|
||||
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"
|
||||
---
|
||||
|
||||
**Goal:** OpenClaw Gateway running on an [exe.dev](https://exe.dev) VM, reachable at `https://<vm-name>.exe.xyz`.
|
||||
|
||||
This guide assumes exe.dev's default **exeuntu** image. Map packages accordingly on other distros.
|
||||
|
||||
## What you need
|
||||
|
||||
- exe.dev account
|
||||
- `ssh exe.dev` access to exe.dev VMs (optional, for manual setup)
|
||||
|
||||
## Beginner quick path
|
||||
|
||||
1. Open [https://exe.new/openclaw](https://exe.new/openclaw)
|
||||
2. Fill in your auth key/token as needed
|
||||
3. Click "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 (token auth by default; password auth also works if you switch `gateway.auth.mode`)
|
||||
5. Approve pending device pairing requests with `openclaw devices approve <requestId>`
|
||||
|
||||
## Automated install with Shelley
|
||||
|
||||
Shelley, exe.dev's agent, can install OpenClaw from a prompt:
|
||||
|
||||
```text
|
||||
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
|
||||
|
||||
<Steps>
|
||||
<Step title="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/`.
|
||||
</Tip>
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Install prerequisites (on the VM)">
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y git curl jq ca-certificates openssl
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Install OpenClaw">
|
||||
```bash
|
||||
curl -fsSL https://openclaw.ai/install.sh | bash
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Configure nginx to proxy to port 8000">
|
||||
Edit `/etc/nginx/sites-enabled/default`:
|
||||
|
||||
```nginx
|
||||
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.
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Access OpenClaw and approve devices">
|
||||
Open `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 by default, so retrieve `gateway.auth.token` with `openclaw config get gateway.auth.token`, or generate a new one with `openclaw doctor --n`. If you switched 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.
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Remote channel setup
|
||||
|
||||
For remote hosts, prefer one `config patch` call over many SSH calls to `config set`. Keep real tokens in the VM environment or `~/.openclaw/.env`, and put only SecretRefs in `openclaw.json`. See [Secrets management](/gateway/secrets) for the full SecretRef contract.
|
||||
|
||||
On the VM, make the service environment contain the secrets it needs:
|
||||
|
||||
```bash
|
||||
cat >> ~/.openclaw/.env <<'EOF'
|
||||
SLACK_BOT_TOKEN=xoxb-...
|
||||
SLACK_APP_TOKEN=xapp-...
|
||||
DISCORD_BOT_TOKEN=...
|
||||
OPENAI_API_KEY=sk-...
|
||||
EOF
|
||||
```
|
||||
|
||||
From your local machine, create a patch file and pipe it to the VM:
|
||||
|
||||
```json5
|
||||
// openclaw.remote.patch.json5
|
||||
{
|
||||
secrets: {
|
||||
providers: {
|
||||
default: { source: "env" },
|
||||
},
|
||||
},
|
||||
channels: {
|
||||
slack: {
|
||||
enabled: true,
|
||||
mode: "socket",
|
||||
botToken: { source: "env", provider: "default", id: "SLACK_BOT_TOKEN" },
|
||||
appToken: { source: "env", provider: "default", id: "SLACK_APP_TOKEN" },
|
||||
groupPolicy: "open",
|
||||
requireMention: false,
|
||||
},
|
||||
discord: {
|
||||
enabled: true,
|
||||
token: { source: "env", provider: "default", id: "DISCORD_BOT_TOKEN" },
|
||||
dmPolicy: "disabled",
|
||||
dm: { enabled: false },
|
||||
groupPolicy: "allowlist",
|
||||
},
|
||||
},
|
||||
agents: {
|
||||
defaults: {
|
||||
model: { primary: "openai/gpt-5.5" },
|
||||
models: {
|
||||
"openai/gpt-5.5": { params: { fastMode: true } },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
ssh <vm-name>.exe.xyz 'openclaw config patch --stdin --dry-run' < ./openclaw.remote.patch.json5
|
||||
ssh <vm-name>.exe.xyz 'openclaw config patch --stdin' < ./openclaw.remote.patch.json5
|
||||
ssh <vm-name>.exe.xyz 'openclaw gateway restart && openclaw health'
|
||||
```
|
||||
|
||||
Use `--replace-path` when a nested allowlist should become exactly the patch value, for example replacing a Discord channel allowlist:
|
||||
|
||||
```bash
|
||||
ssh <vm-name>.exe.xyz 'openclaw config patch --stdin --replace-path "channels.discord.guilds[\"123\"].channels"' < ./discord.patch.json5
|
||||
```
|
||||
|
||||
See [Discord](/channels/discord) and [Slack](/channels/slack) for full channel config reference.
|
||||
|
||||
## Remote access
|
||||
|
||||
exe.dev handles authentication for remote access. By default, HTTP traffic from port 8000 is forwarded to `https://<vm-name>.exe.xyz` with email auth.
|
||||
|
||||
## Updating
|
||||
|
||||
```bash
|
||||
openclaw update
|
||||
```
|
||||
|
||||
See [Updating](/install/updating) for channel switches and manual recovery.
|
||||
|
||||
## Related
|
||||
|
||||
- [Remote gateway](/gateway/remote)
|
||||
- [Install overview](/install)
|
||||
473
docs/install/fly.md
Normal file
473
docs/install/fly.md
Normal file
@@ -0,0 +1,473 @@
|
||||
---
|
||||
summary: "Step-by-step Fly.io deployment for OpenClaw with persistent storage and HTTPS"
|
||||
title: Fly.io
|
||||
read_when:
|
||||
- Deploying OpenClaw on Fly.io
|
||||
- Setting up Fly volumes, secrets, and first-run config
|
||||
---
|
||||
|
||||
**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 the Control UI
|
||||
|
||||
<Steps>
|
||||
<Step title="Create the Fly app">
|
||||
```bash
|
||||
git clone https://github.com/openclaw/openclaw.git
|
||||
cd openclaw
|
||||
|
||||
# pick your own name
|
||||
fly apps create my-openclaw
|
||||
|
||||
# 1GB is usually enough
|
||||
fly volumes create openclaw_data --size 1 --region iad
|
||||
```
|
||||
|
||||
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. The repo's tracked `fly.toml` is the public template shown below; `deploy/fly.private.toml` is the hardened, no-public-IP variant (see [Private deployment](#private-deployment-hardened)).
|
||||
|
||||
```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"
|
||||
```
|
||||
|
||||
The OpenClaw Docker image entrypoint is `tini`, running `node openclaw.mjs gateway` by default. Fly `[processes]` replaces the Docker `CMD` (here it runs `node dist/index.js gateway ...` directly, the same compiled entrypoint) without touching `ENTRYPOINT`, so the process still runs under `tini`.
|
||||
|
||||
**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 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 auth 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=example-anthropic-key-not-real
|
||||
|
||||
# optional: other providers
|
||||
fly secrets set OPENAI_API_KEY=example-openai-key-not-real
|
||||
fly secrets set GOOGLE_API_KEY=...
|
||||
|
||||
# channel tokens
|
||||
fly secrets set DISCORD_BOT_TOKEN=example-discord-bot-token
|
||||
```
|
||||
|
||||
Non-loopback binds (`--bind lan`) require a valid gateway auth path. This example uses `OPENCLAW_GATEWAY_TOKEN`, but `gateway.auth.password` or a correctly configured non-loopback trusted-proxy deployment also satisfy the requirement. See [Secrets management](/gateway/secrets) for the SecretRef contract.
|
||||
|
||||
Treat these tokens like passwords. Prefer env vars/`fly secrets` over the config file for API keys and tokens so secrets stay out of `openclaw.json`.
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Deploy">
|
||||
```bash
|
||||
fly deploy
|
||||
```
|
||||
|
||||
First deploy builds the Docker image. Verify after deployment:
|
||||
|
||||
```bash
|
||||
fly status
|
||||
fly logs
|
||||
```
|
||||
|
||||
Gateway startup logs `gateway ready` once the HTTP/WebSocket listener is up. Fly's own health check watches `internal_port = 3000` per `fly.toml`; the image's Docker `HEALTHCHECK` directive additionally polls `/healthz` on its default port 18789, which is unused here since this deployment overrides the gateway to `--port 3000`.
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Create config file">
|
||||
SSH into the machine to create a proper config:
|
||||
|
||||
```bash
|
||||
fly ssh console
|
||||
```
|
||||
|
||||
```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",
|
||||
"controlUi": {
|
||||
"allowedOrigins": [
|
||||
"https://my-openclaw.fly.dev",
|
||||
"http://localhost:3000",
|
||||
"http://127.0.0.1:3000"
|
||||
]
|
||||
}
|
||||
},
|
||||
"meta": {}
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
With `OPENCLAW_STATE_DIR=/data`, the config path is `/data/openclaw.json`.
|
||||
|
||||
Replace `https://my-openclaw.fly.dev` with your real Fly app origin. Gateway startup seeds local Control UI origins from the runtime `--bind` and `--port` values so first boot can proceed before config exists, but browser access through Fly still needs the exact HTTPS origin listed in `gateway.controlUi.allowedOrigins`.
|
||||
|
||||
The Discord token can come from either:
|
||||
|
||||
- Environment variable `DISCORD_BOT_TOKEN` (recommended for secrets); no need to add it to config, the gateway reads it automatically
|
||||
- Config file `channels.discord.token`
|
||||
|
||||
Restart to apply:
|
||||
|
||||
```bash
|
||||
exit
|
||||
fly machine restart <machine-id>
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Access the Gateway">
|
||||
### Control UI
|
||||
|
||||
```bash
|
||||
fly open
|
||||
```
|
||||
|
||||
Or visit `https://my-openclaw.fly.dev/`.
|
||||
|
||||
Authenticate with the configured shared secret: the gateway token from `OPENCLAW_GATEWAY_TOKEN`, or your password if you switched to password auth.
|
||||
|
||||
### 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 cannot reach the gateway on the configured port.
|
||||
|
||||
**Fix:** ensure `internal_port` matches the gateway port (`--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
|
||||
```
|
||||
|
||||
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 after a container restart.
|
||||
|
||||
The single-instance lock file lives at `<tmpdir>/openclaw-<uid>/gateway.<hash>.lock` (Linux: `/tmp/openclaw-<uid>/gateway.<hash>.lock`), not on the persistent `/data` volume, so a full container restart normally clears it along with the rest of the container filesystem. If the lock survives (for example a `fly machine restart` that preserves the container filesystem) and blocks startup, remove it manually:
|
||||
|
||||
```bash
|
||||
fly ssh console --command "rm -f /tmp/openclaw-*/gateway.*.lock"
|
||||
fly machine restart <machine-id>
|
||||
```
|
||||
|
||||
### 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" }` for a normal local gateway start.
|
||||
|
||||
Verify the config exists:
|
||||
|
||||
```bash
|
||||
fly ssh console --command "cat /data/openclaw.json"
|
||||
```
|
||||
|
||||
### Writing config via SSH
|
||||
|
||||
`fly ssh console -C` does not support shell redirection. To write a config file:
|
||||
|
||||
```bash
|
||||
# echo + tee (pipe from local to remote)
|
||||
echo '{"your":"config"}' | fly ssh console -C "tee /data/openclaw.json"
|
||||
|
||||
# or sftp
|
||||
fly sftp shell
|
||||
> put /local/path/config.json /data/openclaw.json
|
||||
```
|
||||
|
||||
`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 instead of the volume.
|
||||
|
||||
**Fix:** ensure `OPENCLAW_STATE_DIR=/data` is set in `fly.toml` and redeploy.
|
||||
|
||||
## Updating
|
||||
|
||||
```bash
|
||||
git pull
|
||||
fly deploy
|
||||
fly status
|
||||
fly logs
|
||||
```
|
||||
|
||||
`git pull` + `fly deploy` is the supervised path here: it rebuilds the image from the Dockerfile, so the CLI/gateway version, the base OS image, and any Dockerfile changes all update together. `openclaw update` inside the running container is not the same operation, since the image ships as a Docker-built `dist/` tree with no `.git` checkout and no npm-managed global install for it to detect; see [Updating](/install/updating) for that flow on VM-style installs.
|
||||
|
||||
### Updating the machine command
|
||||
|
||||
To change the startup command without a full redeploy:
|
||||
|
||||
```bash
|
||||
fly machines list
|
||||
fly machine update <machine-id> --command "node dist/index.js gateway --port 3000 --bind lan" -y
|
||||
|
||||
# or with a memory increase
|
||||
fly machine update <machine-id> --vm-memory 2048 --command "node dist/index.js gateway --port 3000 --bind lan" -y
|
||||
```
|
||||
|
||||
A later `fly deploy` resets the machine command back to whatever is in `fly.toml`; re-apply manual changes after redeploying.
|
||||
|
||||
## Private deployment (hardened)
|
||||
|
||||
By default, Fly allocates public IPs, so your gateway is reachable at `https://your-app.fly.dev` and discoverable by internet scanners (Shodan, Censys, etc.).
|
||||
|
||||
Use `deploy/fly.private.toml` for a hardened deployment with **no public IP**: it omits `[http_service]`, so no public ingress is allocated.
|
||||
|
||||
### When to use private deployment
|
||||
|
||||
- Only outbound calls/messages (no inbound webhooks)
|
||||
- ngrok or Tailscale tunnels handle any webhook callbacks
|
||||
- Gateway access is via SSH, proxy, or WireGuard instead of a browser
|
||||
- The deployment should be hidden from internet scanners
|
||||
|
||||
### Setup
|
||||
|
||||
```bash
|
||||
fly deploy -c deploy/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 the private config so future deploys do not re-allocate public IPs
|
||||
fly deploy -c deploy/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:
|
||||
|
||||
```text
|
||||
VERSION IP TYPE REGION
|
||||
v6 fdaa:x:x:x:x::x private global
|
||||
```
|
||||
|
||||
### Accessing a private deployment
|
||||
|
||||
**Option 1: local proxy (simplest)**
|
||||
|
||||
```bash
|
||||
fly proxy 3000:3000 -a my-openclaw
|
||||
# open http://localhost:3000 in a browser
|
||||
```
|
||||
|
||||
**Option 2: WireGuard VPN**
|
||||
|
||||
```bash
|
||||
fly wireguard create
|
||||
# import to a 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
|
||||
|
||||
For 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 for outbound calls without webhooks
|
||||
|
||||
Example voice-call config with ngrok, under `plugins.entries.voice-call.config`:
|
||||
|
||||
```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 tunnel hostname so forwarded host headers are accepted.
|
||||
|
||||
### Security tradeoffs
|
||||
|
||||
| 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; the Dockerfile is compatible with both x86 and ARM.
|
||||
- For WhatsApp/Telegram onboarding, use `fly ssh console`.
|
||||
- Persistent data lives on the volume at `/data`.
|
||||
- Signal requires signal-cli (a Java-based CLI) on the image; use a custom image and keep memory at 2GB+.
|
||||
|
||||
## Cost
|
||||
|
||||
With the recommended config (`shared-cpu-2x`, 2GB RAM), expect roughly $10-15/month depending on usage; the free tier covers some baseline allowance. See [Fly.io pricing](https://fly.io/docs/about/pricing/) for current rates.
|
||||
|
||||
## Next steps
|
||||
|
||||
- Set up messaging channels: [Channels](/channels)
|
||||
- Configure the Gateway: [Gateway configuration](/gateway/configuration)
|
||||
- Keep OpenClaw up to date: [Updating](/install/updating)
|
||||
|
||||
## Related
|
||||
|
||||
- [Install overview](/install)
|
||||
- [Hetzner](/install/hetzner)
|
||||
- [Docker](/install/docker)
|
||||
- [VPS hosting](/vps)
|
||||
329
docs/install/gcp.md
Normal file
329
docs/install/gcp.md
Normal file
@@ -0,0 +1,329 @@
|
||||
---
|
||||
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"
|
||||
---
|
||||
|
||||
Run a persistent OpenClaw Gateway on a GCP Compute Engine VM using Docker, with durable state, baked-in binaries, and safe restart behavior.
|
||||
|
||||
Pricing varies by machine type and region; pick the smallest VM that fits your workload and scale up if you hit OOMs.
|
||||
|
||||
The Gateway can be accessed via SSH port forwarding from your laptop, or via 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).
|
||||
|
||||
## What you need
|
||||
|
||||
- GCP account (`e2-micro` is free-tier eligible)
|
||||
- `gcloud` CLI, or the [Cloud Console](https://console.cloud.google.com)
|
||||
- SSH access from your laptop
|
||||
- Docker and Docker Compose
|
||||
- Model auth credentials
|
||||
- Optional provider credentials (WhatsApp QR, Telegram bot token, Gmail OAuth)
|
||||
- ~20-30 minutes
|
||||
|
||||
## Quick path
|
||||
|
||||
1. Create a GCP project, enable billing and the Compute Engine API
|
||||
2. Create a Compute Engine VM (`e2-small`, Debian 12, 20GB)
|
||||
3. SSH into the VM, install Docker
|
||||
4. Clone the OpenClaw repository
|
||||
5. Create persistent host directories
|
||||
6. Configure `.env` and `docker-compose.yml`
|
||||
7. Bake required binaries, build, and launch
|
||||
|
||||
<Steps>
|
||||
<Step title="Install gcloud CLI (or use Console)">
|
||||
Install from [cloud.google.com/sdk/docs/install](https://cloud.google.com/sdk/docs/install), then:
|
||||
|
||||
```bash
|
||||
gcloud init
|
||||
gcloud auth login
|
||||
```
|
||||
|
||||
Or do every step below through the [Cloud Console](https://console.cloud.google.com) web UI instead.
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Create a GCP project">
|
||||
```bash
|
||||
gcloud projects create my-openclaw-project --name="OpenClaw Gateway"
|
||||
gcloud config set project my-openclaw-project
|
||||
gcloud services enable compute.googleapis.com
|
||||
```
|
||||
|
||||
Enable billing at [console.cloud.google.com/billing](https://console.cloud.google.com/billing) (required for Compute Engine).
|
||||
|
||||
Console equivalent: IAM & Admin > Create Project, enable billing, then APIs & Services > Enable APIs > "Compute Engine API" > Enable.
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Create the VM">
|
||||
| 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 a Docker build |
|
||||
| e2-micro | 2 vCPU (shared), 1GB RAM | Free tier eligible | Often fails with Docker build OOM (exit 137) |
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="SSH into the VM">
|
||||
```bash
|
||||
gcloud compute ssh openclaw-gateway --zone=us-central1-a
|
||||
```
|
||||
|
||||
Console: click "SSH" next to the VM in the Compute Engine dashboard.
|
||||
|
||||
SSH key propagation can take 1-2 minutes after VM creation; wait and retry if connection is refused.
|
||||
|
||||
</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, then SSH back in:
|
||||
|
||||
```bash
|
||||
exit
|
||||
```
|
||||
|
||||
```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 builds a custom image so any binaries you bake in survive restarts.
|
||||
|
||||
</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
|
||||
```
|
||||
|
||||
Set `OPENCLAW_GATEWAY_TOKEN` to manage the stable gateway token through
|
||||
`.env`; otherwise configure `gateway.auth.token` before relying on clients
|
||||
across restarts. If neither is set, OpenClaw uses a runtime-only token for
|
||||
that startup. Generate a keyring password for `GOG_KEYRING_PASSWORD`:
|
||||
|
||||
```bash
|
||||
openssl rand -hex 32
|
||||
```
|
||||
|
||||
**Do not commit this file.** It holds 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, not a substitute for real gateway configuration. Still set auth (`gateway.auth.token` or password) and a safe bind mode for your deployment.
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Shared Docker VM runtime steps">
|
||||
Follow 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">
|
||||
If the build fails with `Killed` or `exit code 137` during `pnpm install --frozen-lockfile`, the VM is out of memory. Use `e2-small` at 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
|
||||
```
|
||||
|
||||
Replace `18789` with your configured port if you changed it.
|
||||
|
||||
</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 `http://127.0.0.1:18789/` in your browser.
|
||||
|
||||
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; use your configured password instead if you switched to password
|
||||
auth).
|
||||
|
||||
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>
|
||||
```
|
||||
|
||||
See [Docker VM Runtime](/install/docker-vm-runtime#what-persists-where) for the shared persistence map and [update flow](/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 the Docker build fails with `Killed` and `exit code 137`, the VM was OOM-killed:
|
||||
|
||||
```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, create a dedicated service account with minimal permissions:
|
||||
|
||||
```bash
|
||||
gcloud iam service-accounts create openclaw-deploy \
|
||||
--display-name="OpenClaw Deployment"
|
||||
|
||||
gcloud projects add-iam-policy-binding my-openclaw-project \
|
||||
--member="serviceAccount:openclaw-deploy@my-openclaw-project.iam.gserviceaccount.com" \
|
||||
--role="roles/compute.instanceAdmin.v1"
|
||||
```
|
||||
|
||||
Avoid the Owner role for automation; use the narrowest role that works. See [Understanding roles](https://cloud.google.com/iam/docs/understanding-roles).
|
||||
|
||||
## Next steps
|
||||
|
||||
- Set up messaging channels: [Channels](/channels)
|
||||
- Pair local devices as nodes: [Nodes](/nodes)
|
||||
- Configure the Gateway: [Gateway configuration](/gateway/configuration)
|
||||
|
||||
## Related
|
||||
|
||||
- [Install overview](/install)
|
||||
- [Azure](/install/azure)
|
||||
- [VPS hosting](/vps)
|
||||
245
docs/install/hetzner.md
Normal file
245
docs/install/hetzner.md
Normal file
@@ -0,0 +1,245 @@
|
||||
---
|
||||
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"
|
||||
---
|
||||
|
||||
Run a persistent OpenClaw Gateway on a Hetzner VPS using Docker, with durable state, baked-in binaries, and safe restart behavior.
|
||||
|
||||
Hetzner pricing changes; pick the smallest Debian/Ubuntu VPS that fits and scale up if you hit OOMs.
|
||||
|
||||
The Gateway can be accessed via SSH port forwarding from your laptop, or via direct port exposure if you manage firewalling and tokens yourself.
|
||||
|
||||
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).
|
||||
|
||||
This guide assumes Ubuntu or Debian on Hetzner. On another Linux VPS, map packages accordingly. For the generic Docker flow, see [Docker](/install/docker).
|
||||
|
||||
## What you need
|
||||
|
||||
- Hetzner VPS with root access
|
||||
- SSH access from your laptop
|
||||
- Docker and Docker Compose
|
||||
- Model auth credentials
|
||||
- Optional provider credentials (WhatsApp QR, Telegram bot token, Gmail OAuth)
|
||||
- ~20 minutes
|
||||
|
||||
## Quick path
|
||||
|
||||
1. Provision Hetzner VPS
|
||||
2. Install Docker
|
||||
3. Clone the 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
|
||||
|
||||
<Steps>
|
||||
<Step title="Provision the VPS">
|
||||
Create an Ubuntu or Debian VPS in Hetzner, then connect as root:
|
||||
|
||||
```bash
|
||||
ssh root@YOUR_VPS_IP
|
||||
```
|
||||
|
||||
Treat the VPS as stateful, not 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 builds a custom image so any binaries you bake in survive restarts.
|
||||
|
||||
</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
|
||||
```
|
||||
|
||||
Set `OPENCLAW_GATEWAY_TOKEN` to manage the stable gateway token through
|
||||
`.env`; otherwise configure `gateway.auth.token` before relying on clients
|
||||
across restarts. If neither is set, OpenClaw uses a runtime-only token for
|
||||
that startup. Generate a keyring password for `GOG_KEYRING_PASSWORD`:
|
||||
|
||||
```bash
|
||||
openssl rand -hex 32
|
||||
```
|
||||
|
||||
**Do not commit this file.** It holds 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, not a substitute for real gateway configuration. Still set auth (`gateway.auth.token` or password) and a safe bind mode for your deployment.
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Shared Docker VM runtime steps">
|
||||
Follow 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, open the tunnel.
|
||||
|
||||
**Prerequisite:** ensure your VPS sshd config allows TCP forwarding. If you
|
||||
hardened your SSH config, check `/etc/ssh/sshd_config` and set:
|
||||
|
||||
```text
|
||||
AllowTcpForwarding local
|
||||
```
|
||||
|
||||
`local` allows `ssh -L` local forwards from your laptop while blocking
|
||||
remote forwards from the server. Setting it to `no` fails the tunnel with:
|
||||
`channel 3: open failed: administratively prohibited: open failed`
|
||||
|
||||
After confirming TCP forwarding is enabled, restart the SSH service
|
||||
(`systemctl restart ssh`) and run the 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/` and paste the configured shared secret.
|
||||
This guide uses the gateway token by default; use your configured password
|
||||
instead if you switched to password auth.
|
||||
|
||||
</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.
|
||||
</Note>
|
||||
|
||||
## Next steps
|
||||
|
||||
- Set up messaging channels: [Channels](/channels)
|
||||
- Configure the Gateway: [Gateway configuration](/gateway/configuration)
|
||||
- Keep OpenClaw up to date: [Updating](/install/updating)
|
||||
|
||||
## Related
|
||||
|
||||
- [Install overview](/install)
|
||||
- [Fly.io](/install/fly)
|
||||
- [Docker](/install/docker)
|
||||
- [VPS hosting](/vps)
|
||||
98
docs/install/hostinger.md
Normal file
98
docs/install/hostinger.md
Normal file
@@ -0,0 +1,98 @@
|
||||
---
|
||||
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"
|
||||
---
|
||||
|
||||
Run a persistent OpenClaw Gateway on [Hostinger](https://www.hostinger.com/openclaw), either as a **1-Click** managed deployment or as a **VPS** install you administer yourself.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Hostinger account ([signup](https://www.hostinger.com/openclaw))
|
||||
- About 5-10 minutes
|
||||
|
||||
## Option A: 1-Click OpenClaw
|
||||
|
||||
Hostinger handles infrastructure, Docker, and automatic updates. Fastest path to a running instance.
|
||||
|
||||
<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 the server. Hostinger deploys OpenClaw via Docker on your VPS; 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 run from the Docker Manager interface in hPanel. To update, press **Update** in Docker Manager to pull the latest image.
|
||||
|
||||
## Verify your setup
|
||||
|
||||
Send "Hi" to your assistant on the channel you connected. OpenClaw replies and walks you through initial preferences.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Dashboard not loading** -- Wait a few minutes for the container to finish provisioning, then 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** -- If DM pairing is required, an unknown sender gets a short pairing code instead of a reply. Approve it from the OpenClaw dashboard chat, or with `openclaw pairing approve telegram <CODE>` if you have shell access to the container. See [Pairing](/channels/pairing).
|
||||
|
||||
## Next steps
|
||||
|
||||
- [Channels](/channels) -- connect Telegram, WhatsApp, Discord, and more
|
||||
- [Gateway configuration](/gateway/configuration) -- all config options
|
||||
|
||||
## Related
|
||||
|
||||
- [Install overview](/install)
|
||||
- [VPS hosting](/vps)
|
||||
- [DigitalOcean](/install/digitalocean)
|
||||
210
docs/install/index.md
Normal file
210
docs/install/index.md
Normal file
@@ -0,0 +1,210 @@
|
||||
---
|
||||
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"
|
||||
---
|
||||
|
||||
## System requirements
|
||||
|
||||
- **Node 22.19+, 23.11+, or 24+** - Node 24 is the default target; the installer script handles this automatically.
|
||||
- **macOS, Linux, or Windows** - Windows users can start with the native Windows Hub app, the PowerShell CLI installer, or a WSL2 Gateway. See [Windows](/platforms/windows).
|
||||
- `pnpm` is only needed if you build from source.
|
||||
|
||||
## Recommended: installer script
|
||||
|
||||
The fastest way to install. It detects your OS, installs Node if needed, installs OpenClaw, and launches onboarding.
|
||||
|
||||
<Note>
|
||||
Windows desktop users can also install the native [Windows Hub](/platforms/windows#recommended-windows-hub) companion app, which includes setup, tray status, chat, node mode, and local MCP mode.
|
||||
</Note>
|
||||
|
||||
<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).
|
||||
|
||||
## 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).
|
||||
|
||||
Already installed? Switch between package and git installs with
|
||||
`openclaw update --channel dev` and `openclaw update --channel stable`. See
|
||||
[Updating](/install/updating#switch-between-npm-and-git-installs).
|
||||
|
||||
### npm, pnpm, or bun
|
||||
|
||||
If you already manage Node yourself:
|
||||
|
||||
<Tabs>
|
||||
<Tab title="npm">
|
||||
```bash
|
||||
npm install -g openclaw@latest
|
||||
openclaw onboard --install-daemon
|
||||
```
|
||||
|
||||
<Note>
|
||||
The hosted installer clears npm freshness filters such as `min-release-age`
|
||||
for the OpenClaw package install. If you install manually with npm, your own
|
||||
npm policy still applies.
|
||||
</Note>
|
||||
|
||||
</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>
|
||||
|
||||
### 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 the GitHub main checkout
|
||||
|
||||
```bash
|
||||
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --install-method git --version 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. See [Linux server](/vps) for the full
|
||||
provider picker (DigitalOcean, Hetzner, Hostinger, Fly.io, GCP, Azure, Railway,
|
||||
Northflank, Oracle Cloud, Raspberry Pi, and more), or deploy declaratively on
|
||||
[Render](/install/render).
|
||||
|
||||
<CardGroup cols={3}>
|
||||
<Card title="VPS" href="/vps">
|
||||
Pick a provider.
|
||||
</Card>
|
||||
<Card title="Docker VM" href="/install/docker-vm-runtime">
|
||||
Shared Docker steps.
|
||||
</Card>
|
||||
<Card title="Kubernetes" href="/install/kubernetes">
|
||||
K8s deployment.
|
||||
</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
|
||||
|
||||
Almost always a PATH issue: npm's global bin directory isn't on your shell's `PATH`. See [Node.js troubleshooting](/install/node#troubleshooting) for the full fix, including the Windows path.
|
||||
|
||||
```bash
|
||||
node -v # Node installed?
|
||||
npm prefix -g # Where are global packages?
|
||||
echo "$PATH" # Is the global bin dir in PATH?
|
||||
```
|
||||
453
docs/install/installer.md
Normal file
453
docs/install/installer.md
Normal file
@@ -0,0 +1,453 @@
|
||||
---
|
||||
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"
|
||||
---
|
||||
|
||||
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, can run onboarding. |
|
||||
| [`install-cli.sh`](#install-clish) | macOS / Linux / WSL | Installs Node + OpenClaw into a local prefix (`~/.openclaw`) via npm or git. No root required. |
|
||||
| [`install.ps1`](#installps1) | Windows (PowerShell) | Installs Node if needed, installs OpenClaw via npm (default) or git, can run onboarding. |
|
||||
|
||||
All three support Node **22.19+, 23.11+, or 24+**; Node 24 is the default target for fresh installs.
|
||||
|
||||
## 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).
|
||||
</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). On macOS, Homebrew is installed only when the installer needs it for Node or Git. Node 22.19+ and 23.11+ remain supported for compatibility.
|
||||
On Alpine/musl Linux, the installer uses apk packages instead of NodeSource; the configured Alpine repositories must provide a supported Node version (Alpine 3.21 or newer at the time of writing).
|
||||
</Step>
|
||||
<Step title="Ensure Git">
|
||||
Installs Git if missing using the detected package manager, including Homebrew on macOS and apk on Alpine.
|
||||
</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)
|
||||
- Runs a post-install smoke verify when `--verify` is set
|
||||
|
||||
</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 checkout">
|
||||
```bash
|
||||
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --install-method git --version main
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="Dry run">
|
||||
```bash
|
||||
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --dry-run
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="Verify after install">
|
||||
```bash
|
||||
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --no-onboard --verify
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Flags reference">
|
||||
|
||||
| Flag | Description |
|
||||
| --------------------------------------- | ----------------------------------------------------------------------- |
|
||||
| `--install-method \| --method npm\|git` | Choose install method (default: `npm`) |
|
||||
| `--npm` | Shortcut for npm method |
|
||||
| `--git \| --github` | Shortcut for git method |
|
||||
| `--version <version\|dist-tag\|spec>` | npm version, dist-tag, or package spec (default: `latest`) |
|
||||
| `--beta` | Use beta dist-tag if available, else fall back to `latest` |
|
||||
| `--git-dir \| --dir <path>` | Checkout directory (default: `~/openclaw`) |
|
||||
| `--no-git-update` | Skip `git pull` for existing checkout |
|
||||
| `--no-prompt` | Disable prompts |
|
||||
| `--no-onboard` | Skip onboarding |
|
||||
| `--onboard` | Enable onboarding |
|
||||
| `--verify` | Run a post-install smoke verify (`--version`, gateway health if loaded) |
|
||||
| `--dry-run` | Print actions without applying changes |
|
||||
| `--verbose` | Enable debug output (`set -x`, npm notice-level logs) |
|
||||
| `--help \| -h` | Show usage |
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Environment variables reference">
|
||||
|
||||
| Variable | Description |
|
||||
| ------------------------------------------------- | ------------------------------------------------------------------ |
|
||||
| `OPENCLAW_INSTALL_METHOD=git\|npm` | Install method |
|
||||
| `OPENCLAW_VERSION=latest\|next\|<semver>\|<spec>` | npm version, dist-tag, or package spec |
|
||||
| `OPENCLAW_BETA=0\|1` | Use beta if available |
|
||||
| `OPENCLAW_HOME=<path>` | Base directory for OpenClaw state and default git/onboarding paths |
|
||||
| `OPENCLAW_GIT_DIR=<path>` | Checkout directory |
|
||||
| `OPENCLAW_GIT_UPDATE=0\|1` | Toggle git updates |
|
||||
| `OPENCLAW_NO_PROMPT=1` | Disable prompts |
|
||||
| `OPENCLAW_VERIFY_INSTALL=1` | Run the post-install smoke verify |
|
||||
| `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 (default: `error`, hides npm deprecation noise) |
|
||||
|
||||
</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, default `22.22.0`) to `<prefix>/tools/node-v<version>` and verifies SHA-256.
|
||||
On Alpine/musl Linux, where Node does not publish compatible tarballs for the pinned runtime, installs `nodejs` and `npm` with `apk` and links that runtime into the prefix wrapper path. The Alpine repositories must provide a supported Node version (22.19+, 23.11+, or 24+); use Alpine 3.21 or newer if older repositories only provide Node 20 or 21.
|
||||
</Step>
|
||||
<Step title="Ensure Git">
|
||||
If Git is missing, attempts install via apt/dnf/yum/apk 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 \| --method npm\|git` | Choose install method (default: `npm`) |
|
||||
| `--npm` | Shortcut for npm method |
|
||||
| `--git \| --github` | Shortcut for git method |
|
||||
| `--git-dir \| --dir <path>` | Git checkout directory (default: `~/openclaw`) |
|
||||
| `--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 \| -h` | Show usage |
|
||||
|
||||
</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_HOME=<path>` | Base directory for OpenClaw state and default git/onboarding paths |
|
||||
| `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 (default: `error`) |
|
||||
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
<Note>
|
||||
`openclaw@main` and other GitHub source specs are not valid `--version` targets for npm installs. Use `--install-method git --version main` instead.
|
||||
</Note>
|
||||
|
||||
---
|
||||
|
||||
<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. If no package manager is available, the script downloads the official Node.js 24 Windows zip into `%LOCALAPPDATA%\OpenClaw\deps\portable-node` and adds it to the current process and user PATH. Node 22.19+ and 23.11+ remain supported for compatibility.
|
||||
</Step>
|
||||
<Step title="Install OpenClaw">
|
||||
- `npm` method (default): global npm install using the selected `-Tag`, launched from a writable installer temp directory so shells opened in protected folders such as `C:\` still work
|
||||
- `git` method: clone/update repo, install/build with pnpm, and install wrapper at `%USERPROFILE%\.local\bin\openclaw.cmd`. If Git is missing, the script bootstraps user-local MinGit under `%LOCALAPPDATA%\OpenClaw\deps\portable-git` and adds it to the current process and user PATH.
|
||||
|
||||
</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>
|
||||
<Step title="Handle failures">
|
||||
`iwr ... | iex` and scriptblock installs report a terminating error without closing the current PowerShell session. Direct `powershell -File` / `pwsh -File` installs still exit non-zero for automation.
|
||||
</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 checkout">
|
||||
```powershell
|
||||
& ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -InstallMethod git -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>
|
||||
</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 tries a user-local MinGit bootstrap before printing 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 the `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's global prefix to root-owned paths. `install.sh` can switch the prefix to `~/.npm-global` and append PATH exports to shell rc files (when those files exist).
|
||||
</Accordion>
|
||||
|
||||
<Accordion title='Windows: "npm error spawn git / ENOENT"'>
|
||||
Rerun the installer so it can bootstrap user-local MinGit, or install Git for Windows and reopen PowerShell.
|
||||
</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 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>
|
||||
|
||||
## Related
|
||||
|
||||
- [Install overview](/install)
|
||||
- [Updating](/install/updating)
|
||||
- [Uninstall](/install/uninstall)
|
||||
195
docs/install/kubernetes.md
Normal file
195
docs/install/kubernetes.md
Normal file
@@ -0,0 +1,195 @@
|
||||
---
|
||||
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"
|
||||
---
|
||||
|
||||
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. Layer a Helm chart on top of these manifests if your deployment grows more complex.
|
||||
|
||||
## 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
|
||||
```
|
||||
|
||||
`deploy.sh` creates token auth by default. Retrieve the generated gateway token for the Control UI:
|
||||
|
||||
```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 do not 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
|
||||
```
|
||||
|
||||
Add `--show-token` to either command to print the token 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
|
||||
|
||||
```text
|
||||
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:slim # primary; official Docker Hub mirror: openclaw/openclaw
|
||||
```
|
||||
|
||||
### Expose beyond port-forward
|
||||
|
||||
The default manifests bind the gateway to loopback inside the pod. That works with `kubectl port-forward`, but not with a Kubernetes `Service` or Ingress path that needs to reach the pod IP directly.
|
||||
|
||||
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 hardening: `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
|
||||
|
||||
```text
|
||||
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
|
||||
```
|
||||
|
||||
## Related
|
||||
|
||||
- [Docker](/install/docker)
|
||||
- [Docker VM runtime](/install/docker-vm-runtime)
|
||||
- [Install overview](/install)
|
||||
245
docs/install/macos-vm.md
Normal file
245
docs/install/macos-vm.md
Normal file
@@ -0,0 +1,245 @@
|
||||
---
|
||||
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 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"
|
||||
---
|
||||
|
||||
## 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 only when you specifically need macOS-only capabilities such as iMessage, 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 `imsg`; the default local path is 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 [Install OpenClaw](#6-install-openclaw) 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` is not 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.
|
||||
</Note>
|
||||
|
||||
## 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:
|
||||
|
||||
1. Enable SSH: System Settings -> General -> Sharing, enable "Remote Login".
|
||||
2. For headless VM use, enable auto-login: System Settings -> Users & Groups, select "Automatically log in as:", and choose the VM user.
|
||||
|
||||
## 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: {
|
||||
telegram: {
|
||||
botToken: "YOUR_BOT_TOKEN",
|
||||
},
|
||||
whatsapp: {
|
||||
dmPolicy: "allowlist",
|
||||
allowFrom: ["+15551234567"],
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Then log in 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 [iMessage](/channels/imessage) with `imsg` to add Messages to OpenClaw.
|
||||
|
||||
Inside the VM:
|
||||
|
||||
1. Sign in to Messages.
|
||||
2. Install `imsg`.
|
||||
3. Grant Full Disk Access and Automation permission for the process running OpenClaw/`imsg`.
|
||||
4. Verify RPC support with `imsg rpc --help`.
|
||||
|
||||
Add to your OpenClaw config:
|
||||
|
||||
```json5
|
||||
{
|
||||
channels: {
|
||||
imessage: {
|
||||
enabled: true,
|
||||
cliPath: "imsg",
|
||||
dbPath: "~/Library/Messages/chat.db",
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Restart the gateway. Your agent can now send and receive iMessages. Full setup details: [iMessage channel](/channels/imessage).
|
||||
|
||||
## 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 |
|
||||
| ------------------------ | ----------------------------------------------------------------------------------- |
|
||||
| Cannot SSH into VM | Check "Remote Login" is enabled in the 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 are logged into the VM (not host) when running `openclaw channels login` |
|
||||
|
||||
## Related docs
|
||||
|
||||
- [VPS hosting](/vps)
|
||||
- [Nodes](/nodes)
|
||||
- [Gateway remote](/gateway/remote)
|
||||
- [iMessage channel](/channels/imessage)
|
||||
- [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)
|
||||
165
docs/install/migrating-claude.md
Normal file
165
docs/install/migrating-claude.md
Normal file
@@ -0,0 +1,165 @@
|
||||
---
|
||||
summary: "Move Claude Code and Claude Desktop local state into OpenClaw with a previewed import"
|
||||
read_when:
|
||||
- You are coming from Claude Code or Claude Desktop and want to keep instructions, MCP servers, and skills
|
||||
- You need to understand what OpenClaw imports automatically and what stays archive-only
|
||||
title: "Migrating from Claude"
|
||||
---
|
||||
|
||||
OpenClaw imports local Claude state through the bundled Claude migration provider. The provider previews every item before changing state, redacts secrets in plans and reports, and creates a verified backup before apply.
|
||||
|
||||
<Note>
|
||||
Onboarding imports require a fresh OpenClaw setup. If you already have local OpenClaw state, reset config, credentials, sessions, and the workspace first, or use `openclaw migrate` directly with `--overwrite` after reviewing the plan.
|
||||
</Note>
|
||||
|
||||
## Two ways to import
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Onboarding wizard">
|
||||
The wizard offers Claude when it detects local Claude state.
|
||||
|
||||
```bash
|
||||
openclaw onboard --flow import
|
||||
```
|
||||
|
||||
Or point at a specific source:
|
||||
|
||||
```bash
|
||||
openclaw onboard --import-from claude --import-source ~/.claude
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="CLI">
|
||||
Use `openclaw migrate` for scripted or repeatable runs. See [`openclaw migrate`](/cli/migrate) for the full reference.
|
||||
|
||||
```bash
|
||||
openclaw migrate claude --dry-run
|
||||
openclaw migrate apply claude --yes
|
||||
```
|
||||
|
||||
Add `--from <path>` to import a specific Claude Code home or project root.
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## What gets imported
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Instructions and memory">
|
||||
- Project `CLAUDE.md` and `.claude/CLAUDE.md` content is copied or appended into the OpenClaw agent workspace `AGENTS.md`.
|
||||
- User `~/.claude/CLAUDE.md` content is appended into workspace `USER.md`.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="MCP servers">
|
||||
MCP server definitions are imported from project `.mcp.json`, Claude Code `~/.claude.json`, and Claude Desktop `claude_desktop_config.json` when present.
|
||||
</Accordion>
|
||||
<Accordion title="Skills and commands">
|
||||
- Claude skills with a `SKILL.md` file are copied into the OpenClaw workspace skills directory.
|
||||
- Claude command Markdown files under `.claude/commands/` or `~/.claude/commands/` are converted into OpenClaw skills with `disable-model-invocation: true`.
|
||||
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## What stays archive-only
|
||||
|
||||
The provider copies these into the migration report for manual review, but does **not** load them into live OpenClaw config:
|
||||
|
||||
- Claude hooks
|
||||
- Claude permissions and broad tool allowlists
|
||||
- Claude environment defaults
|
||||
- `CLAUDE.local.md`
|
||||
- `.claude/rules/`
|
||||
- Claude subagents under `.claude/agents/` or `~/.claude/agents/`
|
||||
- Claude Code caches, plans, and project history directories
|
||||
- Claude Desktop extensions and OS-stored credentials
|
||||
|
||||
OpenClaw refuses to execute hooks, trust permission allowlists, or decode opaque OAuth and Desktop credential state automatically. Move what you need by hand after reviewing the archive.
|
||||
|
||||
## Source selection
|
||||
|
||||
Without `--from`, OpenClaw inspects the default Claude Code home at `~/.claude`, the sampled Claude Code `~/.claude.json` state file, and the Claude Desktop MCP config on macOS.
|
||||
|
||||
When `--from` points at a project root, OpenClaw imports only that project's Claude files, such as `CLAUDE.md`, `.claude/settings.json`, `.claude/commands/`, `.claude/skills/`, and `.mcp.json`. It does not read your global Claude home during a project-root import.
|
||||
|
||||
## Recommended flow
|
||||
|
||||
<Steps>
|
||||
<Step title="Preview the plan">
|
||||
```bash
|
||||
openclaw migrate claude --dry-run
|
||||
```
|
||||
|
||||
The plan lists everything that will change, including conflicts, skipped items, and sensitive values redacted from nested MCP `env` or `headers` fields.
|
||||
|
||||
</Step>
|
||||
<Step title="Apply with backup">
|
||||
```bash
|
||||
openclaw migrate apply claude --yes
|
||||
```
|
||||
|
||||
OpenClaw creates and verifies a backup before applying.
|
||||
|
||||
</Step>
|
||||
<Step title="Run doctor">
|
||||
```bash
|
||||
openclaw doctor
|
||||
```
|
||||
|
||||
[Doctor](/gateway/doctor) checks for config or state issues after the import.
|
||||
|
||||
</Step>
|
||||
<Step title="Restart and verify">
|
||||
```bash
|
||||
openclaw gateway restart
|
||||
openclaw status
|
||||
```
|
||||
|
||||
Confirm the gateway is healthy and your imported instructions, MCP servers, and skills are loaded.
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Conflict handling
|
||||
|
||||
Apply refuses to continue when the plan reports conflicts (a file or config value already exists at the target).
|
||||
|
||||
<Warning>
|
||||
Rerun with `--overwrite` only when replacing the existing target is intentional. Providers may still write item-level backups for overwritten files in the migration report directory.
|
||||
</Warning>
|
||||
|
||||
For a fresh OpenClaw install, conflicts are unusual. They typically appear when you re-run the import on a setup that already has user edits.
|
||||
|
||||
## JSON output for automation
|
||||
|
||||
```bash
|
||||
openclaw migrate claude --dry-run --json
|
||||
openclaw migrate apply claude --json --yes
|
||||
```
|
||||
|
||||
`--yes` is required for `migrate apply` outside an interactive terminal; without it OpenClaw errors instead of applying, so scripts and CI must pass `--yes` explicitly. Preview first with `--dry-run --json`, then apply with `--json --yes` once the plan looks right.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Claude state lives outside ~/.claude">
|
||||
Pass `--from /actual/path` (CLI) or `--import-source /actual/path` (onboarding).
|
||||
</Accordion>
|
||||
<Accordion title="Onboarding refuses to import on an existing setup">
|
||||
Onboarding imports require a fresh setup. Either reset state and re-onboard, or use `openclaw migrate apply claude` directly, which supports `--overwrite` and explicit backup control.
|
||||
</Accordion>
|
||||
<Accordion title="MCP servers from Claude Desktop did not import">
|
||||
Claude Desktop reads `claude_desktop_config.json` from a platform-specific path. Point `--from` at that file's directory if OpenClaw did not detect it automatically.
|
||||
</Accordion>
|
||||
<Accordion title="Claude commands became skills with model invocation disabled">
|
||||
By design. Claude commands are user-triggered, so OpenClaw imports them as skills with `disable-model-invocation: true`. Edit each skill's frontmatter if you want the agent to invoke them automatically.
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Related
|
||||
|
||||
- [`openclaw migrate`](/cli/migrate): full CLI reference, plugin contract, and JSON shapes.
|
||||
- [Migration guide](/install/migrating): all migration paths.
|
||||
- [Migrating from Hermes](/install/migrating-hermes): the other cross-system import path.
|
||||
- [Onboarding](/cli/onboard): wizard flow and non-interactive flags.
|
||||
- [Doctor](/gateway/doctor): post-migration health check.
|
||||
- [Agent workspace](/concepts/agent-workspace): where `AGENTS.md`, `USER.md`, and skills live.
|
||||
177
docs/install/migrating-hermes.md
Normal file
177
docs/install/migrating-hermes.md
Normal file
@@ -0,0 +1,177 @@
|
||||
---
|
||||
summary: "Move from Hermes to OpenClaw with a previewed, reversible import"
|
||||
read_when:
|
||||
- You are coming from Hermes and want to keep your model config, prompts, memory, and skills
|
||||
- You want to know what OpenClaw imports automatically and what stays archive-only
|
||||
- You need a clean, scripted migration path (CI, fresh laptop, automation)
|
||||
title: "Migrating from Hermes"
|
||||
---
|
||||
|
||||
The bundled Hermes migration provider detects state at `~/.hermes`, previews every change before applying, redacts secrets in plans and reports, and writes a verified OpenClaw backup before it touches anything.
|
||||
|
||||
<Note>
|
||||
Imports require a fresh OpenClaw setup. If you already have local OpenClaw state, reset config, credentials, sessions, and the workspace first, or use `openclaw migrate apply hermes` directly with `--overwrite` after reviewing the plan.
|
||||
</Note>
|
||||
|
||||
## Two ways to import
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Onboarding wizard">
|
||||
Detects Hermes at `~/.hermes` and shows a preview before applying.
|
||||
|
||||
```bash
|
||||
openclaw onboard --flow import
|
||||
```
|
||||
|
||||
Or point at a specific source:
|
||||
|
||||
```bash
|
||||
openclaw onboard --import-from hermes --import-source ~/.hermes
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="CLI">
|
||||
Use `openclaw migrate` for scripted or repeatable runs. See [`openclaw migrate`](/cli/migrate) for the full reference.
|
||||
|
||||
```bash
|
||||
openclaw migrate hermes --dry-run # preview only
|
||||
openclaw migrate apply hermes --yes # apply with confirmation skipped
|
||||
```
|
||||
|
||||
Add `--from <path>` when Hermes lives outside `~/.hermes`.
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## What gets imported
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Model configuration">
|
||||
- Default model selection from Hermes `config.yaml`.
|
||||
- Configured model providers and custom OpenAI-compatible endpoints from `providers` and `custom_providers`.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="MCP servers">
|
||||
MCP server definitions from `mcp_servers` or `mcp.servers`.
|
||||
</Accordion>
|
||||
<Accordion title="Workspace files">
|
||||
- `SOUL.md` and `AGENTS.md` are copied into the OpenClaw agent workspace.
|
||||
- `memories/MEMORY.md` and `memories/USER.md` are **appended** to the matching OpenClaw memory files instead of overwriting them.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="Memory configuration">
|
||||
Memory config defaults for OpenClaw file memory. External memory providers such as Honcho are recorded as archive or manual-review items so you can move them deliberately.
|
||||
</Accordion>
|
||||
<Accordion title="Skills">
|
||||
Skills with a `SKILL.md` file under `skills/<name>/` are copied, along with per-skill config values from `skills.config`.
|
||||
</Accordion>
|
||||
<Accordion title="Auth credentials">
|
||||
Interactive `openclaw migrate` asks before importing auth credentials, with yes selected by default. Accepting imports OpenCode OpenAI OAuth and GitHub Copilot entries from OpenCode's `auth.json`, plus the [supported Hermes `.env` keys](/cli/migrate#supported-env-keys). Hermes's own `auth.json` OAuth entries are legacy state: they surface as a manual reauth/doctor item instead of importing into live auth. Use `--include-secrets` to import credentials in a non-interactive run, `--no-auth-credentials` to skip credential import entirely, or the onboarding wizard's `--import-secrets` flag.
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## What stays archive-only
|
||||
|
||||
The provider copies these into the migration report directory for manual review, but does **not** load them into live OpenClaw config or credentials:
|
||||
|
||||
- `plugins/`
|
||||
- `sessions/`
|
||||
- `logs/`
|
||||
- `cron/`
|
||||
- `mcp-tokens/`
|
||||
- `state.db`
|
||||
|
||||
OpenClaw refuses to execute or trust this state automatically because formats and trust assumptions can drift between systems. Move what you need by hand after reviewing the archive.
|
||||
|
||||
## Recommended flow
|
||||
|
||||
<Steps>
|
||||
<Step title="Preview the plan">
|
||||
```bash
|
||||
openclaw migrate hermes --dry-run
|
||||
```
|
||||
|
||||
The plan lists everything that will change, including conflicts, skipped items, and sensitive items. Nested secret-looking keys are redacted in the output.
|
||||
|
||||
</Step>
|
||||
<Step title="Apply with backup">
|
||||
```bash
|
||||
openclaw migrate apply hermes --yes
|
||||
```
|
||||
|
||||
OpenClaw creates and verifies a backup before applying. This non-interactive example imports non-secret state only. Run without `--yes` to answer the credential prompt interactively, or add `--include-secrets` to include supported credentials in an unattended run.
|
||||
|
||||
</Step>
|
||||
<Step title="Run doctor">
|
||||
```bash
|
||||
openclaw doctor
|
||||
```
|
||||
|
||||
[Doctor](/gateway/doctor) reapplies any pending config migrations and checks for issues introduced during the import.
|
||||
|
||||
</Step>
|
||||
<Step title="Restart and verify">
|
||||
```bash
|
||||
openclaw gateway restart
|
||||
openclaw status
|
||||
```
|
||||
|
||||
Confirm the gateway is healthy and your imported model, memory, and skills are loaded.
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Conflict handling
|
||||
|
||||
Apply refuses to continue when the plan reports conflicts (a file or config value already exists at the target).
|
||||
|
||||
<Warning>
|
||||
Rerun with `--overwrite` only when replacing the existing target is intentional. Providers may still write item-level backups for overwritten files in the migration report directory.
|
||||
</Warning>
|
||||
|
||||
Conflicts are unusual on a fresh install. They typically show up when you re-run the import against a setup that already has user edits.
|
||||
|
||||
If a conflict surfaces mid-apply (for example, an unexpected race on a config file), Hermes marks remaining dependent config items as `skipped` with reason `blocked by earlier apply conflict` instead of writing them partially. The migration report records each blocked item so you can resolve the original conflict and rerun the import.
|
||||
|
||||
## Secrets
|
||||
|
||||
Interactive `openclaw migrate` asks whether to import detected auth credentials, with yes selected by default.
|
||||
|
||||
- Accepting imports OpenCode OpenAI OAuth and GitHub Copilot entries from OpenCode's `auth.json`, plus the [supported `.env` keys](/cli/migrate#supported-env-keys). Hermes's own `auth.json` OAuth entries are reported for manual OpenAI reauth or doctor repair instead.
|
||||
- Use `--no-auth-credentials`, or answer no at the prompt, to import non-secret state only.
|
||||
- Use `--include-secrets` to import credentials in an unattended `--yes` run.
|
||||
- Use the onboarding wizard's `--import-secrets` flag to import credentials from the wizard.
|
||||
|
||||
## JSON output for automation
|
||||
|
||||
```bash
|
||||
openclaw migrate hermes --dry-run --json
|
||||
openclaw migrate apply hermes --json --yes
|
||||
```
|
||||
|
||||
With `--json` and no `--yes`, apply prints the plan and does not mutate state — the safest mode for CI and shared scripts.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Apply refuses with conflicts">
|
||||
Inspect the plan output. Each conflict identifies the source path and the existing target. Decide per item whether to skip, edit the target, or rerun with `--overwrite`.
|
||||
</Accordion>
|
||||
<Accordion title="Hermes lives outside ~/.hermes">
|
||||
Pass `--from /actual/path` (CLI) or `--import-source /actual/path` (onboarding).
|
||||
</Accordion>
|
||||
<Accordion title="Onboarding refuses to import on an existing setup">
|
||||
Onboarding imports require a fresh setup. Either reset state and re-onboard, or use `openclaw migrate apply hermes` directly, which supports `--overwrite` and explicit backup control.
|
||||
</Accordion>
|
||||
<Accordion title="API keys did not import">
|
||||
Interactive `openclaw migrate` imports API keys only when you accept the credential prompt. Non-interactive `--yes` runs need `--include-secrets`; onboarding imports need `--import-secrets`. Only the [supported `.env` keys](/cli/migrate#supported-env-keys) are recognized — other `.env` variables are ignored.
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Related
|
||||
|
||||
- [`openclaw migrate`](/cli/migrate): full CLI reference, plugin contract, and JSON shapes.
|
||||
- [Onboarding](/cli/onboard): wizard flow and non-interactive flags.
|
||||
- [Migrating](/install/migrating): move an OpenClaw install between machines.
|
||||
- [Doctor](/gateway/doctor): post-migration health check.
|
||||
- [Agent workspace](/concepts/agent-workspace): where `SOUL.md`, `AGENTS.md`, and memory files live.
|
||||
137
docs/install/migrating.md
Normal file
137
docs/install/migrating.md
Normal file
@@ -0,0 +1,137 @@
|
||||
---
|
||||
summary: "Migration hub: cross-system imports, machine-to-machine moves, and plugin upgrades"
|
||||
read_when:
|
||||
- You are moving OpenClaw to a new laptop or server
|
||||
- You are coming from another agent system and want to keep state
|
||||
- You are upgrading an in-place plugin
|
||||
title: "Migration guide"
|
||||
---
|
||||
|
||||
OpenClaw supports three migration paths: importing from another agent system, moving an existing install to a new machine, and upgrading a plugin in place.
|
||||
|
||||
## Import from another agent system
|
||||
|
||||
Bundled migration providers bring instructions, MCP servers, skills, model config, and (opt-in) API keys into OpenClaw. Plans are previewed before any change, secrets are redacted in reports, and apply is backed by a verified backup.
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Migrating from Claude" href="/install/migrating-claude" icon="brain">
|
||||
Import Claude Code and Claude Desktop state, including `CLAUDE.md`, MCP servers, skills, and project commands.
|
||||
</Card>
|
||||
<Card title="Migrating from Hermes" href="/install/migrating-hermes" icon="feather">
|
||||
Import Hermes config, providers, MCP servers, memory, skills, and supported `.env` keys.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
The CLI entry point is [`openclaw migrate`](/cli/migrate). Onboarding can also offer migration when it detects a known source (`openclaw onboard --flow import`).
|
||||
|
||||
## Move OpenClaw to a new machine
|
||||
|
||||
Copy the **state directory** (`~/.openclaw/` by default) and your **workspace** to preserve:
|
||||
|
||||
- **Config** — `openclaw.json` and all gateway settings.
|
||||
- **Auth** — per-agent `auth-profiles.json` (API keys plus OAuth), plus any channel or provider state under `credentials/`.
|
||||
- **Sessions** — conversation history and agent state.
|
||||
- **Channel state** — WhatsApp login, Telegram session, and similar.
|
||||
- **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 (for example `~/.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 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
|
||||
```
|
||||
|
||||
Confirm 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>
|
||||
|
||||
If Telegram or Discord uses the default env fallback (`TELEGRAM_BOT_TOKEN` or `DISCORD_BOT_TOKEN`), verify the migrated state-dir `.env` contains those keys without printing the secret values:
|
||||
|
||||
```bash
|
||||
awk -F= '/^(TELEGRAM_BOT_TOKEN|DISCORD_BOT_TOKEN)=/ { print $1 "=present" }' ~/.openclaw/.env
|
||||
```
|
||||
|
||||
`openclaw doctor` also warns when an enabled default Telegram or Discord account has no configured token and the matching env variable is unavailable to the doctor process.
|
||||
|
||||
### 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 and provider state 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.
|
||||
|
||||
## Upgrade a plugin in place
|
||||
|
||||
In-place plugin upgrades preserve the same plugin id and config keys but may move on-disk state into the current layout. Plugin-specific upgrade guides live alongside their channels:
|
||||
|
||||
- [Matrix migration](/channels/matrix-migration): encrypted-state recovery limits, automatic snapshot behavior, and manual recovery commands.
|
||||
|
||||
## Related
|
||||
|
||||
- [`openclaw migrate`](/cli/migrate): CLI reference for cross-system imports.
|
||||
- [Install overview](/install): all installation methods.
|
||||
- [Doctor](/gateway/doctor): post-migration health check.
|
||||
- [Uninstall](/install/uninstall): removing OpenClaw cleanly.
|
||||
109
docs/install/nix.md
Normal file
109
docs/install/nix.md
Normal file
@@ -0,0 +1,109 @@
|
||||
---
|
||||
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"
|
||||
---
|
||||
|
||||
Install OpenClaw declaratively with **[nix-openclaw](https://github.com/openclaw/nix-openclaw)**, the first-party, 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 for Nix-managed installs. Other Nix packages can set the same mode; nix-openclaw is the first-party reference.
|
||||
|
||||
You can also set it manually:
|
||||
|
||||
```bash
|
||||
export OPENCLAW_NIX_MODE=1
|
||||
```
|
||||
|
||||
On macOS, the GUI app does not 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.
|
||||
- `openclaw.json` is treated as immutable. Startup-derived defaults stay runtime-only, and config writers (setup, onboarding, mutating `openclaw update`, plugin install/update/uninstall/enable, `doctor --fix`, `doctor --generate-gateway-token`, `openclaw config set`) refuse to edit the file.
|
||||
- Edit the Nix source instead. For nix-openclaw, use the agent-first [Quick Start](https://github.com/openclaw/nix-openclaw#quick-start) and set config under `programs.openclaw.config` or `instances.<name>.config`.
|
||||
- Missing dependencies surface Nix-specific remediation messages.
|
||||
- The UI shows 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`. 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` |
|
||||
|
||||
### Service PATH discovery
|
||||
|
||||
The launchd/systemd gateway service auto-discovers Nix-profile binaries so plugins and tools that shell out to `nix`-installed executables work without manual PATH setup:
|
||||
|
||||
- When `NIX_PROFILES` is set, every entry is added to the service PATH in right-to-left precedence (matches Nix shell precedence: rightmost wins).
|
||||
- When `NIX_PROFILES` is unset, `~/.nix-profile/bin` is added as a fallback.
|
||||
|
||||
This applies to both macOS launchd and Linux systemd service environments.
|
||||
|
||||
## Related
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="nix-openclaw" href="https://github.com/openclaw/nix-openclaw" icon="arrow-up-right-from-square">
|
||||
Source-of-truth Home Manager module and full setup guide.
|
||||
</Card>
|
||||
<Card title="Setup wizard" href="/start/wizard" icon="wand-magic-sparkles">
|
||||
Non-Nix CLI setup walkthrough.
|
||||
</Card>
|
||||
<Card title="Docker" href="/install/docker" icon="docker">
|
||||
Containerized setup as a non-Nix alternative.
|
||||
</Card>
|
||||
<Card title="Updating" href="/install/updating" icon="arrow-up-right-from-square">
|
||||
Updating Home Manager-managed installs alongside the package.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
142
docs/install/node.md
Normal file
142
docs/install/node.md
Normal file
@@ -0,0 +1,142 @@
|
||||
---
|
||||
summary: "Install and configure Node.js for OpenClaw - version requirements, install options, and PATH troubleshooting"
|
||||
title: "Node.js"
|
||||
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"
|
||||
---
|
||||
|
||||
OpenClaw requires **Node 22.19+, Node 23.11+, or Node 24+**. **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) detects and installs Node automatically — use this page when you want to set up Node yourself (versions, PATH, global installs).
|
||||
|
||||
## Check your version
|
||||
|
||||
```bash
|
||||
node -v
|
||||
```
|
||||
|
||||
`v24.x.x` or higher is the recommended default. `v22.19.x` or higher is the supported Node 22 LTS path (upgrade to Node 24 when convenient). Node 23 builds before `v23.11.0` are unsupported. If Node is missing or outside the supported range, 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>
|
||||
Initialize your version manager in your shell startup file (`~/.zshrc` or `~/.bashrc`). If you skip this, `openclaw` may not be found in new terminal sessions because 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
|
||||
39
docs/install/northflank.mdx
Normal file
39
docs/install/northflank.mdx
Normal file
@@ -0,0 +1,39 @@
|
||||
---
|
||||
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 a 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)
|
||||
218
docs/install/oracle.md
Normal file
218
docs/install/oracle.md
Normal file
@@ -0,0 +1,218 @@
|
||||
---
|
||||
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"
|
||||
---
|
||||
|
||||
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 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>
|
||||
|
||||
## Verify the security posture
|
||||
|
||||
With the VCN locked down (only UDP 41641 open) and the Gateway bound to loopback, public traffic is blocked at the network edge and admin access is tailnet-only. That removes the need for several traditional VPS hardening steps:
|
||||
|
||||
| Traditional step | Needed? | Why |
|
||||
| ------------------ | ----------- | ------------------------------------------------------------------------- |
|
||||
| UFW firewall | No | The VCN blocks traffic before it reaches the instance. |
|
||||
| fail2ban | No | Port 22 is blocked at the VCN; no brute-force surface. |
|
||||
| sshd hardening | No | Tailscale SSH does not use sshd. |
|
||||
| Disable root login | No | Tailscale authenticates by tailnet identity, not system users. |
|
||||
| SSH key-only auth | No | Same -- tailnet identity replaces system SSH keys. |
|
||||
| IPv6 hardening | Usually not | Depends on VCN/subnet settings; verify what is actually assigned/exposed. |
|
||||
|
||||
Still recommended:
|
||||
|
||||
- `chmod 700 ~/.openclaw` to restrict credential file permissions.
|
||||
- `openclaw security audit` for an OpenClaw-specific posture check.
|
||||
- Regular `sudo apt update && sudo apt upgrade` for OS patches.
|
||||
- Review devices in the [Tailscale admin console](https://login.tailscale.com/admin) periodically.
|
||||
|
||||
Quick verification commands:
|
||||
|
||||
```bash
|
||||
# Confirm no public ports are listening
|
||||
sudo ss -tlnp | grep -v '127.0.0.1\|::1'
|
||||
|
||||
# Verify Tailscale SSH is active
|
||||
tailscale status | grep -q 'offers: ssh' && echo "Tailscale SSH active"
|
||||
|
||||
# Optional: disable sshd entirely once Tailscale SSH is confirmed working
|
||||
sudo systemctl disable --now ssh
|
||||
```
|
||||
|
||||
## ARM notes
|
||||
|
||||
The Always Free tier is ARM (`aarch64`). Most OpenClaw features work fine; a small number of native binaries need ARM builds:
|
||||
|
||||
- Node.js, Telegram, WhatsApp (Baileys): pure JavaScript, no issues.
|
||||
- Most npm packages with native code: pre-built `linux-arm64` artifacts available.
|
||||
- Optional CLI helpers (e.g. Go/Rust binaries shipped by skills): check for an `aarch64` / `linux-arm64` release before installing.
|
||||
|
||||
Verify the architecture with `uname -m` (should print `aarch64`). For binaries without an ARM build, install from source or skip them.
|
||||
|
||||
## Persistence and backups
|
||||
|
||||
OpenClaw state lives under:
|
||||
|
||||
- `~/.openclaw/` -- `openclaw.json`, per-agent `auth-profiles.json`, channel/provider state, and session data.
|
||||
- `~/.openclaw/workspace/` -- the agent workspace (SOUL.md, memory, artifacts).
|
||||
|
||||
These survive reboots. To take a portable snapshot:
|
||||
|
||||
```bash
|
||||
openclaw backup create
|
||||
```
|
||||
|
||||
## 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
|
||||
|
||||
## Related
|
||||
|
||||
- [Install overview](/install)
|
||||
- [GCP](/install/gcp)
|
||||
- [VPS hosting](/vps)
|
||||
177
docs/install/podman.md
Normal file
177
docs/install/podman.md
Normal file
@@ -0,0 +1,177 @@
|
||||
---
|
||||
summary: "Run OpenClaw in a rootless Podman container"
|
||||
read_when:
|
||||
- You want a containerized gateway with Podman instead of Docker
|
||||
title: "Podman"
|
||||
---
|
||||
|
||||
Run the OpenClaw Gateway in a rootless Podman container, managed by your current non-root user.
|
||||
|
||||
The model:
|
||||
|
||||
- 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`.
|
||||
|
||||
This builds `openclaw:local` in your rootless Podman store (or pulls `OPENCLAW_IMAGE` / `OPENCLAW_PODMAN_IMAGE` if set), creates `~/.openclaw/openclaw.json` with `gateway.mode: "local"` if missing, and creates `~/.openclaw/.env` with a generated `OPENCLAW_GATEWAY_TOKEN` if missing.
|
||||
|
||||
Optional build-time env vars:
|
||||
|
||||
| Var | Effect |
|
||||
| --- | --- |
|
||||
| `OPENCLAW_IMAGE` / `OPENCLAW_PODMAN_IMAGE` | Use an existing/pulled image instead of building `openclaw:local` |
|
||||
| `OPENCLAW_IMAGE_APT_PACKAGES` | Install extra apt packages during image build (also accepts legacy `OPENCLAW_DOCKER_APT_PACKAGES`) |
|
||||
| `OPENCLAW_IMAGE_PIP_PACKAGES` | Install extra Python packages during image build; pin versions and use only package indexes you trust |
|
||||
| `OPENCLAW_EXTENSIONS` | Pre-install plugin dependencies at build time |
|
||||
| `OPENCLAW_INSTALL_BROWSER` | Pre-install Chromium and Xvfb for browser automation (set to `1`) |
|
||||
|
||||
For Quadlet-managed setup instead (Linux + systemd user services only):
|
||||
|
||||
```bash
|
||||
./scripts/podman/setup.sh --quadlet
|
||||
```
|
||||
|
||||
Or set `OPENCLAW_PODMAN_QUADLET=1`.
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Start the Gateway container">
|
||||
```bash
|
||||
./scripts/run-openclaw-podman.sh launch
|
||||
```
|
||||
|
||||
Starts the container as your current uid/gid with `--userns=keep-id` and bind-mounts your OpenClaw state into the container.
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Run onboarding inside the container">
|
||||
```bash
|
||||
./scripts/run-openclaw-podman.sh launch setup
|
||||
```
|
||||
|
||||
Then open `http://127.0.0.1:18789/` and use the token from `~/.openclaw/.env`.
|
||||
|
||||
Model auth: use OpenClaw-managed auth during setup (Anthropic API keys, or OpenAI Codex browser OAuth/device-code auth for Codex-backed OpenAI). The Podman launcher does not mount host CLI credential homes such as `~/.claude` or `~/.codex` into the setup or gateway container. Existing host CLI logins are same-host convenience paths only -- for container installs, keep provider auth in the mounted `~/.openclaw` state that setup manages.
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Manage the running container from the host CLI">
|
||||
```bash
|
||||
export OPENCLAW_CONTAINER=openclaw
|
||||
```
|
||||
|
||||
Then normal `openclaw` commands 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 and Tailscale](#podman-and-tailscale).
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
The manual launcher 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.
|
||||
|
||||
<a id="podman-and-tailscale"></a>
|
||||
|
||||
## Podman and Tailscale
|
||||
|
||||
For HTTPS or remote browser access, follow the main Tailscale docs.
|
||||
|
||||
Podman-specific notes:
|
||||
|
||||
- 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) and [Control UI](/web/control-ui).
|
||||
|
||||
## Systemd (Quadlet, optional)
|
||||
|
||||
If you ran `./scripts/podman/setup.sh --quadlet`, setup installs a Quadlet file at `~/.config/containers/systemd/openclaw.container`.
|
||||
|
||||
| Action | Command |
|
||||
| ------ | ------------------------------------------ |
|
||||
| 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)"
|
||||
```
|
||||
|
||||
The generated Quadlet service keeps a fixed, hardened default shape: `127.0.0.1` published ports (`18789` gateway, `18790` bridge), `--bind lan` inside the container, `keep-id` user namespace, `OPENCLAW_NO_RESPAWN=1`, `Restart=on-failure`, and `TimeoutStartSec=300`. It reads `~/.openclaw/.env` as a runtime `EnvironmentFile` for values such as `OPENCLAW_GATEWAY_TOKEN`, but does not consume the manual launcher's Podman-specific override allowlist. For custom publish ports, publish host, or other container-run flags, use the manual launcher instead, or edit `~/.config/containers/systemd/openclaw.container` directly and then reload and restart the service.
|
||||
|
||||
## 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. 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 (persist these in `~/.openclaw/.env`; the launcher reads that file before finalizing container/image defaults):
|
||||
|
||||
| Var | Default | Effect |
|
||||
| ------------------------------------------ | ---------------- | -------------------------------------- |
|
||||
| `OPENCLAW_PODMAN_CONTAINER` | `openclaw` | Container name |
|
||||
| `OPENCLAW_PODMAN_IMAGE` / `OPENCLAW_IMAGE` | `openclaw:local` | Image to run |
|
||||
| `OPENCLAW_PODMAN_GATEWAY_HOST_PORT` | `18789` | Host port mapped to container `18789` |
|
||||
| `OPENCLAW_PODMAN_BRIDGE_HOST_PORT` | `18790` | Host port mapped to container `18790` |
|
||||
| `OPENCLAW_PODMAN_PUBLISH_HOST` | `127.0.0.1` | Host interface for published ports |
|
||||
| `OPENCLAW_GATEWAY_BIND` | `lan` | Gateway bind mode inside the container |
|
||||
| `OPENCLAW_PODMAN_USERNS` | `keep-id` | `keep-id`, `auto`, or `host` |
|
||||
|
||||
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.
|
||||
|
||||
## 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)
|
||||
75
docs/install/railway.mdx
Normal file
75
docs/install/railway.mdx
Normal file
@@ -0,0 +1,75 @@
|
||||
---
|
||||
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.
|
||||
|
||||
## One-click deploy
|
||||
|
||||
<a href="https://railway.com/deploy/clawdbot-railway-template" target="_blank" rel="noreferrer">
|
||||
Deploy on Railway
|
||||
</a>
|
||||
|
||||
<Steps>
|
||||
<Step title="Deploy the template">
|
||||
Click **Deploy on Railway** above.
|
||||
</Step>
|
||||
|
||||
<Step title="Add a volume">
|
||||
Attach a volume mounted at `/data` (required for persistent state).
|
||||
</Step>
|
||||
|
||||
<Step title="Set variables">
|
||||
Set the required **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)
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Enable public networking">
|
||||
Under **Public Networking**, enable **HTTP Proxy** for the service on port `8080`.
|
||||
</Step>
|
||||
|
||||
<Step title="Connect">
|
||||
Find your public URL in **Railway -> your service -> Settings -> Domains** -- either a generated domain (often `https://<something>.up.railway.app`) or your attached custom domain.
|
||||
|
||||
Open `https://<your-railway-domain>/openclaw` and connect using the configured shared secret. The template uses `OPENCLAW_GATEWAY_TOKEN` by default; if you replace it with password auth, use that password instead.
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## What you get
|
||||
|
||||
- Hosted OpenClaw Gateway + Control UI
|
||||
- Persistent storage via the Railway 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 Railway's shell for channel setup instructions:
|
||||
|
||||
- [Discord](/channels/discord)
|
||||
- [Telegram](/channels/telegram) (fastest -- just a bot token)
|
||||
- [All channels](/channels)
|
||||
|
||||
## Backups and 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)
|
||||
230
docs/install/raspberry-pi.md
Normal file
230
docs/install/raspberry-pi.md
Normal file
@@ -0,0 +1,230 @@
|
||||
---
|
||||
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"
|
||||
---
|
||||
|
||||
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 -- typical hardware cost is **$35-80 one-time**, no monthly fees.
|
||||
|
||||
## Hardware compatibility
|
||||
|
||||
| Pi model | RAM | Works? | Notes |
|
||||
| ----------- | ------ | ------ | ----------------------------------- |
|
||||
| Pi 5 | 4/8 GB | Best | Fastest, recommended. |
|
||||
| Pi 4 | 4 GB | Good | Sweet spot for most users. |
|
||||
| Pi 4 | 2 GB | OK | Add swap. |
|
||||
| Pi 4 | 1 GB | Tight | Possible with swap, minimal config. |
|
||||
| Pi 3B+ | 1 GB | Slow | Works but sluggish. |
|
||||
| Pi Zero 2 W | 512 MB | No | Not recommended. |
|
||||
|
||||
**Minimum:** 1 GB RAM, 1 core, 500 MB free disk, 64-bit OS.
|
||||
**Recommended:** 2 GB+ RAM, 16 GB+ SD card (or USB SSD), Ethernet.
|
||||
|
||||
## 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 and survives more write cycles; use it for `OPENCLAW_STATE_DIR` if you keep the OS on SD. 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. `OPENCLAW_NO_RESPAWN=1` keeps routine Gateway restarts in-process, avoiding extra process handoffs and keeping PID tracking simple on small 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
|
||||
```
|
||||
|
||||
Use `/var/tmp`, not `/tmp` -- some distros clear `/tmp` on boot, which drops the warmed cache.
|
||||
|
||||
**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
|
||||
```
|
||||
|
||||
**systemd drop-in for stable restarts** -- If this Pi is mostly running OpenClaw, add a service drop-in:
|
||||
|
||||
```bash
|
||||
systemctl --user edit openclaw-gateway.service
|
||||
```
|
||||
|
||||
```ini
|
||||
[Service]
|
||||
Environment=OPENCLAW_NO_RESPAWN=1
|
||||
Environment=NODE_COMPILE_CACHE=/var/tmp/openclaw-compile-cache
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
TimeoutStartSec=90
|
||||
```
|
||||
|
||||
Then `systemctl --user daemon-reload && systemctl --user restart openclaw-gateway.service`. On a headless Pi, also enable lingering once so the user service survives logout: `sudo loginctl enable-linger "$(whoami)"`.
|
||||
|
||||
## Recommended model setup
|
||||
|
||||
Since the Pi only runs the gateway, use cloud-hosted API models -- do not run local LLMs on a Pi, even small models are too slow to be useful:
|
||||
|
||||
```json
|
||||
{
|
||||
"agents": {
|
||||
"defaults": {
|
||||
"model": {
|
||||
"primary": "anthropic/claude-sonnet-4-6",
|
||||
"fallbacks": ["openai/gpt-5.4-mini"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## ARM binary notes
|
||||
|
||||
Most OpenClaw features work on ARM64 without changes (Node.js, Telegram, WhatsApp/Baileys, Chromium). The binaries that occasionally lack ARM builds are typically optional Go/Rust CLI tools shipped by skills. Verify architecture with `uname -m` (should show `aarch64`), then check a missing binary's release page for `linux-arm64` / `aarch64` artifacts before falling back to building from source.
|
||||
|
||||
## Persistence and backups
|
||||
|
||||
OpenClaw state lives under:
|
||||
|
||||
- `~/.openclaw/` -- `openclaw.json`, per-agent `auth-profiles.json`, channel/provider state, sessions.
|
||||
- `~/.openclaw/workspace/` -- agent workspace (SOUL.md, memory, artifacts).
|
||||
|
||||
These survive reboots and benefit from SSD over SD card for both performance and longevity. Take a portable snapshot with:
|
||||
|
||||
```bash
|
||||
openclaw backup create
|
||||
```
|
||||
|
||||
## 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
|
||||
|
||||
## Related
|
||||
|
||||
- [Install overview](/install)
|
||||
- [Linux server](/vps)
|
||||
- [Platforms](/platforms)
|
||||
135
docs/install/render.mdx
Normal file
135
docs/install/render.mdx
Normal file
@@ -0,0 +1,135 @@
|
||||
---
|
||||
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](https://render.com) using the repo's `render.yaml` Blueprint. It declares the service, disk, and environment variables in one file.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A [Render account](https://render.com) (free tier available)
|
||||
- An API key from your preferred [model provider](/providers)
|
||||
|
||||
## Deploy
|
||||
|
||||
[Deploy to Render](https://render.com/deploy?repo=https://github.com/openclaw/openclaw)
|
||||
|
||||
This creates a Render service from `render.yaml`, builds the Docker image, and deploys it. Your service URL follows the pattern `https://<service-name>.onrender.com`.
|
||||
|
||||
## The Blueprint
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
| 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 the free tier, change `plan: free` in your fork's `render.yaml` — note that with no persistent disk, 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 shared secret: the auto-generated `OPENCLAW_GATEWAY_TOKEN` (find it in **Dashboard → your service → Environment**), or your password if you switched to password auth.
|
||||
|
||||
### Logs
|
||||
|
||||
**Dashboard → your service → Logs** shows build logs (Docker image creation), deploy logs (service startup), and runtime logs (application output).
|
||||
|
||||
### Shell access
|
||||
|
||||
**Dashboard → your service → Shell** opens a shell session. The persistent disk is mounted at `/data`.
|
||||
|
||||
### Environment variables
|
||||
|
||||
Edit variables in **Dashboard → your service → Environment**. Changes trigger an automatic redeploy.
|
||||
|
||||
### Auto-deploy
|
||||
|
||||
Render redeploys automatically when the connected repo's branch gets a new commit. If you deployed straight from `openclaw/openclaw` instead of your own fork, you have no push access to trigger that, so update by running a manual Blueprint sync from the Dashboard, or point the service at your own fork.
|
||||
|
||||
## Custom domain
|
||||
|
||||
1. **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
|
||||
|
||||
- **Vertical**: change the plan for more CPU/RAM. Usually sufficient for OpenClaw.
|
||||
- **Horizontal**: increase instance count (Standard plan and above). Requires sticky sessions or external state management since OpenClaw keeps runtime state on the local disk.
|
||||
|
||||
## Backups and migration
|
||||
|
||||
From the Render Dashboard shell, export state, config, auth profiles, and workspace at any time:
|
||||
|
||||
```bash
|
||||
openclaw backup create
|
||||
```
|
||||
|
||||
This creates a portable backup archive. See [Backup](/cli/backup).
|
||||
|
||||
## 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` 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 for always-on.
|
||||
|
||||
### Data loss after redeploy
|
||||
|
||||
Happens on the free tier (no persistent disk). Upgrade to a paid plan, or regularly export a backup with `openclaw backup create` from the Render shell.
|
||||
|
||||
### Health check failures
|
||||
|
||||
If builds succeed but deploys fail, the service may be taking too long to start or `/health` may not be reachable. 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)
|
||||
145
docs/install/uninstall.md
Normal file
145
docs/install/uninstall.md
Normal file
@@ -0,0 +1,145 @@
|
||||
---
|
||||
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"
|
||||
---
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
State removal preserves configured workspace directories unless you also select `--workspace`.
|
||||
|
||||
Preview what will be removed (safe):
|
||||
|
||||
```bash
|
||||
openclaw uninstall --dry-run --all
|
||||
```
|
||||
|
||||
Non-interactive (automation / npx). Use with caution and only after confirming scopes:
|
||||
|
||||
```bash
|
||||
openclaw uninstall --all --yes --non-interactive
|
||||
npx -y openclaw uninstall --all --yes --non-interactive
|
||||
```
|
||||
|
||||
Flags: `--service`, `--state`, `--workspace`, `--app` select individual scopes; `--all` selects all four.
|
||||
|
||||
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.
|
||||
If you want to keep a workspace inside the state dir, such as `~/.openclaw/workspace`, move it aside before running `rm -rf` or delete state contents selectively.
|
||||
|
||||
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>` with a profile):
|
||||
|
||||
```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>`.
|
||||
|
||||
### Linux (systemd user unit)
|
||||
|
||||
Default unit name is `openclaw-gateway.service` (or `openclaw-gateway-<profile>.service`). A pre-rename `clawdbot-gateway.service` unit may still exist on machines upgraded from very old installs; `openclaw uninstall` / `openclaw gateway uninstall` detects and removes it automatically.
|
||||
|
||||
```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 launches a windowless `gateway.vbs` script under your state dir, which in turn
|
||||
runs `gateway.cmd`; remove both.
|
||||
|
||||
```powershell
|
||||
schtasks /Delete /F /TN "OpenClaw Gateway"
|
||||
Remove-Item -Force "$env:USERPROFILE\.openclaw\gateway.cmd" -ErrorAction SilentlyContinue
|
||||
Remove-Item -Force "$env:USERPROFILE\.openclaw\gateway.vbs" -ErrorAction SilentlyContinue
|
||||
```
|
||||
|
||||
If you used a profile, delete the matching task name and the `gateway.cmd` /
|
||||
`gateway.vbs` files under `~\.openclaw-<profile>`.
|
||||
|
||||
## 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.
|
||||
|
||||
## Related
|
||||
|
||||
- [Install overview](/install)
|
||||
- [Migration guide](/install/migrating)
|
||||
288
docs/install/updating.md
Normal file
288
docs/install/updating.md
Normal file
@@ -0,0 +1,288 @@
|
||||
---
|
||||
summary: "Updating OpenClaw safely (global install or source), plus rollback strategy"
|
||||
read_when:
|
||||
- Updating OpenClaw
|
||||
- Something breaks after an update
|
||||
title: "Updating"
|
||||
---
|
||||
|
||||
Keep OpenClaw up to date.
|
||||
|
||||
## Recommended: `openclaw update`
|
||||
|
||||
Detects your install type (npm or git), fetches the latest version, runs `openclaw doctor`, and restarts the gateway.
|
||||
|
||||
```bash
|
||||
openclaw update
|
||||
```
|
||||
|
||||
Switch channels or target a specific version:
|
||||
|
||||
```bash
|
||||
openclaw update --channel beta
|
||||
openclaw update --channel extended-stable
|
||||
openclaw update --channel dev
|
||||
openclaw update --dry-run # preview without applying
|
||||
```
|
||||
|
||||
`openclaw update` has no `--verbose` flag (the installer does). For diagnostics use
|
||||
`--dry-run` to preview planned actions, `--json` for structured results, or
|
||||
`openclaw update status --json` to inspect channel and availability state.
|
||||
|
||||
`--channel beta` prefers the beta npm dist-tag, but falls back to stable/latest
|
||||
when the beta tag is missing or its version is older than the latest stable
|
||||
release. Use `--tag beta` for a one-off package update pinned to the raw npm
|
||||
beta dist-tag instead.
|
||||
|
||||
`--channel extended-stable` is package-only and foreground-only. OpenClaw reads
|
||||
the public npm `extended-stable` selector, verifies the selected exact package,
|
||||
and installs that exact version. Missing or inconsistent registry data fails
|
||||
closed; it never falls back to `latest`. If the selected version is older than
|
||||
the installed version, the normal downgrade confirmation still applies.
|
||||
|
||||
`--channel dev` gives a persistent moving GitHub `main` checkout. For a one-off
|
||||
package update, `--tag main` maps to the `github:openclaw/openclaw#main` package
|
||||
spec and installs it directly through the target package manager (npm/pnpm/bun).
|
||||
|
||||
For managed plugins, a missing beta release is a warning, not a failure: the
|
||||
core update can still succeed while a plugin falls back to its recorded
|
||||
default/latest release.
|
||||
|
||||
See [Release channels](/install/development-channels) for channel semantics.
|
||||
|
||||
## Switch between npm and git installs
|
||||
|
||||
Use channels to change the install type. The updater keeps your state, config,
|
||||
credentials, and workspace in `~/.openclaw`; it only changes which OpenClaw
|
||||
code install the CLI and gateway use.
|
||||
|
||||
```bash
|
||||
# npm package install -> editable git checkout
|
||||
openclaw update --channel dev
|
||||
|
||||
# git checkout -> npm package install
|
||||
openclaw update --channel stable
|
||||
```
|
||||
|
||||
Preview the install-mode switch first:
|
||||
|
||||
```bash
|
||||
openclaw update --channel dev --dry-run
|
||||
openclaw update --channel stable --dry-run
|
||||
```
|
||||
|
||||
`dev` ensures a git checkout, builds it, and installs the global CLI from that
|
||||
checkout. The `stable`, `extended-stable`, and `beta` channels use package
|
||||
installs. Extended-stable is rejected on a git checkout without mutating or
|
||||
converting it. If the gateway is already installed, `openclaw update` refreshes
|
||||
the service metadata and restarts it unless you pass `--no-restart`.
|
||||
|
||||
For package installs with a managed Gateway service, `openclaw update` targets
|
||||
the package root used by that service. If the shell `openclaw` command comes
|
||||
from a different install, the updater prints both roots and the managed
|
||||
service's Node path, and checks that Node version against the target release's
|
||||
`engines.node` requirement before replacing the package.
|
||||
|
||||
## Alternative: re-run the installer
|
||||
|
||||
```bash
|
||||
curl -fsSL https://openclaw.ai/install.sh | bash
|
||||
```
|
||||
|
||||
Add `--no-onboard` to skip onboarding. To force a specific install type, pass
|
||||
`--install-method git --no-onboard` or `--install-method npm --no-onboard`.
|
||||
|
||||
If `openclaw update` fails after the npm package install phase, re-run the
|
||||
installer instead. It does not call the updater; it runs the global package
|
||||
install directly and can recover a partially updated npm install.
|
||||
|
||||
```bash
|
||||
curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method npm
|
||||
```
|
||||
|
||||
Pin the recovery to a specific version or dist-tag with `--version`:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method npm --version <version-or-dist-tag>
|
||||
```
|
||||
|
||||
## Alternative: manual npm, pnpm, or bun
|
||||
|
||||
```bash
|
||||
npm i -g openclaw@latest
|
||||
```
|
||||
|
||||
Prefer `openclaw update` for supervised installs: it can coordinate the package
|
||||
swap with the running Gateway service. If you update manually on a supervised
|
||||
install, stop the managed Gateway first. Package managers replace files in
|
||||
place, and a running Gateway can otherwise try to load core or plugin files
|
||||
mid-swap. Restart the Gateway after the package manager finishes so it picks up
|
||||
the new install.
|
||||
|
||||
For a root-owned Linux system-global install, if `openclaw update` fails with
|
||||
`EACCES`, recover with system npm while keeping the Gateway stopped for the
|
||||
manual replacement. Use the same profile flags/environment you normally use for
|
||||
that Gateway. Replace `/usr/bin/npm` with the system npm that owns the
|
||||
root-owned global prefix on your host:
|
||||
|
||||
```bash
|
||||
openclaw gateway stop
|
||||
sudo /usr/bin/npm i -g openclaw@latest
|
||||
openclaw gateway install --force
|
||||
openclaw gateway restart
|
||||
```
|
||||
|
||||
Then verify:
|
||||
|
||||
```bash
|
||||
openclaw --version
|
||||
curl -fsS http://127.0.0.1:18789/readyz
|
||||
openclaw plugins list --json
|
||||
openclaw gateway status --deep --json
|
||||
openclaw doctor --lint --json
|
||||
```
|
||||
|
||||
When `openclaw update` manages a global npm install, it installs the target
|
||||
into a temporary npm prefix first, verifies the packaged `dist` inventory, then
|
||||
swaps the clean package tree into the real global prefix — avoiding npm
|
||||
overlaying a new package onto stale files from the old one. If the install
|
||||
command fails, OpenClaw retries once with `--omit=optional`, which helps hosts
|
||||
where native optional dependencies cannot compile.
|
||||
|
||||
OpenClaw-managed npm update and plugin-update commands also clear npm's
|
||||
`min-release-age` supply-chain quarantine (or the older `before` config key)
|
||||
for the child npm process. That policy exists for general protection, but an
|
||||
explicit OpenClaw update means "install the selected release now."
|
||||
|
||||
```bash
|
||||
pnpm add -g openclaw@latest
|
||||
```
|
||||
|
||||
```bash
|
||||
bun add -g openclaw@latest
|
||||
```
|
||||
|
||||
### Advanced npm install topics
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Read-only package tree">
|
||||
OpenClaw treats packaged global installs as read-only at runtime, even when the global package directory is writable by the current user. Plugin package installs live in OpenClaw-owned npm/git roots under the user config directory, and Gateway startup does not mutate the OpenClaw package tree.
|
||||
|
||||
Some Linux npm setups install global packages under root-owned directories such as `/usr/lib/node_modules/openclaw`. OpenClaw supports that layout because plugin install/update commands write outside that global package directory.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="Hardened systemd units">
|
||||
Give OpenClaw write access to its config/state roots so explicit plugin installs, plugin updates, and doctor cleanup can persist their changes:
|
||||
|
||||
```ini
|
||||
ReadWritePaths=/var/lib/openclaw /home/openclaw/.openclaw /tmp
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="Disk-space preflight">
|
||||
Before package updates and explicit plugin installs, OpenClaw tries a best-effort disk-space check for the target volume. Low space produces a warning with the checked path, but does not block the update because filesystem quotas, snapshots, and network volumes can change after the check. The actual package-manager install and post-install verification remain authoritative.
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Auto-updater
|
||||
|
||||
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` (default: 6), then applies with deterministic jitter across `stableJitterHours` (default: 12) for a spread rollout. |
|
||||
| `extended-stable` | No startup check or automatic apply. Use `openclaw update` or `openclaw update status` manually. |
|
||||
| `beta` | Checks every `betaCheckIntervalHours` (default: 1) 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`).
|
||||
Stored extended-stable selections skip startup and background resolution entirely.
|
||||
For downgrade or incident recovery, set `OPENCLAW_NO_AUTO_UPDATE=1` in the gateway environment to block automatic applies even when `update.auto.enabled` is configured. Startup update hints can still run unless `update.checkOnStart` is also disabled.
|
||||
|
||||
Package-manager updates requested through the live Gateway control-plane
|
||||
(`update.run`) do not replace the package tree inside the running Gateway
|
||||
process. On managed service installs, the Gateway starts a detached handoff,
|
||||
exits, and lets the normal `openclaw update --yes --json` CLI path stop the
|
||||
service, replace the package, refresh service metadata, restart, verify the
|
||||
Gateway version and reachability, and recover an installed-but-unloaded macOS
|
||||
LaunchAgent when possible. If the Gateway cannot make that handoff safely,
|
||||
`update.run` reports a safe shell command instead of running the package
|
||||
manager in-process.
|
||||
|
||||
## 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.
|
||||
</Tip>
|
||||
|
||||
### 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.
|
||||
96
docs/install/upstash.md
Normal file
96
docs/install/upstash.md
Normal file
@@ -0,0 +1,96 @@
|
||||
---
|
||||
summary: "Host OpenClaw on Upstash Box with keep-alive and SSH tunnel access"
|
||||
read_when:
|
||||
- Deploying OpenClaw to Upstash Box
|
||||
- You want a managed Linux environment for OpenClaw with SSH-tunneled dashboard access
|
||||
title: "Upstash Box"
|
||||
---
|
||||
|
||||
Run a persistent OpenClaw Gateway on Upstash Box, a managed Linux environment
|
||||
with keep-alive lifecycle support.
|
||||
|
||||
Use an SSH tunnel for dashboard access. Do not expose the Gateway port directly
|
||||
to the public internet.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Upstash account
|
||||
- Keep-alive Upstash Box
|
||||
- SSH client on your local machine
|
||||
|
||||
## Create a Box
|
||||
|
||||
Create a keep-alive Box in the Upstash Console. Note the Box ID (for example
|
||||
`right-flamingo-14486`) and your Box API key.
|
||||
|
||||
Upstash maintains its current OpenClaw Box walkthrough at
|
||||
[OpenClaw Setup](https://upstash.com/docs/box/guides/openclaw-setup).
|
||||
|
||||
## Connect with an SSH tunnel
|
||||
|
||||
Forward the OpenClaw dashboard port to your local machine. Use your Box API key
|
||||
as the SSH password when prompted:
|
||||
|
||||
```bash
|
||||
ssh -o ServerAliveInterval=15 -o ServerAliveCountMax=3 -L 18789:127.0.0.1:18789 <box-id>@us-east-1.box.upstash.com
|
||||
```
|
||||
|
||||
The keepalive options reduce idle tunnel drops during onboarding.
|
||||
|
||||
## Install OpenClaw
|
||||
|
||||
Inside the Box:
|
||||
|
||||
```bash
|
||||
sudo npm install -g openclaw
|
||||
```
|
||||
|
||||
## Run onboarding
|
||||
|
||||
```bash
|
||||
openclaw onboard --install-daemon
|
||||
```
|
||||
|
||||
Follow the prompts. Copy the dashboard URL and token when onboarding finishes.
|
||||
|
||||
## Start the Gateway
|
||||
|
||||
Configure the Gateway for the Box network and start it in the background:
|
||||
|
||||
```bash
|
||||
openclaw config set gateway.bind lan
|
||||
nohup openclaw gateway > gateway.log 2>&1 &
|
||||
```
|
||||
|
||||
With the SSH tunnel active, open the dashboard URL locally:
|
||||
|
||||
```text
|
||||
http://127.0.0.1:18789/#token=<your-token>
|
||||
```
|
||||
|
||||
## Auto-restart
|
||||
|
||||
Set this command as the Box init script so the Gateway restarts when the Box
|
||||
starts:
|
||||
|
||||
```bash
|
||||
nohup openclaw gateway > gateway.log 2>&1 &
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If SSH freezes during onboarding, reconnect with a clean SSH config and
|
||||
keepalives:
|
||||
|
||||
```bash
|
||||
ssh -F /dev/null -o ControlMaster=no -o ServerAliveInterval=15 -o ServerAliveCountMax=3 -L 18789:127.0.0.1:18789 <box-id>@us-east-1.box.upstash.com
|
||||
```
|
||||
|
||||
This bypasses stale local `~/.ssh/config` settings and keeps the tunnel active
|
||||
through idle network periods.
|
||||
|
||||
## Related
|
||||
|
||||
- [Remote access](/gateway/remote)
|
||||
- [Gateway security](/gateway/security)
|
||||
- [Updating OpenClaw](/install/updating)
|
||||
Reference in New Issue
Block a user