diff --git a/docs/install/azure.md b/docs/install/azure.md
index a257059f75d..615049ef937 100644
--- a/docs/install/azure.md
+++ b/docs/install/azure.md
@@ -27,139 +27,148 @@ You’ll need:
- An Azure subscription with permission to create compute and network resources
- Azure CLI installed (see [Azure CLI install steps](https://learn.microsoft.com/cli/azure/install-azure-cli) if needed)
-## 1) Sign in to Azure CLI
+
+
+ ```bash
+ az login # Sign in and select your Azure subscription
+ az extension add -n ssh # Extension required for Azure Bastion SSH management
+ ```
+
-```bash
-az login # Sign in and select your Azure subscription
-az extension add -n ssh # Extension required for Azure Bastion SSH management
-```
+
+ ```bash
+ az provider register --namespace Microsoft.Compute
+ az provider register --namespace Microsoft.Network
+ ```
-## 2) Register required resource providers (one-time)
+ Verify Azure resource provider registration. Wait until both show `Registered`.
-```bash
-az provider register --namespace Microsoft.Compute
-az provider register --namespace Microsoft.Network
-```
+ ```bash
+ az provider show --namespace Microsoft.Compute --query registrationState -o tsv
+ az provider show --namespace Microsoft.Network --query registrationState -o tsv
+ ```
-Verify Azure resource provider 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
-```
+
+ ```bash
+ RG="rg-openclaw"
+ LOCATION="westus2"
+ TEMPLATE_URI="https://raw.githubusercontent.com/openclaw/openclaw/main/infra/azure/templates/azuredeploy.json"
+ PARAMS_URI="https://raw.githubusercontent.com/openclaw/openclaw/main/infra/azure/templates/azuredeploy.parameters.json"
+ ```
+
-## 3) Set deployment variables
+
+ Use your existing public key if you have one:
-```bash
-RG="rg-openclaw"
-LOCATION="westus2"
-TEMPLATE_URI="https://raw.githubusercontent.com/openclaw/openclaw/main/infra/azure/templates/azuredeploy.json"
-PARAMS_URI="https://raw.githubusercontent.com/openclaw/openclaw/main/infra/azure/templates/azuredeploy.parameters.json"
-```
+ ```bash
+ SSH_PUB_KEY="$(cat ~/.ssh/id_ed25519.pub)"
+ ```
-## 4) Select SSH key
+ If you don’t have an SSH key yet, run the following:
-Use your existing public key if you have one:
+ ```bash
+ ssh-keygen -t ed25519 -a 100 -f ~/.ssh/id_ed25519 -C "you@example.com"
+ SSH_PUB_KEY="$(cat ~/.ssh/id_ed25519.pub)"
+ ```
-```bash
-SSH_PUB_KEY="$(cat ~/.ssh/id_ed25519.pub)"
-```
+
-If you don’t have an SSH key yet, run the following:
+
+ Set VM and disk sizing variables:
-```bash
-ssh-keygen -t ed25519 -a 100 -f ~/.ssh/id_ed25519 -C "you@example.com"
-SSH_PUB_KEY="$(cat ~/.ssh/id_ed25519.pub)"
-```
+ ```bash
+ VM_SIZE="Standard_B2as_v2"
+ OS_DISK_SIZE_GB=64
+ ```
-## 5) Select VM size and OS disk size
+ Choose a VM size and OS disk size that are available in your Azure subscription/region and matches your workload:
-Set VM and disk sizing variables:
+ - Start smaller for light usage and scale up later
+ - Use more vCPU/RAM/OS disk size for heavier automation, more channels, or larger model/tool workloads
+ - If a VM size is unavailable in your region or subscription quota, pick the closest available SKU
-```bash
-VM_SIZE="Standard_B2as_v2"
-OS_DISK_SIZE_GB=64
-```
+ List VM sizes available in your target region:
-Choose a VM size and OS disk size that are available in your Azure subscription/region and matches your workload:
+ ```bash
+ az vm list-skus --location "${LOCATION}" --resource-type virtualMachines -o table
+ ```
-- Start smaller for light usage and scale up later
-- Use more vCPU/RAM/OS disk size for heavier automation, more channels, or larger model/tool workloads
-- If a VM size is unavailable in your region or subscription quota, pick the closest available SKU
+ Check your current VM vCPU and OS disk size usage/quota:
-List VM sizes available in your target region:
+ ```bash
+ az vm list-usage --location "${LOCATION}" -o table
+ ```
-```bash
-az vm list-skus --location "${LOCATION}" --resource-type virtualMachines -o table
-```
+
-Check your current VM vCPU and OS disk size usage/quota:
+
+ ```bash
+ az group create -n "${RG}" -l "${LOCATION}"
+ ```
+
-```bash
-az vm list-usage --location "${LOCATION}" -o table
-```
+
+ This command applies your selected SSH key, VM size, and OS disk size.
-## 6) Create the resource group
+ ```bash
+ az deployment group create \
+ -g "${RG}" \
+ --template-uri "${TEMPLATE_URI}" \
+ --parameters "${PARAMS_URI}" \
+ --parameters location="${LOCATION}" \
+ --parameters vmSize="${VM_SIZE}" \
+ --parameters osDiskSizeGb="${OS_DISK_SIZE_GB}" \
+ --parameters sshPublicKey="${SSH_PUB_KEY}"
+ ```
-```bash
-az group create -n "${RG}" -l "${LOCATION}"
-```
+
-## 7) Deploy resources
+
+ ```bash
+ RG="rg-openclaw"
+ VM_NAME="vm-openclaw"
+ BASTION_NAME="bas-openclaw"
+ ADMIN_USERNAME="openclaw"
+ VM_ID="$(az vm show -g "${RG}" -n "${VM_NAME}" --query id -o tsv)"
-This command applies your selected SSH key, VM size, and OS disk size.
+ 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
+ ```
-```bash
-az deployment group create \
- -g "${RG}" \
- --template-uri "${TEMPLATE_URI}" \
- --parameters "${PARAMS_URI}" \
- --parameters location="${LOCATION}" \
- --parameters vmSize="${VM_SIZE}" \
- --parameters osDiskSizeGb="${OS_DISK_SIZE_GB}" \
- --parameters sshPublicKey="${SSH_PUB_KEY}"
-```
+
-## 8) SSH into the VM through Azure Bastion
+
+ ```bash
+ curl -fsSL https://openclaw.ai/install.sh -o /tmp/openclaw-install.sh
+ bash /tmp/openclaw-install.sh
+ rm -f /tmp/openclaw-install.sh
+ openclaw --version
+ ```
-```bash
-RG="rg-openclaw"
-VM_NAME="vm-openclaw"
-BASTION_NAME="bas-openclaw"
-ADMIN_USERNAME="openclaw"
-VM_ID="$(az vm show -g "${RG}" -n "${VM_NAME}" --query id -o tsv)"
+ The installer script handles Node detection/installation and runs onboarding by default.
-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
-```
+
-## 9) Install OpenClaw (in the VM shell)
+
+ After onboarding completes:
-```bash
-curl -fsSL https://openclaw.ai/install.sh -o /tmp/openclaw-install.sh
-bash /tmp/openclaw-install.sh
-rm -f /tmp/openclaw-install.sh
-openclaw --version
-```
+ ```bash
+ openclaw gateway status
+ ```
-The installer script handles Node detection/installation and runs onboarding by default.
+ Most enterprise Azure teams already have GitHub Copilot licenses. If that is your case, we recommend choosing the GitHub Copilot provider in the OpenClaw onboarding wizard. See [GitHub Copilot provider](/providers/github-copilot).
-## 10) Verify the Gateway
+ The included ARM template uses Ubuntu image `version: "latest"` for convenience. If you need reproducible builds, pin a specific image version in `infra/azure/templates/azuredeploy.json` (you can list versions with `az vm image list --publisher Canonical --offer ubuntu-24_04-lts --sku server --all -o table`).
-After onboarding completes:
-
-```bash
-openclaw gateway status
-```
-
-Most enterprise Azure teams already have GitHub Copilot licenses. If that is your case, we recommend choosing the GitHub Copilot provider in the OpenClaw onboarding wizard. See [GitHub Copilot provider](/providers/github-copilot).
-
-The included ARM template uses Ubuntu image `version: "latest"` for convenience. If you need reproducible builds, pin a specific image version in `infra/azure/templates/azuredeploy.json` (you can list versions with `az vm image list --publisher Canonical --offer ubuntu-24_04-lts --sku server --all -o table`).
+
+
## Next steps
diff --git a/docs/install/fly.md b/docs/install/fly.md
index 1c01c7f63fa..aacfa484670 100644
--- a/docs/install/fly.md
+++ b/docs/install/fly.md
@@ -25,220 +25,228 @@ read_when:
3. Deploy with `fly deploy`
4. SSH in to create config or use Control UI
-## 1) Create the Fly app
+
+
+ ```bash
+ # Clone the repo
+ git clone https://github.com/openclaw/openclaw.git
+ cd openclaw
-```bash
-# Clone the repo
-git clone https://github.com/openclaw/openclaw.git
-cd openclaw
+ # Create a new Fly app (pick your own name)
+ fly apps create my-openclaw
-# Create a new Fly app (pick your own name)
-fly apps create my-openclaw
+ # Create a persistent volume (1GB is usually enough)
+ fly volumes create openclaw_data --size 1 --region iad
+ ```
-# Create a persistent volume (1GB is usually enough)
-fly volumes create openclaw_data --size 1 --region iad
-```
+ **Tip:** Choose a region close to you. Common options: `lhr` (London), `iad` (Virginia), `sjc` (San Jose).
-**Tip:** Choose a region close to you. Common options: `lhr` (London), `iad` (Virginia), `sjc` (San Jose).
+
-## 2) Configure fly.toml
+
+ Edit `fly.toml` to match your app name and requirements.
-Edit `fly.toml` to match your app name and requirements.
+ **Security note:** The default config exposes a public URL. For a hardened deployment with no public IP, see [Private Deployment](#private-deployment-hardened) or use `fly.private.toml`.
-**Security note:** The default config exposes a public URL. For a hardened deployment with no public IP, see [Private Deployment](#private-deployment-hardened) or use `fly.private.toml`.
+ ```toml
+ app = "my-openclaw" # Your app name
+ primary_region = "iad"
-```toml
-app = "my-openclaw" # Your app name
-primary_region = "iad"
+ [build]
+ dockerfile = "Dockerfile"
-[build]
- dockerfile = "Dockerfile"
+ [env]
+ NODE_ENV = "production"
+ OPENCLAW_PREFER_PNPM = "1"
+ OPENCLAW_STATE_DIR = "/data"
+ NODE_OPTIONS = "--max-old-space-size=1536"
-[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"
-[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"]
-[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"
-[[vm]]
- size = "shared-cpu-2x"
- memory = "2048mb"
+ [mounts]
+ source = "openclaw_data"
+ destination = "/data"
+ ```
-[mounts]
- source = "openclaw_data"
- destination = "/data"
-```
+ **Key settings:**
-**Key settings:**
+ | Setting | Why |
+ | ------------------------------ | --------------------------------------------------------------------------- |
+ | `--bind lan` | Binds to `0.0.0.0` so Fly's proxy can reach the gateway |
+ | `--allow-unconfigured` | Starts without a config file (you'll create one after) |
+ | `internal_port = 3000` | Must match `--port 3000` (or `OPENCLAW_GATEWAY_PORT`) for Fly health checks |
+ | `memory = "2048mb"` | 512MB is too small; 2GB recommended |
+ | `OPENCLAW_STATE_DIR = "/data"` | Persists state on the volume |
-| Setting | Why |
-| ------------------------------ | --------------------------------------------------------------------------- |
-| `--bind lan` | Binds to `0.0.0.0` so Fly's proxy can reach the gateway |
-| `--allow-unconfigured` | Starts without a config file (you'll create one after) |
-| `internal_port = 3000` | Must match `--port 3000` (or `OPENCLAW_GATEWAY_PORT`) for Fly health checks |
-| `memory = "2048mb"` | 512MB is too small; 2GB recommended |
-| `OPENCLAW_STATE_DIR = "/data"` | Persists state on the volume |
+
-## 3) Set secrets
+
+ ```bash
+ # Required: Gateway token (for non-loopback binding)
+ fly secrets set OPENCLAW_GATEWAY_TOKEN=$(openssl rand -hex 32)
-```bash
-# Required: Gateway token (for non-loopback binding)
-fly secrets set OPENCLAW_GATEWAY_TOKEN=$(openssl rand -hex 32)
+ # Model provider API keys
+ fly secrets set ANTHROPIC_API_KEY=sk-ant-...
-# Model provider API keys
-fly secrets set ANTHROPIC_API_KEY=sk-ant-...
+ # Optional: Other providers
+ fly secrets set OPENAI_API_KEY=sk-...
+ fly secrets set GOOGLE_API_KEY=...
-# Optional: Other providers
-fly secrets set OPENAI_API_KEY=sk-...
-fly secrets set GOOGLE_API_KEY=...
+ # Channel tokens
+ fly secrets set DISCORD_BOT_TOKEN=MTQ...
+ ```
-# Channel tokens
-fly secrets set DISCORD_BOT_TOKEN=MTQ...
-```
+ **Notes:**
-**Notes:**
+ - Non-loopback binds (`--bind lan`) require `OPENCLAW_GATEWAY_TOKEN` for security.
+ - Treat these tokens like passwords.
+ - **Prefer env vars over config file** for all API keys and tokens. This keeps secrets out of `openclaw.json` where they could be accidentally exposed or logged.
-- Non-loopback binds (`--bind lan`) require `OPENCLAW_GATEWAY_TOKEN` for security.
-- Treat these tokens like passwords.
-- **Prefer env vars over config file** for all API keys and tokens. This keeps secrets out of `openclaw.json` where they could be accidentally exposed or logged.
+
-## 4) Deploy
+
+ ```bash
+ fly deploy
+ ```
-```bash
-fly deploy
-```
+ First deploy builds the Docker image (~2-3 minutes). Subsequent deploys are faster.
-First deploy builds the Docker image (~2-3 minutes). Subsequent deploys are faster.
+ After deployment, verify:
-After deployment, verify:
+ ```bash
+ fly status
+ fly logs
+ ```
-```bash
-fly status
-fly logs
-```
+ You should see:
-You should see:
+ ```
+ [gateway] listening on ws://0.0.0.0:3000 (PID xxx)
+ [discord] logged in to discord as xxx
+ ```
-```
-[gateway] listening on ws://0.0.0.0:3000 (PID xxx)
-[discord] logged in to discord as xxx
-```
+
-## 5) Create config file
+
+ SSH into the machine to create a proper config:
-SSH into the machine to create a proper config:
+ ```bash
+ fly ssh console
+ ```
-```bash
-fly ssh console
-```
+ Create the config directory and file:
-Create the config directory and file:
-
-```bash
-mkdir -p /data
-cat > /data/openclaw.json << 'EOF'
-{
- "agents": {
- "defaults": {
- "model": {
- "primary": "anthropic/claude-opus-4-6",
- "fallbacks": ["anthropic/claude-sonnet-4-6", "openai/gpt-4o"]
- },
- "maxConcurrent": 4
- },
- "list": [
- {
- "id": "main",
- "default": true
- }
- ]
- },
- "auth": {
- "profiles": {
- "anthropic:default": { "mode": "token", "provider": "anthropic" },
- "openai:default": { "mode": "token", "provider": "openai" }
- }
- },
- "bindings": [
+ ```bash
+ mkdir -p /data
+ cat > /data/openclaw.json << 'EOF'
{
- "agentId": "main",
- "match": { "channel": "discord" }
- }
- ],
- "channels": {
- "discord": {
- "enabled": true,
- "groupPolicy": "allowlist",
- "guilds": {
- "YOUR_GUILD_ID": {
- "channels": { "general": { "allow": true } },
- "requireMention": false
+ "agents": {
+ "defaults": {
+ "model": {
+ "primary": "anthropic/claude-opus-4-6",
+ "fallbacks": ["anthropic/claude-sonnet-4-6", "openai/gpt-4o"]
+ },
+ "maxConcurrent": 4
+ },
+ "list": [
+ {
+ "id": "main",
+ "default": true
+ }
+ ]
+ },
+ "auth": {
+ "profiles": {
+ "anthropic:default": { "mode": "token", "provider": "anthropic" },
+ "openai:default": { "mode": "token", "provider": "openai" }
}
- }
+ },
+ "bindings": [
+ {
+ "agentId": "main",
+ "match": { "channel": "discord" }
+ }
+ ],
+ "channels": {
+ "discord": {
+ "enabled": true,
+ "groupPolicy": "allowlist",
+ "guilds": {
+ "YOUR_GUILD_ID": {
+ "channels": { "general": { "allow": true } },
+ "requireMention": false
+ }
+ }
+ }
+ },
+ "gateway": {
+ "mode": "local",
+ "bind": "auto"
+ },
+ "meta": {}
}
- },
- "gateway": {
- "mode": "local",
- "bind": "auto"
- },
- "meta": {}
-}
-EOF
-```
+ EOF
+ ```
-**Note:** With `OPENCLAW_STATE_DIR=/data`, the config path is `/data/openclaw.json`.
+ **Note:** With `OPENCLAW_STATE_DIR=/data`, the config path is `/data/openclaw.json`.
-**Note:** The Discord token can come from either:
+ **Note:** The Discord token can come from either:
-- Environment variable: `DISCORD_BOT_TOKEN` (recommended for secrets)
-- Config file: `channels.discord.token`
+ - Environment variable: `DISCORD_BOT_TOKEN` (recommended for secrets)
+ - Config file: `channels.discord.token`
-If using env var, no need to add token to config. The gateway reads `DISCORD_BOT_TOKEN` automatically.
+ If using env var, no need to add token to config. The gateway reads `DISCORD_BOT_TOKEN` automatically.
-Restart to apply:
+ Restart to apply:
-```bash
-exit
-fly machine restart
-```
+ ```bash
+ exit
+ fly machine restart
+ ```
-## 6) Access the Gateway
+
-### Control UI
+
+ ### Control UI
-Open in browser:
+ Open in browser:
-```bash
-fly open
-```
+ ```bash
+ fly open
+ ```
-Or visit `https://my-openclaw.fly.dev/`
+ Or visit `https://my-openclaw.fly.dev/`
-Paste your gateway token (the one from `OPENCLAW_GATEWAY_TOKEN`) to authenticate.
+ Paste your gateway token (the one from `OPENCLAW_GATEWAY_TOKEN`) to authenticate.
-### Logs
+ ### Logs
-```bash
-fly logs # Live logs
-fly logs --no-tail # Recent logs
-```
+ ```bash
+ fly logs # Live logs
+ fly logs --no-tail # Recent logs
+ ```
-### SSH Console
+ ### SSH Console
-```bash
-fly ssh console
-```
+ ```bash
+ fly ssh console
+ ```
+
+
+
## Troubleshooting
diff --git a/docs/install/gcp.md b/docs/install/gcp.md
index e997aed1cb1..3714d9bcb1b 100644
--- a/docs/install/gcp.md
+++ b/docs/install/gcp.md
@@ -65,277 +65,271 @@ For the generic Docker flow, see [Docker](/install/docker).
---
-## 1) Install gcloud CLI (or use Console)
+
+
+ **Option A: gcloud CLI** (recommended for automation)
-**Option A: gcloud CLI** (recommended for automation)
+ Install from [https://cloud.google.com/sdk/docs/install](https://cloud.google.com/sdk/docs/install)
-Install from [https://cloud.google.com/sdk/docs/install](https://cloud.google.com/sdk/docs/install)
+ Initialize and authenticate:
-Initialize and authenticate:
+ ```bash
+ gcloud init
+ gcloud auth login
+ ```
-```bash
-gcloud init
-gcloud auth login
-```
+ **Option B: Cloud Console**
-**Option B: Cloud Console**
+ All steps can be done via the web UI at [https://console.cloud.google.com](https://console.cloud.google.com)
-All steps can be done via the web UI at [https://console.cloud.google.com](https://console.cloud.google.com)
+
----
+
+ **CLI:**
-## 2) Create a GCP project
+ ```bash
+ gcloud projects create my-openclaw-project --name="OpenClaw Gateway"
+ gcloud config set project my-openclaw-project
+ ```
-**CLI:**
+ Enable billing at [https://console.cloud.google.com/billing](https://console.cloud.google.com/billing) (required for Compute Engine).
-```bash
-gcloud projects create my-openclaw-project --name="OpenClaw Gateway"
-gcloud config set project my-openclaw-project
-```
+ Enable the Compute Engine API:
-Enable billing at [https://console.cloud.google.com/billing](https://console.cloud.google.com/billing) (required for Compute Engine).
+ ```bash
+ gcloud services enable compute.googleapis.com
+ ```
-Enable the Compute Engine API:
+ **Console:**
-```bash
-gcloud services enable compute.googleapis.com
-```
+ 1. Go to IAM & Admin > Create Project
+ 2. Name it and create
+ 3. Enable billing for the project
+ 4. Navigate to APIs & Services > Enable APIs > search "Compute Engine API" > Enable
-**Console:**
+
-1. Go to IAM & Admin > Create Project
-2. Name it and create
-3. Enable billing for the project
-4. Navigate to APIs & Services > Enable APIs > search "Compute Engine API" > Enable
+
+ **Machine types:**
----
+ | Type | Specs | Cost | Notes |
+ | --------- | ------------------------ | ------------------ | -------------------------------------------- |
+ | e2-medium | 2 vCPU, 4GB RAM | ~$25/mo | Most reliable for local Docker builds |
+ | e2-small | 2 vCPU, 2GB RAM | ~$12/mo | Minimum recommended for Docker build |
+ | e2-micro | 2 vCPU (shared), 1GB RAM | Free tier eligible | Often fails with Docker build OOM (exit 137) |
-## 3) Create the VM
+ **CLI:**
-**Machine types:**
+ ```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
+ ```
-| Type | Specs | Cost | Notes |
-| --------- | ------------------------ | ------------------ | -------------------------------------------- |
-| e2-medium | 2 vCPU, 4GB RAM | ~$25/mo | Most reliable for local Docker builds |
-| e2-small | 2 vCPU, 2GB RAM | ~$12/mo | Minimum recommended for Docker build |
-| e2-micro | 2 vCPU (shared), 1GB RAM | Free tier eligible | Often fails with Docker build OOM (exit 137) |
+ **Console:**
-**CLI:**
+ 1. Go to Compute Engine > VM instances > Create instance
+ 2. Name: `openclaw-gateway`
+ 3. Region: `us-central1`, Zone: `us-central1-a`
+ 4. Machine type: `e2-small`
+ 5. Boot disk: Debian 12, 20GB
+ 6. Create
-```bash
-gcloud compute instances create openclaw-gateway \
- --zone=us-central1-a \
- --machine-type=e2-small \
- --boot-disk-size=20GB \
- --image-family=debian-12 \
- --image-project=debian-cloud
-```
+
-**Console:**
+
+ **CLI:**
-1. Go to Compute Engine > VM instances > Create instance
-2. Name: `openclaw-gateway`
-3. Region: `us-central1`, Zone: `us-central1-a`
-4. Machine type: `e2-small`
-5. Boot disk: Debian 12, 20GB
-6. Create
+ ```bash
+ gcloud compute ssh openclaw-gateway --zone=us-central1-a
+ ```
----
+ **Console:**
-## 4) SSH into the VM
+ Click the "SSH" button next to your VM in the Compute Engine dashboard.
-**CLI:**
+ Note: SSH key propagation can take 1-2 minutes after VM creation. If connection is refused, wait and retry.
-```bash
-gcloud compute ssh openclaw-gateway --zone=us-central1-a
-```
+
-**Console:**
+
+ ```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
+ ```
-Click the "SSH" button next to your VM in the Compute Engine dashboard.
+ Log out and back in for the group change to take effect:
-Note: SSH key propagation can take 1-2 minutes after VM creation. If connection is refused, wait and retry.
+ ```bash
+ exit
+ ```
----
+ Then SSH back in:
-## 5) Install Docker (on the VM)
+ ```bash
+ gcloud compute ssh openclaw-gateway --zone=us-central1-a
+ ```
-```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
-```
+ Verify:
-Log out and back in for the group change to take effect:
+ ```bash
+ docker --version
+ docker compose version
+ ```
-```bash
-exit
-```
+
-Then SSH back in:
+
+ ```bash
+ git clone https://github.com/openclaw/openclaw.git
+ cd openclaw
+ ```
-```bash
-gcloud compute ssh openclaw-gateway --zone=us-central1-a
-```
+ This guide assumes you will build a custom image to guarantee binary persistence.
-Verify:
+
-```bash
-docker --version
-docker compose version
-```
+
+ Docker containers are ephemeral.
+ All long-lived state must live on the host.
----
+ ```bash
+ mkdir -p ~/.openclaw
+ mkdir -p ~/.openclaw/workspace
+ ```
-## 6) Clone the OpenClaw repository
+
-```bash
-git clone https://github.com/openclaw/openclaw.git
-cd openclaw
-```
+
+ Create `.env` in the repository root.
-This guide assumes you will build a custom image to guarantee binary persistence.
+ ```bash
+ OPENCLAW_IMAGE=openclaw:latest
+ OPENCLAW_GATEWAY_TOKEN=change-me-now
+ OPENCLAW_GATEWAY_BIND=lan
+ OPENCLAW_GATEWAY_PORT=18789
----
+ OPENCLAW_CONFIG_DIR=/home/$USER/.openclaw
+ OPENCLAW_WORKSPACE_DIR=/home/$USER/.openclaw/workspace
-## 7) Create persistent host directories
+ GOG_KEYRING_PASSWORD=change-me-now
+ XDG_CONFIG_HOME=/home/node/.openclaw
+ ```
-Docker containers are ephemeral.
-All long-lived state must live on the host.
+ Generate strong secrets:
-```bash
-mkdir -p ~/.openclaw
-mkdir -p ~/.openclaw/workspace
-```
+ ```bash
+ openssl rand -hex 32
+ ```
----
+ **Do not commit this file.**
-## 8) Configure environment variables
+
-Create `.env` in the repository root.
+
+ Create or update `docker-compose.yml`.
-```bash
-OPENCLAW_IMAGE=openclaw:latest
-OPENCLAW_GATEWAY_TOKEN=change-me-now
-OPENCLAW_GATEWAY_BIND=lan
-OPENCLAW_GATEWAY_PORT=18789
+ ```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",
+ ]
+ ```
-OPENCLAW_CONFIG_DIR=/home/$USER/.openclaw
-OPENCLAW_WORKSPACE_DIR=/home/$USER/.openclaw/workspace
+ `--allow-unconfigured` is only for bootstrap convenience, it is not a replacement for a proper gateway configuration. Still set auth (`gateway.auth.token` or password) and use safe bind settings for your deployment.
-GOG_KEYRING_PASSWORD=change-me-now
-XDG_CONFIG_HOME=/home/node/.openclaw
-```
+
-Generate strong secrets:
+
+ Use the shared runtime guide for the common Docker host flow:
-```bash
-openssl rand -hex 32
-```
+ - [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)
-**Do not commit this file.**
+
----
+
+ On GCP, if build fails with `Killed` or `exit code 137` during `pnpm install --frozen-lockfile`, the VM is out of memory. Use `e2-small` minimum, or `e2-medium` for more reliable first builds.
-## 9) Docker Compose configuration
+ When binding to LAN (`OPENCLAW_GATEWAY_BIND=lan`), configure a trusted browser origin before continuing:
-Create or update `docker-compose.yml`.
+ ```bash
+ docker compose run --rm openclaw-cli config set gateway.controlUi.allowedOrigins '["http://127.0.0.1:18789"]' --strict-json
+ ```
+
+ If you changed the gateway port, replace `18789` with your configured port.
-```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",
- ]
-```
+
+
+
+ Create an SSH tunnel to forward the Gateway port:
-`--allow-unconfigured` is only for bootstrap convenience, it is not a replacement for a proper gateway configuration. Still set auth (`gateway.auth.token` or password) and use safe bind settings for your deployment.
+ ```bash
+ gcloud compute ssh openclaw-gateway --zone=us-central1-a -- -L 18789:127.0.0.1:18789
+ ```
+
+ Open in your browser:
----
+ `http://127.0.0.1:18789/`
+
+ Fetch a fresh tokenized dashboard link:
-## 10) Shared Docker VM runtime steps
+ ```bash
+ docker compose run --rm openclaw-cli dashboard --no-open
+ ```
-Use the shared runtime guide for the common Docker host flow:
+ Paste the token from that URL.
+
+ If Control UI shows `unauthorized` or `disconnected (1008): pairing required`, approve the browser device:
-- [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)
-
----
-
-## 11) GCP-specific launch notes
-
-On GCP, if build fails with `Killed` or `exit code 137` during `pnpm install --frozen-lockfile`, the VM is out of memory. Use `e2-small` minimum, or `e2-medium` for more reliable first builds.
-
-When binding to LAN (`OPENCLAW_GATEWAY_BIND=lan`), configure a trusted browser origin before continuing:
-
-```bash
-docker compose run --rm openclaw-cli config set gateway.controlUi.allowedOrigins '["http://127.0.0.1:18789"]' --strict-json
-```
-
-If you changed the gateway port, replace `18789` with your configured port.
-
-## 12) Access from your laptop
-
-Create an SSH tunnel to forward the Gateway port:
-
-```bash
-gcloud compute ssh openclaw-gateway --zone=us-central1-a -- -L 18789:127.0.0.1:18789
-```
-
-Open in your browser:
-
-`http://127.0.0.1:18789/`
-
-Fetch a fresh tokenized dashboard link:
-
-```bash
-docker compose run --rm openclaw-cli dashboard --no-open
-```
-
-Paste the token from that URL.
-
-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
-```
-
-Need the shared persistence and update reference again?
-See [Docker VM Runtime](/install/docker-vm-runtime#what-persists-where) and [Docker VM Runtime updates](/install/docker-vm-runtime#updates).
+ ```bash
+ docker compose run --rm openclaw-cli devices list
+ docker compose run --rm openclaw-cli devices approve
+ ```
+
+ Need the shared persistence and update reference again?
+ See [Docker VM Runtime](/install/docker-vm-runtime#what-persists-where) and [Docker VM Runtime updates](/install/docker-vm-runtime#updates).
+
+
+
---
diff --git a/docs/install/hetzner.md b/docs/install/hetzner.md
index 906ac7969a4..b123b3d92f6 100644
--- a/docs/install/hetzner.md
+++ b/docs/install/hetzner.md
@@ -72,162 +72,156 @@ For the generic Docker flow, see [Docker](/install/docker).
---
-## 1) Provision the VPS
+
+
+ Create an Ubuntu or Debian VPS in Hetzner.
-Create an Ubuntu or Debian VPS in Hetzner.
+ Connect as root:
-Connect as root:
+ ```bash
+ ssh root@YOUR_VPS_IP
+ ```
-```bash
-ssh root@YOUR_VPS_IP
-```
+ This guide assumes the VPS is stateful.
+ Do not treat it as disposable infrastructure.
-This guide assumes the VPS is stateful.
-Do not treat it as disposable infrastructure.
+
----
+
+ ```bash
+ apt-get update
+ apt-get install -y git curl ca-certificates
+ curl -fsSL https://get.docker.com | sh
+ ```
-## 2) Install Docker (on the VPS)
+ Verify:
-```bash
-apt-get update
-apt-get install -y git curl ca-certificates
-curl -fsSL https://get.docker.com | sh
-```
+ ```bash
+ docker --version
+ docker compose version
+ ```
-Verify:
+
-```bash
-docker --version
-docker compose version
-```
+
+ ```bash
+ git clone https://github.com/openclaw/openclaw.git
+ cd openclaw
+ ```
----
+ This guide assumes you will build a custom image to guarantee binary persistence.
-## 3) Clone the OpenClaw repository
+
-```bash
-git clone https://github.com/openclaw/openclaw.git
-cd openclaw
-```
+
+ Docker containers are ephemeral.
+ All long-lived state must live on the host.
-This guide assumes you will build a custom image to guarantee binary persistence.
+ ```bash
+ mkdir -p /root/.openclaw/workspace
----
+ # Set ownership to the container user (uid 1000):
+ chown -R 1000:1000 /root/.openclaw
+ ```
-## 4) Create persistent host directories
+
-Docker containers are ephemeral.
-All long-lived state must live on the host.
+
+ Create `.env` in the repository root.
-```bash
-mkdir -p /root/.openclaw/workspace
+ ```bash
+ OPENCLAW_IMAGE=openclaw:latest
+ OPENCLAW_GATEWAY_TOKEN=change-me-now
+ OPENCLAW_GATEWAY_BIND=lan
+ OPENCLAW_GATEWAY_PORT=18789
-# Set ownership to the container user (uid 1000):
-chown -R 1000:1000 /root/.openclaw
-```
+ OPENCLAW_CONFIG_DIR=/root/.openclaw
+ OPENCLAW_WORKSPACE_DIR=/root/.openclaw/workspace
----
+ GOG_KEYRING_PASSWORD=change-me-now
+ XDG_CONFIG_HOME=/home/node/.openclaw
+ ```
-## 5) Configure environment variables
+ Generate strong secrets:
-Create `.env` in the repository root.
+ ```bash
+ openssl rand -hex 32
+ ```
-```bash
-OPENCLAW_IMAGE=openclaw:latest
-OPENCLAW_GATEWAY_TOKEN=change-me-now
-OPENCLAW_GATEWAY_BIND=lan
-OPENCLAW_GATEWAY_PORT=18789
+ **Do not commit this file.**
-OPENCLAW_CONFIG_DIR=/root/.openclaw
-OPENCLAW_WORKSPACE_DIR=/root/.openclaw/workspace
+
-GOG_KEYRING_PASSWORD=change-me-now
-XDG_CONFIG_HOME=/home/node/.openclaw
-```
+
+ Create or update `docker-compose.yml`.
-Generate strong secrets:
+ ```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",
+ ]
+ ```
-```bash
-openssl rand -hex 32
-```
+ `--allow-unconfigured` is only for bootstrap convenience, it is not a replacement for a proper gateway configuration. Still set auth (`gateway.auth.token` or password) and use safe bind settings for your deployment.
-**Do not commit this file.**
+
----
+
+ Use the shared runtime guide for the common Docker host flow:
-## 6) Docker Compose configuration
+ - [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)
-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",
- ]
-```
+
+ After the shared build and launch steps, tunnel from your laptop:
-`--allow-unconfigured` is only for bootstrap convenience, it is not a replacement for a proper gateway configuration. Still set auth (`gateway.auth.token` or password) and use safe bind settings for your deployment.
+ ```bash
+ ssh -N -L 18789:127.0.0.1:18789 root@YOUR_VPS_IP
+ ```
----
+ Open:
-## 7) Shared Docker VM runtime steps
+ `http://127.0.0.1:18789/`
-Use the shared runtime guide for the common Docker host flow:
+ Paste your gateway token.
-- [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)
-
----
-
-## 8) Hetzner-specific access
-
-After the shared build and launch steps, tunnel from your laptop:
-
-```bash
-ssh -N -L 18789:127.0.0.1:18789 root@YOUR_VPS_IP
-```
-
-Open:
-
-`http://127.0.0.1:18789/`
-
-Paste your gateway token.
-
----
+
+
The shared persistence map lives in [Docker VM Runtime](/install/docker-vm-runtime#what-persists-where).