Files
2026-02-14 14:28:03 +01:00

9.1 KiB

OpenClaw on TrueNAS SCALE

Self-hosted AI agent gateway that connects LLMs to messaging platforms (Telegram, Discord, WhatsApp). Runs as a persistent daemon — can message proactively, execute shell commands, manage files, and automate tasks.

Prerequisites

  • TrueNAS SCALE (24.10 Electric Eel or newer recommended — native Docker support)
  • Dockge running on TrueNAS for Docker Compose management
  • A dataset for OpenClaw storage: tank/configs/openclaw
  • NanoGPT API key from https://nano-gpt.com (or OpenRouter key from https://openrouter.ai)
  • Telegram bot token from @BotFather

1. Create Storage Datasets

In TrueNAS web UI, create two datasets under your apps pool:

tank/configs/openclaw/config    # maps to ~/.openclaw
tank/configs/openclaw/workspace # maps to ~/openclaw/workspace

Set permissions to UID 1000 (the container runs as node uid 1000):

sudo chown -R 1000:1000 /mnt/tank/configs/openclaw/config
sudo chown -R 1000:1000 /mnt/tank/configs/openclaw/workspace

Important: If you skip this step, onboarding will fail with EACCES: permission denied when writing openclaw.json.

2. Create the Telegram Bot

  1. Open Telegram, search for @BotFather
  2. Send /newbot
  3. Choose a name and username (username must end in bot)
  4. Save the bot token (format: 123456789:ABCdefGHIjklMNOpqrsTUVwxyz)

3. Deploy via Dockge

In Dockge, create a new stack called openclaw.

Compose YAML

Two services are required: openclaw-gateway runs the persistent gateway, and openclaw-cli is used for one-off CLI commands (onboarding, channel setup, diagnostics). The cli profile prevents it from starting automatically.

services:
  openclaw-gateway:
    image: ghcr.io/openclaw/openclaw:latest
    container_name: openclaw
    restart: unless-stopped
    ports:
      - "18789:18789"
    volumes:
      - /mnt/tank/configs/openclaw/config:/home/node/.openclaw
      - /mnt/tank/configs/openclaw/workspace:/home/node/workspace
    environment:
      - NANO_GPT_API_KEY=${NANO_GPT_API_KEY}
      - OPENROUTER_API_KEY=${OPENROUTER_API_KEY}
    command: ["node", "openclaw.mjs", "gateway", "--allow-unconfigured", "--bind", "lan"]

  openclaw-cli:
    image: ghcr.io/openclaw/openclaw:latest
    volumes:
      - /mnt/tank/configs/openclaw/config:/home/node/.openclaw
      - /mnt/tank/configs/openclaw/workspace:/home/node/workspace
    environment:
      - NANO_GPT_API_KEY=${NANO_GPT_API_KEY}
      - OPENROUTER_API_KEY=${OPENROUTER_API_KEY}
    entrypoint: ["node", "openclaw.mjs"]
    profiles:
      - cli

Why two services? The Docker image's default entrypoint runs node openclaw.mjs gateway. If you try to run CLI commands (like onboard) via the gateway service, it fails with Cannot find module '/app/onboard' because the entrypoint tries to execute the argument as a standalone script. The openclaw-cli service overrides entrypoint to ["node", "openclaw.mjs"] so subcommands work correctly.

Why --bind lan? The gateway defaults to binding on 127.0.0.1 (loopback) inside the container. Docker port mapping requires the process to listen on 0.0.0.0, so --bind lan is mandatory for the port forwarding to work.

Environment Variables

In the Dockge .env section, add:

NANO_GPT_API_KEY=your-nanogpt-key-here
OPENROUTER_API_KEY=your-openrouter-key-here

First Run

Before starting the stack normally, run the onboarding wizard via SSH:

cd /mnt/tank/stacks/openclaw
sudo docker compose run --rm openclaw-cli onboard --no-install-daemon

The --no-install-daemon flag is required in Docker since the gateway runs as a separate container, not as a system daemon.

After onboarding completes, start the stack from the Dockge UI (or sudo docker compose up -d openclaw-gateway).

4. Configure OpenClaw

After the container is running, the config file lives at:

/mnt/tank/configs/openclaw/config/openclaw.json

The onboarding wizard writes this file. Key settings to verify:

  • gateway.bind should be "lan" (not "loopback")
  • gateway.auth.mode should be "token" with a generated token
  • channels.telegram.enabled should be true

NanoGPT as Provider (OpenAI-compatible)

NanoGPT exposes an OpenAI-compatible API at https://nano-gpt.com/api/v1. Configure it as a custom provider:

