Files
nuc/docs/openclaw.md
Alejandro Gutiérrez f56528ddcd Slim CLAUDE.md from 65K to 21K by splitting app-specific docs
Move OpenClaw, Palmr, MinIO, JSX publishing, MCP configs, and migration
candidates into dedicated docs/ files. Keep only DevOps-essential content
inline (deployment rules, DNS, router, credentials, troubleshooting).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 02:56:08 +00:00

7.1 KiB

OpenClaw (AI Assistant Gateway)

Self-hosted AI assistant gateway running on the NUC via Docker Compose. Connects to messaging platforms (WhatsApp, Telegram, Discord, etc.) and routes messages through Claude.

Access

Property Value
Control UI (HTTPS) https://alezmad-nuc.tail58f5ad.ts.net:8443
Gateway WS ws://192.168.1.3:18789
Gateway Token 3547c3f2b7b4a33eb077cf804bcca446057f81ba1578b2045dbb3aa4e04346ee
Model anthropic/claude-sonnet-4-5-20250929
Repo on NUC ~/openclaw/
Config ~/.openclaw/openclaw.json
Version 2026.2.10

HTTPS Required: The Control UI requires a secure context (HTTPS or localhost). Access via Tailscale Serve on port 8443.

Tailscale Serve (HTTPS access)

The gateway is exposed via Tailscale Serve (not Funnel - tailnet only, not public):

# Start HTTPS proxy (requires sudo, must run from NUC terminal)
ssh nuc
sudo tailscale serve --bg --https=8443 http://localhost:18789
# Password: 7vXHpSTD

The --bg flag makes it persistent. Without it, Ctrl+C stops the proxy.

Docker Compose Management

# Start gateway
ssh nuc "cd ~/openclaw && docker compose up -d openclaw-gateway"

# Restart gateway
ssh nuc "cd ~/openclaw && docker compose restart openclaw-gateway"

# View logs
ssh nuc "docker logs openclaw-openclaw-gateway-1 2>&1 | tail -30"

# Run CLI commands (use docker exec for commands that need gateway connection)
ssh nuc "docker exec openclaw-openclaw-gateway-1 node dist/index.js <command> --token 3547c3f2b7b4a33eb077cf804bcca446057f81ba1578b2045dbb3aa4e04346ee --url ws://127.0.0.1:18789"

# Run CLI commands that don't need gateway (use docker compose run)
ssh nuc "cd ~/openclaw && script -qc 'docker compose run --rm openclaw-cli <command>' /dev/null"

Device Pairing

When the Control UI shows "pairing required", approve the pending device:

# List pending devices
ssh nuc "docker exec openclaw-openclaw-gateway-1 node dist/index.js devices list --token 3547c3f2b7b4a33eb077cf804bcca446057f81ba1578b2045dbb3aa4e04346ee --url ws://127.0.0.1:18789"

# Approve a device (use requestId from the list)
ssh nuc "docker exec openclaw-openclaw-gateway-1 node dist/index.js devices approve <requestId> --token 3547c3f2b7b4a33eb077cf804bcca446057f81ba1578b2045dbb3aa4e04346ee --url ws://127.0.0.1:18789"

Dashboard URL with embedded token (auto-authenticates):

https://alezmad-nuc.tail58f5ad.ts.net:8443/#token=3547c3f2b7b4a33eb077cf804bcca446057f81ba1578b2045dbb3aa4e04346ee

Channel Plugins

Channels are plugins that must be enabled before use. 35 available, 4 loaded by default.

# List all plugins
ssh nuc "script -qc 'cd ~/openclaw && docker compose run --rm openclaw-cli plugins list' /dev/null"

# Enable a channel plugin
ssh nuc "script -qc 'cd ~/openclaw && docker compose run --rm openclaw-cli plugins enable <plugin-id>' /dev/null"

# Then restart gateway
ssh nuc "cd ~/openclaw && docker compose restart openclaw-gateway"

Currently enabled channels: WhatsApp (linked and active)

Available channel plugins:

Plugin ID Channel
whatsapp WhatsApp
telegram Telegram
discord Discord
slack Slack
signal Signal
matrix Matrix
msteams Microsoft Teams
googlechat Google Chat
imessage iMessage
irc IRC

