Dashboard
Setup

Dashboard Setup

Deploy the Clawner dashboard to manage your fleet of OpenClaw hosts.

Docker (Recommended)

Quick Start

docker run -d \
  --name clawner \
  -p 9000:9000 \
  -p 3002:3002 \
  -v clawner-data:/app/data \
  -e CLAWNER_PASSWORD=your-secure-password \
  ghcr.io/clawner/dashboard

Access:

Environment Variables

VariableDescriptionDefault
PORTAPI/WebSocket port9000
CLAWNER_PASSWORDAdmin passwordclawner
CLAWNER_JWT_SECRETJWT signing secret(random)

Docker Compose

version: '3.8'
 
services:
  clawner:
    image: ghcr.io/clawner/dashboard:latest
    container_name: clawner
    ports:
      - "9000:9000"
      - "3002:3002"
    environment:
      - CLAWNER_PASSWORD=${CLAWNER_PASSWORD}
      - CLAWNER_JWT_SECRET=${CLAWNER_JWT_SECRET}
    volumes:
      - clawner-data:/app/data
    restart: unless-stopped
 
volumes:
  clawner-data:

From Source

Prerequisites

  • Node.js 20+
  • pnpm (recommended) or npm

Installation

git clone https://github.com/clawner/dashboard.git
cd dashboard
npm install

Development

npm run dev

Production

npm run build
npm start

Reverse Proxy

Nginx

server {
    listen 443 ssl http2;
    server_name clawner.example.com;
 
    ssl_certificate /etc/letsencrypt/live/clawner.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/clawner.example.com/privkey.pem;
 
    # Dashboard
    location / {
        proxy_pass http://localhost:3002;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
 
    # WebSocket API
    location /ws {
        proxy_pass http://localhost:9000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_read_timeout 86400;
    }
 
    # REST API
    location /api {
        proxy_pass http://localhost:9000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Traefik

http:
  routers:
    clawner:
      rule: "Host(`clawner.example.com`)"
      service: clawner-dashboard
      tls:
        certResolver: letsencrypt
 
    clawner-api:
      rule: "Host(`clawner.example.com`) && (PathPrefix(`/ws`) || PathPrefix(`/api`) || PathPrefix(`/hosts`) || PathPrefix(`/invite`) || PathPrefix(`/health`))"
      service: clawner-api
      tls:
        certResolver: letsencrypt
 
  services:
    clawner-dashboard:
      loadBalancer:
        servers:
          - url: "http://localhost:3002"
 
    clawner-api:
      loadBalancer:
        servers:
          - url: "http://localhost:9000"