--- name: openclaw-deploy version: 1.7.0 description: Deploy OpenClaw personal AI assistant on a Debian LXC in the BNNA cluster tags: [openclaw, ai, assistant, bnna, deploy, node, systemd, ollama, discord] --- **Security pattern:** For production, create an `app` user and run OpenClaw as that user. For dev instances, running as root is simpler. **Model rule:** Only use models from your configured provider. For Ollama Cloud, list available models with: ```sh curl -sS -H "Authorization: Bearer $OLLAMA_API_KEY" https://ollama.com/api/tags | jq '.models[].name' ``` # Deploy OpenClaw OpenClaw is a personal AI assistant you run on your own devices. This skill covers deployment on a Debian LXC behind the BNNA TLS router. **Official repo:** `https://github.com/openclaw/openclaw` **npm package:** `openclaw@latest` (or pin to specific version like `2026.4.1`) **Template:** Use Debian 13 (trixie), NOT Alpine. OpenClaw requires glibc for some dependencies. ## Quick Deploy (npm - recommended) ```sh # 1. Create container (use bnna API, NOT Proxmox passthrough) BNNA_HOST="https://tls-10-11-8-205.vms.coolaj86.com" AUTH="Authorization: Bearer " SSH_KEYS=$(curl -sSL "https://keys.coolaj86.com" | grep -E '^(ssh|ecdsa)-[a-zA-Z0-9-]+ AAA') curl -sSL -X POST -H "$AUTH" "$BNNA_HOST/api/nodes/pve1/lxc" \ --data-urlencode "vmid=1108202" \ --data-urlencode "hostname=openclaw-tron-dev" \ --data-urlencode "ostemplate=slc1-smb1-shared:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst" \ --data-urlencode "pool=aj-dev" \ --data-urlencode "cores=4" \ --data-urlencode "memory=8192" \ --data-urlencode "rootfs=zpool-lab-slc1-aj:32" \ --data-urlencode "net0=name=eth0,bridge=aj,ip=10.11.8.202/24,gw=10.11.8.1" \ --data-urlencode "ssh-public-keys=$SSH_KEYS" \ --data-urlencode "unprivileged=1" \ --data-urlencode "start=1" # 2. Wait for provisioning (1-2 min), then SSH (Debian standard uses root) ssh-keygen -R tls-10-11-8-202.a.bnna.net ssh root@tls-10-11-8-202.a.bnna.net # 3. Install dependencies (as root for dev, or create app user for production) apt-get update && apt-get install -y curl git unzip curl -sS https://webi.sh | sh source ~/.config/envman/PATH.env webi node@lts jq # 4. Install OpenClaw (npm, pinned version) npm install -g openclaw@2026.4.1 openclaw --version # 5. Configure gateway openclaw config set gateway.mode local openclaw config set gateway.bind lan openclaw config set gateway.port 3080 openclaw config set gateway.auth.token # 6. Set up Ollama Cloud (API key in .env for daemon access) echo 'OLLAMA_API_KEY=your-api-key' >> ~/.openclaw/.env # 7. Create systemd service webi serviceman ~/.local/bin/serviceman add --name openclaw --workdir ~/.openclaw --user root -- ~/.local/opt/node/bin/node $(which openclaw) gateway run --port 3080 --bind lan # 8. Enable and start systemctl daemon-reload systemctl enable openclaw systemctl start openclaw # 9. Verify curl https://tls-10-11-8-202.a.bnna.net/healthz ``` ## Quick Deploy (from source - for development) For dev instances where you want the full source available: ```sh # 1-3. Same as above (create container, install dependencies) # 4. Clone OpenClaw repo with version picker mkdir -p ~/openclaw && cd ~/openclaw git clone --depth 1 --branch main https://github.com/openclaw/openclaw.git . git fetch origin refs/tags/v2026.4.1:refs/tags/v2026.4.1 --depth 1 git checkout v2026.4.1 # 5. Install dependencies and build curl -sS https://webi.sh | sh source ~/.config/envman/PATH.env webi node@lts pnpm pnpm install && pnpm build # 6. Create run script cat > ~/openclaw/run-gateway.sh << 'EOF' #!/bin/bash source ~/.config/envman/PATH.env cd ~/openclaw export PORT=3080 exec ~/.local/opt/node/bin/node ~/openclaw/openclaw.mjs gateway run --port 3080 --bind lan EOF chmod +x ~/openclaw/run-gateway.sh # 7. Set up systemd webi serviceman ~/.local/bin/serviceman add --name openclaw --workdir /root/openclaw --user root -- ~/openclaw/run-gateway.sh # 8. Enable and start systemctl daemon-reload systemctl enable openclaw systemctl start openclaw ``` ## Configuration (both methods) After deploying with either method, configure: ### Essential Config ```sh # Gateway auth openclaw config set gateway.auth.token $(openssl rand -hex 16) # CORS for Control UI (add your domain) openclaw config set gateway.controlUi.allowedOrigins '["http://localhost:3080","https://your-domain.com"]' ``` ### Ollama Cloud See [Model Provider Setup](#model-provider-setup) for full details. Quick start: ```sh echo 'OLLAMA_API_KEY=your-api-key' >> ~/.openclaw/.env openclaw config set models.providers.ollama.baseUrl "https://ollama.com" systemctl restart openclaw ``` ### Discord See [Discord Setup](#discord-setup) for full details. Quick start: ```sh echo 'DISCORD_BOT_TOKEN=your-bot-token' >> ~/.openclaw/.env openclaw config set channels.discord.enabled true --strict-json systemctl restart openclaw ``` ## Container Requirements | Resource | Minimum | Recommended | |----------|---------|-------------| | CPU | 2 cores | 4+ cores | | RAM | 4 GB | 8+ GB | | Disk | 4 GB | 8+ GB | Note: npm install is smaller than git clone + build (~500MB vs ~2GB). ## BNNA TLS Router - **Port 3080** — OpenClaw gateway listens here, TLS router terminates HTTPS - Access externally at `https://tls-10-11-8-202.a.bnna.net` (replace IP with container IP) ## Node.js Version - **Node 24** (recommended) or **Node 22.16+** required - Install via webi: `webi node@lts` or `webi node@24` ## Version Pinning Always pin to a specific version for reproducible deployments. For supply chain security, choose a version at least 2 weeks old: ```sh # List versions with release dates npm view openclaw versions --json | jq -r '.[]' | while read v; do date=$(npm view "openclaw@$v" time.created 2>/dev/null | cut -d'T' -f1) echo "$v: $date" done # Recommended: use version 2+ weeks old for supply chain safety # v2026.3.13-1 (March 14) is ~18 days old as of April 1 ``` **Git clone with tag (for source + inspection):** ```sh # Clone main (shallow), then fetch specific tag git clone --depth 1 --branch main https://github.com/openclaw/openclaw.git cd openclaw git fetch origin refs/tags/v2026.3.13-1:refs/tags/v2026.3.13-1 --depth 1 git checkout v2026.3.13-1 pnpm install && pnpm build ``` **Version picker script:** `scripts/openclaw-version-picker.sh` - Set `MIN_AGE_DAYS=14` to pick versions >= 14 days old - Automatically selects latest stable version meeting age requirement ## Authentication (Token vs Password) OpenClaw supports two auth modes for the gateway: | Mode | Config | Use case | |------|--------|----------| | **Token** | `gateway.auth.token` | Recommended. Auto-generated token, simple to use. | | **Password** | `gateway.auth.password` | Alternative. Simpler for some setups. | ```sh # Token auth (recommended) openclaw config set gateway.auth.token $(openssl rand -hex 16) # Password auth (alternative) openclaw config set gateway.auth.password "your-secure-password" ``` ## Dashboard (Control UI) Access the Control UI at the gateway URL: ``` https://tls-10-11-8-202.a.bnna.net/ ``` 1. Open the URL in your browser 2. Paste the token (or password) into the auth field 3. You're now connected to the gateway **Get the token:** ```sh # From the container cat ~/.openclaw/openclaw.json | grep token # or openclaw config get gateway.auth.token # Shows __OPENCLAW_REDACTED__ ``` ## Pairing a Device When you first connect, the device needs to be approved: **Flow:** 1. First connection → "gateway token missing" → paste token in Control UI settings 2. Second connection → "pairing required" → approve device on gateway host ```sh # List pending devices (on gateway host) openclaw devices list # Approve a device openclaw devices approve ``` **For CORS (external origins):** ```sh # Add allowed origin for external domain openclaw config set gateway.controlUi.allowedOrigins '["http://localhost:3080","http://127.0.0.1:3080","https://your-domain.com"]' systemctl restart openclaw ``` ## Model Provider Setup For Ollama Cloud with BNNA: ```sh # Set Ollama Cloud endpoint openclaw config set models.providers.ollama.baseUrl "https://ollama.com" # API key goes in .env (not config) for daemon access echo 'OLLAMA_API_KEY=your-api-key' >> ~/.openclaw/.env # Define models (no :cloud suffix for direct API) openclaw config set models.providers.ollama.models '[{"id":"glm-4.7","name":"GLM-4.7","contextWindow":131072},{"id":"glm-5","name":"GLM-5","contextWindow":131072}]' # Set primary and fallback openclaw config set agents.defaults.model.primary "ollama/glm-4.7" openclaw config set agents.defaults.model.fallbacks '["ollama/glm-5"]' # Restart to load env systemctl restart openclaw ``` **Recommended BNNA model stack:** | Model | Role | Why | |-------|------|-----| | `glm-4.7` | Primary | Fast, lightweight (30B-class) | | `gpt-oss:20b` | Fallback | Good coding model, 8K context | | `minimax-m2.7` | Optional | Strongest coding/agentic (200K context) | | `kimi-k2.5` | Optional | Multimodal reasoning with subagents | | `glm-5` | Optional | Powerful reasoning, for coding tasks | **Note:** Ollama Cloud API uses model names WITHOUT `:cloud` suffix. The `:cloud` suffix is only for local Ollama CLI to route to cloud instead of pulling locally. ## Listing Available Models **IMPORTANT:** Always use models from your configured provider only. For Ollama Cloud, list available models: ```sh # List all available models from Ollama Cloud API curl -sS -H "Authorization: Bearer $OLLAMA_API_KEY" https://ollama.com/api/tags | jq '.models[].name' # On the gateway host (if OLLAMA_API_KEY is in .env) source ~/.openclaw/.env curl -sS -H "Authorization: Bearer $OLLAMA_API_KEY" https://ollama.com/api/tags | jq '.models[].name' ``` **Rule:** Only configure models that exist in your provider's API response. Do NOT add models from other providers (Claude, OpenAI, etc.) without their API keys configured. **Ollama Cloud pricing** (all models included, no per-token fees): | Tier | Price | Concurrent | Usage | Reset | |------|-------|------------|-------|-------| | Free | $0/mo | 1 model | baseline | 5h sessions, 7d weekly | | Pro | $20/mo | 3 models | 50x Free | same | | Max | $100/mo | 10 models | 250x Free | same | Usage measured in GPU time, not tokens. All models included at no extra cost. See: https://ollama.com/cloud ## Model Cost Reference (from OpenCode Zen pricing) Prices per 1M tokens. Use relative cost to pick the right model for the task. ### Free (testing) | Model | Input | Output | Cached Read | |-------|-------|--------|-------------| | Big Pickle | Free | Free | Free | | MiMo V2 Pro Free | Free | Free | Free | | MiMo V2 Omni Free | Free | Free | Free | | Qwen3.6 Plus Free | Free | Free | Free | | Nematron 3 Super Free | Free | Free | Free | | MiniMax M2.5 Free | Free | Free | Free | ### $0.30-$1.00 (everyday use) | Model | Input | Output | Cached Read | Notes | |-------|-------|--------|-------------|-------| | MiniMax M2.5 | $0.30 | $1.20 | $0.06 | **Best value** - fast, strong coding | | Qwen3 Coder 480B | $0.45 | $1.50 | - | Large coding model | | Kimi K2.5 | $0.60 | $3.00 | $0.10 | Multimodal, subagents | | GLM 5 | $1.00 | $3.20 | $0.20 | Reasoning, multimodal | | Claude Haiku 4.5 | $1.00 | $5.00 | $0.10 | Fast, lightweight | ### $3.00 (balanced) | Model | Input | Output | Cached Read | Notes | |-------|-------|--------|-------------|-------| | Claude Sonnet 4.6 | $3.00 | $15.00 | $0.30 | Large context, balanced | ### $5.00+ (reasoning) | Model | Input | Output | Cached Read | Notes | |-------|-------|--------|-------------|-------| | Claude Opus 4.6 | $5.00 | $25.00 | $0.50 | Top reasoning | **Recommended BNNA stack**: MiniMax M2.5 as primary (best value), Kimi K2.5 for multimodal/subagents, GLM-5 for complex reasoning. Use Claude Opus sparingly for critical decisions. See: https://opencode.ai/docs/zen/#pricing ## Channels (WhatsApp, Telegram, etc.) After the gateway is running, configure channels: ```sh # List channels openclaw channels status --probe # WhatsApp (QR code) openclaw channels login # Telegram openclaw channels add --channel telegram --token "" # Discord openclaw channels add --channel discord --token "" ``` ## Discord Setup Discord provides guild channels where each channel gets its own agent session. This is ideal for organizing work by topic/branch. **Quick setup:** 1. Create bot at [Discord Developer Portal](https://discord.com/developers/applications) 2. Enable privileged intents: **Message Content**, **Server Members** 3. Copy bot token 4. Add bot to your server with OAuth URL (scopes: `bot`, `applications.commands`) 5. Enable Developer Mode in Discord → copy Server ID and your User ID **Configure on gateway:** ```sh # Set bot token (use env for security) echo 'DISCORD_BOT_TOKEN=your-bot-token' >> ~/.openclaw/.env # Configure Discord channel openclaw config set channels.discord.enabled true --strict-json openclaw config set channels.discord.groupPolicy allowlist openclaw config set channels.discord.guilds '{"YOUR_SERVER_ID":{"requireMention":false,"users":["YOUR_USER_ID"]}}' # Restart gateway systemctl restart openclaw ``` **Pair device:** ```sh # DM your bot in Discord - it will respond with a pairing code # Then on gateway: openclaw pairing approve discord ``` ## Health Checks ```sh # Liveness (no auth) curl -fsS http://127.0.0.1:3080/healthz # Readiness (no auth) curl -fsS http://127.0.0.1:3080/readyz # Deep health (auth required) openclaw health --token "$OPENCLAW_GATEWAY_TOKEN" ``` ## Testing the Model ```sh # Through gateway (uses gateway's env vars) ssh root@tls-10-11-8-202.a.bnna.net 'openclaw agent --agent main --message "hello"' # Check model status openclaw models status openclaw models list ``` **Note:** The `--local` flag runs the agent embedded in the current shell without the gateway's environment. For gateway operations, omit `--local` to route through the gateway which has access to `~/.openclaw/.env`. ## Updating ```sh # Update to latest npm install -g openclaw@latest # Or pin to specific version npm install -g openclaw@2026.4.1 # Restart service systemctl restart openclaw ``` ## Storage Paths | Path | Purpose | |------|---------| | `~/.openclaw/` | Config, credentials, sessions | | `~/.openclaw/workspace/` | Agent workspace | | `/tmp/openclaw/` | Rolling logs | **Disk growth hotspots:** media files, session JSONL files. ## Troubleshooting ### Permission errors ```sh # Ensure user owns config chown -R root:root ~/.openclaw chmod 700 ~/.openclaw ``` ### Gateway not reachable 1. Check TLS router is forwarding: `curl -v https://tls-10-11-8-202.a.bnna.net` 2. Check OpenClaw is listening: `ss -tlnp | grep 3080` 3. Check bind mode: `openclaw config get gateway.bind` ### Pairing required ```sh openclaw dashboard --no-open # Open the URL in browser, approve device openclaw devices list openclaw devices approve ``` ## Development (from source) If you need to run from source instead of npm: ```sh git clone --depth 1 --branch main https://github.com/openclaw/openclaw.git cd openclaw pnpm install pnpm build ./openclaw.mjs gateway run --port 3080 --bind lan ``` Note: `pnpm` is required for builds from source. Prefer npm install for production. ## References - [OpenClaw Docs](https://docs.openclaw.ai) - [Getting Started](https://docs.openclaw.ai/start/getting-started) - [Configuration](https://docs.openclaw.ai/gateway/configuration) - [Channels](https://docs.openclaw.ai/channels) — WhatsApp, Telegram, Discord, etc. - [Dashboard](https://docs.openclaw.ai/web/dashboard) — Control UI auth and access