{
  "agents": {
    "defaults": {
      "model": {
        "primary": "nanogpt/claude-sonnet-4.5",
        "fallbacks": ["openrouter/anthropic/claude-sonnet-4.5"]
      }
    }
  },
  "env": {
    "NANO_GPT_API_KEY": "your-nanogpt-key",
    "OPENROUTER_API_KEY": "sk-or-your-openrouter-key"
  }
}

Note: If NanoGPT is not natively supported as a provider, configure it as a custom provider with base URL https://nano-gpt.com/api/v1. Check the custom providers docs for exact syntax.

OpenRouter as Provider (alternative)

{
  "agents": {
    "defaults": {
      "model": {
        "primary": "openrouter/anthropic/claude-sonnet-4.5"
      }
    }
  },
  "env": {
    "OPENROUTER_API_KEY": "sk-or-your-key"
  }
}

5. Connect Telegram

From SSH on TrueNAS, use the CLI service:

cd /mnt/tank/stacks/openclaw
sudo docker compose run --rm openclaw-cli channels add --channel telegram --token "YOUR_BOT_TOKEN"

Then approve the pairing. Send a message to your bot in Telegram — it will reply with a pairing code. Approve it:

sudo docker compose run --rm openclaw-cli pairing approve telegram <CODE>

6. Access the Control UI

The Control UI requires HTTPS or localhost (browser secure context requirement). Direct access via LAN IP will not work.

Step 1: SSH tunnel

ssh -L 18789:localhost:18789 truenas_admin@192.168.178.189

Step 2: Get the dashboard URL with token

The gateway uses token-based authentication. The token is embedded in the URL fragment (#token=...). Get the full URL:

cd /mnt/tank/stacks/openclaw
sudo docker compose run --rm openclaw-cli dashboard --no-open

This prints a URL like:

http://172.16.10.3:18789/#token=your-gateway-token-here

Step 3: Open in browser

Replace the IP with localhost and open:

http://localhost:18789/#token=your-gateway-token-here

Do not access via http://192.168.178.189:18789 directly — the gateway rejects non-localhost, non-HTTPS WebSocket connections with code=4008 reason=connect failed.

7. Verify

  • Check gateway status: sudo docker compose run --rm openclaw-cli gateway status
  • View logs: sudo docker logs -f openclaw
  • Run diagnostics: sudo docker compose run --rm openclaw-cli doctor

8. Security Considerations

  • Do not expose port 18789 to the public internet. Use Tailscale, WireGuard, or VPN to access the Control UI remotely.
  • Enable explicit consent mode to require approval before OpenClaw executes write/exec commands.
  • Treat the /mnt/tank/configs/openclaw/config directory as sensitive — it contains API keys and session data.
  • The container runs as non-root (uid 1000), which is good practice.
  • Consider network isolation: create a dedicated Docker network or VLAN if your TrueNAS hosts other services.

Useful Commands

All CLI commands below assume you are in /mnt/tank/stacks/openclaw.

Command Description
sudo docker compose run --rm openclaw-cli gateway status Check if gateway is running
sudo docker compose restart openclaw-gateway Restart the gateway
sudo docker compose run --rm openclaw-cli doctor Automated health checks
sudo docker compose run --rm openclaw-cli dashboard --no-open Get Control UI URL with token
sudo docker logs -f openclaw Stream live logs
sudo docker compose run --rm openclaw-cli channels list List connected channels
sudo docker compose pull && sudo docker compose up -d openclaw-gateway Update to latest version

Troubleshooting

  • Cannot find module '/app/onboard': You ran a CLI subcommand via the gateway service. Use openclaw-cli service instead (it has the correct entrypoint).
  • EACCES: permission denied on config files: Host directories not owned by UID 1000. Run sudo chown -R 1000:1000 /mnt/tank/configs/openclaw/config.
  • Bind: loopback in doctor output: The onboarding wizard set bind to loopback in the config file, overriding the --bind lan command flag. Edit openclaw.json and set gateway.bind to "lan", then restart the gateway.
  • Browser shows "connection reset" or blank page: You are accessing via LAN IP instead of localhost. Use the SSH tunnel and open http://localhost:18789/#token=....
  • code=4008 reason=connect failed in logs: The browser is connecting without the required token or via a non-secure origin. Get the full URL with dashboard --no-open.
  • Gateway Bridge errors: Try network_mode: host in the compose file if bridge networking causes issues.
  • Container won't start: Check sudo docker logs openclaw for config validation errors — OpenClaw rejects malformed JSON5.