Setting Up Channels That Require QR Codes (WhatsApp, etc.)

The CLI needs a TTY for QR display. Cannot run directly via ssh nuc "command". Use script to fake a TTY and capture output:

# Step 1: Enable the plugin
ssh nuc "script -qc 'cd ~/openclaw && docker compose run --rm openclaw-cli plugins enable whatsapp' /dev/null"

# Step 2: Restart gateway
ssh nuc "cd ~/openclaw && docker compose restart openclaw-gateway"

# Step 3: Run login with TTY capture (captures QR to file)
ssh nuc "script -q /tmp/openclaw-qr.txt -c 'cd ~/openclaw && docker compose run --rm openclaw-cli channels login'"

# Step 4: If QR needs to be viewed remotely, copy and render as image
scp nuc:/tmp/openclaw-qr.txt /tmp/
# Then use Python + Pillow to convert Unicode block chars to PNG

QR to PNG conversion (run locally on Mac):

from PIL import Image
import re

with open("/tmp/openclaw-qr.txt", "rb") as f:
    content = f.read().decode("utf-8", errors="replace")

lines = content.split("\n")
qr_lines = []
for l in lines:
    clean = re.sub(r"\x1b\[[0-9;]*[a-zA-Z]", "", l).replace(chr(0), "")
    if any(c in clean for c in ["\u2584", "\u2588", "\u2580"]):
        qr_lines.append(clean)

scale = 10
width = max(len(l) for l in qr_lines)
height = len(qr_lines) * 2
img = Image.new("RGB", (width * scale, height * scale), "white")

for row_idx, line in enumerate(qr_lines):
    for col_idx, ch in enumerate(line):
        top_black = ch in ["\u2588", "\u2580"]
        bot_black = ch in ["\u2588", "\u2584"]
        for dy in range(scale):
            for dx in range(scale):
                if top_black:
                    img.putpixel((col_idx*scale+dx, row_idx*2*scale+dy), (0,0,0))
                if bot_black:
                    img.putpixel((col_idx*scale+dx, (row_idx*2+1)*scale+dy), (0,0,0))

img.save("/tmp/qr.png")

Anthropic Authentication

Uses a Claude Code OAuth token (valid 1 year). Set in both config and docker-compose env:

Config (~/.openclaw/openclaw.json):

{
  "env": {
    "ANTHROPIC_API_KEY": "sk-ant-oat01-..."
  }
}

Docker env (~/openclaw/.env):

ANTHROPIC_API_KEY=sk-ant-oat01-...

To regenerate token (run on Mac where claude CLI is installed):

claude setup-token
# Copy the output token and update both config + .env on NUC

Config Schema (current)

{
  "agents": {
    "defaults": {
      "model": {
        "primary": "anthropic/claude-sonnet-4-5-20250929"
      }
    }
  },
  "gateway": {
    "port": 18789,
    "mode": "local",
    "bind": "lan",
    "auth": {
      "mode": "token"
    }
  }
}

Config gotchas:

  • agent.model is legacy — use agents.defaults.model.primary instead
  • Run docker exec openclaw-openclaw-gateway-1 node dist/index.js doctor --fix to migrate legacy keys
  • The gateway.pairing key does NOT exist — device pairing is managed via the devices CLI, not config

Troubleshooting

  1. "control ui requires HTTPS or localhost": Access via https://alezmad-nuc.tail58f5ad.ts.net:8443 (Tailscale Serve), NOT http://192.168.1.3:18789

  2. "pairing required": Approve the device via devices approve command (see Device Pairing section above)

  3. "unauthorized: gateway token missing": Use the dashboard URL with #token=... hash to auto-authenticate

  4. CLI commands fail with "gateway closed": Use docker exec into the running gateway container instead of docker compose run (the CLI container can't reach the gateway on its internal Docker IP)

  5. Config "invalid" after edit: Run doctor --fix inside the gateway container to clean up

  6. Channel "unsupported": Enable the plugin first with plugins enable <id>, then restart gateway

  7. CLAUDE_AI_SESSION_KEY warnings: Harmless — these are for Claude web session auth which isn't used when using API key