Windows OpenClaw Setup — инструкция для Claude Code

Цель

Развернуть OpenClaw Gateway на Windows-машине Алексея (рядом с уже работающим WSL2+Ollama), подключить как backend наш локальный Qwen 2.5 14B, поднять headless HTTP API на порту 18789, пробросить через autossh-туннель на VPS.

Это замена нашего самописа erp-openclaw-agent + erp-llm-gateway (отказан 2026-05-13) на готовый mainstream-фреймворк (371k звёзд на GitHub, MIT). См. ADR-022 rev 2.


Целевое состояние

  • ✅ Node 24 (или 22.16+) установлен на Windows
  • ✅ OpenClaw Gateway установлен через official installer
  • ✅ Конфиг: provider=ollama, baseUrl=http://127.0.0.1:11434, model=qwen2.5:14b-instruct-q5_k_m
  • ✅ HTTP API auth-token сгенерирован и сохранён
  • ✅ Gateway запущен в headless mode на 0.0.0.0:18789
  • ✅ Smoke-test: curl http://localhost:18789/v1/chat/completions → отвечает Qwen
  • ✅ autossh-туннель пробрасывает 18789 на VPS (как сейчас Ollama 11434)
  • ✅ Файл Desktop\openclaw-setup-result.txt со всеми данными для Алексея

Правила работы для Claude

  1. Действуй автономно — не спрашивай разрешения на установку пакетов, минимум перезагрузок.
  2. PowerShell как Administrator где требуется.
  3. После каждого шага — проверка результата. Если упало — один retry, потом проси юзера помочь.
  4. Ничего не отключай в системе (Defender, Firewall в широком смысле — только конкретные правила).
  5. Все скачивания — через winget или официальные installers. Только официальные источники.
  6. Финальный отчёт в C:\Users\<имя>\Desktop\openclaw-setup-result.txt.

Контекст что уже есть на машине

Алексей уже выполнил инструкцию Windows LLM Host Setup:

  • WSL2 + Ubuntu с Ollama внутри — слушает на 127.0.0.1:11434
  • Tailscale установлен (но текущая интеграция использует autossh reverse SSH, см. ниже)
  • autossh туннель WSL→VPS работает для порта 11434

Что добавляем сейчас: OpenClaw на Windows native (не в WSL — она тяжёлая, и нам нужен HTTP API ближе к юзеру), который ходит в WSL2 Ollama через localhost:11434 (WSL forwards localhost ports на Windows автоматически).


Шаг 0: Проверки

# 0.1. Версия Windows + место
Get-ComputerInfo | Select-Object WindowsProductName, OsVersion
Get-PSDrive C | Select-Object Used, Free
 
# 0.2. WSL и Ollama живы?
wsl -d Ubuntu -e bash -c "curl -s --max-time 3 http://127.0.0.1:11434/api/version"
# Ожидаемо: {"version":"0.23.2"} или похожее
# Если пусто или ошибка — попроси юзера запустить WSL: wsl
 
# 0.3. Доступен ли Ollama НА Windows на 11434? (WSL2 mirrored mode прокидывает)
curl http://127.0.0.1:11434/api/version
# Если 404/refused — WSL2 НЕ форвардит. В этом случае шаг 1.5 ниже.
 
# 0.4. winget
winget --version

Если место < 5 GB или WSL/Ollama не отвечают → остановись.


Шаг 1: Node.js 24 (или 22.16+)

# 1.1. Текущая версия
node --version
# Если < 22.16 — установить v24 через nvm-windows или winget
 
# 1.2. Установка
winget install OpenJS.NodeJS.LTS --accept-source-agreements --accept-package-agreements
# или вручную: https://nodejs.org/en/download (Windows installer .msi LTS)
 
# 1.3. Проверка после установки (новый PowerShell)
node --version  # должно быть v22.16+ или v24
npm --version

Шаг 1.5: Если Ollama не виден с Windows (WSL2 NAT)

Часто требуется на чистой Windows 11

WSL2 по умолчанию работает в NAT, и localhost:11434 на Windows НЕ ходит в WSL. Решение — включить mirrored networking mode (требует Windows 11 22H2+).

# 1.5.1. Создать или обновить .wslconfig
$wslconfig = "$env:USERPROFILE\.wslconfig"
@"
[wsl2]
networkingMode=mirrored
firewall=false
"@ | Set-Content -Path $wslconfig -Encoding UTF8 -Force
 
# 1.5.2. Перезагрузить WSL
wsl --shutdown
Start-Sleep -Seconds 5
 
# 1.5.3. После рестарта WSL — снова проверить из Windows
curl http://127.0.0.1:11434/api/version
# Должно вернуть {"version":"..."}

Если всё равно не работает — fallback: использовать IP WSL: wsl -d Ubuntu -e bash -c "hostname -I" и подставить его в config OpenClaw вместо 127.0.0.1.


Шаг 2: Установка OpenClaw

# 2.1. Официальный installer (PowerShell one-liner)
iwr -useb https://openclaw.ai/install.ps1 | iex
 
# Установщик создаст:
# - бинарь openclaw в PATH
# - конфиг в %APPDATA%\openclaw\ или %LOCALAPPDATA%\openclaw\
 
# 2.2. Проверка
openclaw --version
openclaw --help

Если installer не работает или PATH не обновился — открыть новое окно PowerShell (тек. сессия PATH старого).


Шаг 3: Конфиг — подключить Ollama Qwen 14B

OpenClaw читает конфиг из %APPDATA%\openclaw\config.json5 (если на Windows иначе — проверь openclaw config show или --help).

# 3.1. Найти путь к конфигу
$openclawConfigDir = "$env:APPDATA\openclaw"
if (-not (Test-Path $openclawConfigDir)) { New-Item -ItemType Directory -Force -Path $openclawConfigDir }
$configPath = "$openclawConfigDir\config.json5"
echo "Config path: $configPath"
 
# 3.2. Сгенерировать auth-token
$authToken = -join ((48..57) + (65..90) + (97..122) | Get-Random -Count 48 | ForEach-Object {[char]$_})
echo "Generated auth token: $authToken"
 
# 3.3. Сохранить токен в переменную окружения (для smoke-test и для autossh-инструкции потом)
[Environment]::SetEnvironmentVariable("OPENCLAW_AUTH_TOKEN", $authToken, "User")
 
# 3.4. Создать config.json5
$config = @"
{
  // OpenClaw Gateway config — ERP-агент, backend = локальный Qwen 14B
  // See: https://docs.openclaw.ai/providers/ollama
 
  gateway: {
    // Слушать на всех интерфейсах чтобы можно было пробросить через autossh
    host: '0.0.0.0',
    port: 18789,
    auth: {
      mode: 'token',
      tokens: ['$authToken']
    }
  },
 
  models: {
    providers: {
      ollama: {
        baseUrl: 'http://127.0.0.1:11434',
        apiKey: 'ollama-local',
        api: 'ollama',
        timeoutSeconds: 300,
        models: [
          {
            id: 'qwen2.5:14b-instruct-q5_k_m',
            name: 'qwen2.5:14b-instruct-q5_k_m',
            input: ['text'],
            params: {
              keep_alive: '24h'
            }
          }
        ]
      }
    }
  },
 
  agents: {
    defaults: {
      model: { primary: 'ollama/qwen2.5:14b-instruct-q5_k_m' }
    },
    list: [
      {
        id: 'erp-agent',
        // Persona + Qwen native tool-call format + минимальный workflow.
        // Без 3-4 строк workflow Qwen 14B Q5 не делает chain-of-thought
        // «получил error → попробовать другой tool» — модель просит юзера
        // найти UUID руками. С workflow — chain работает.
        systemPromptOverride: \`Ты — AI-помощник владельца кафе-франшизы в системе Альфа ERP.
Отвечаешь на русском, коротко.
 
Tool calls — строго в формате:
<tool_call>
{"name": "имя_инструмента", "arguments": {...}}
</tool_call>
 
Workflow:
1. Если юзер упомянул ТТ по имени (например «Арбат», «флагман») — СНАЧАЛА вызови find_stores с этим именем.
2. Из результата возьми store_id — используй его в следующих tool вызовах.
3. Если find_stores вернул 0 ТТ — скажи юзеру что не нашёл.
4. После всех tools — короткий финальный ответ юзеру.
 
НИКОГДА не проси юзера найти UUID — у тебя есть find_stores. НИКОГДА не выдумывай UUID.\`,
        mcpServers: ['obsidian-vault', 'erp-skills']
      }
    ]
  },
 
  // MCP — два сервера: vault (obsidian_erp) и erp-skills (наш собственный)
  // Win-Claude склонирует репо на шаге 5/6 и подставит пути ниже.
  mcp: {
    servers: {
      'obsidian-vault': {
        command: 'npx',
        args: [
          '-y',
          '@modelcontextprotocol/server-filesystem',
          // путь к локально склонированному obsidian_erp (Шаг 5)
          'C:\\\\Users\\\\$env:USERNAME\\\\Documents\\\\obsidian_erp'
        ]
      },
      'erp-skills': {
        command: 'node',
        args: [
          // путь к собранному dist/server.js erp-openclaw-skills (Шаг 6)
          'C:\\\\Users\\\\$env:USERNAME\\\\erp-openclaw-skills\\\\dist\\\\server.js'
        ],
        env: {
          ERP_BASE_URL: 'https://erp-test.nirbi.ru',
          // ⬇️ ВАЖНО: подставить service-token который дал Алексей (выдан 2026-05-13, TTL 90 дней)
          ERP_SERVICE_TOKEN: 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJjOWQzODQ3Ny02YjY0LTQ4ZTQtODc4Ny02NDBhMzc1OGVjMGUiLCJmcmFuY2hpc2VfaWQiOiIwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDEiLCJyb2xlX2lkcyI6W10sImlzX3NlcnZpY2UiOnRydWUsImV4cCI6MTc4NjQ0MTI1NiwiaWF0IjoxNzc4NjY1MjU2fQ.LQAm92lHY4IKwyuTjA0TitlIvAcYWVynOJit3h3PX5I'
        }
      }
    }
  },
 
  // Каналы (Telegram/Discord/etc) — ВЫКЛЮЧЕНЫ.
  // Для ERP-интеграции используем только HTTP API + WebSocket.
  channels: {}
}
"@
 
$config | Set-Content -Path $configPath -Encoding UTF8 -Force
 
# 3.5. Валидировать что конфиг подхватился
openclaw gateway config show 2>&1 | head -20
# или
openclaw gateway status 2>&1

Если синтаксис конфига сменился

openclaw мог сменить структуру с прошлого моего знания. Если падает на валидации:

  1. Запусти openclaw config init — он создаст базовый конфиг с актуальной схемой
  2. Изучи docs: https://docs.openclaw.ai/gateway/configuration-reference
  3. Внеси правки сохраняя нашу структуру (port=18789, ollama provider, qwen2.5:14b-instruct-q5_k_m)

Шаг 4: Первый запуск + smoke test

# 4.1. Запустить Gateway в фоне (Start-Process с -PassThru чтобы получить PID)
$openclawProc = Start-Process -FilePath "openclaw" -ArgumentList "gateway","start" `
  -WindowStyle Hidden -PassThru
echo "OpenClaw PID: $($openclawProc.Id)"
Start-Sleep -Seconds 8
 
# 4.2. Health check
curl http://127.0.0.1:18789/health
# или (если /health нет):
curl http://127.0.0.1:18789/v1/models -H "Authorization: Bearer $env:OPENCLAW_AUTH_TOKEN"
 
# 4.3. Полный smoke-test — обращение к Qwen через OpenClaw
$body = @'
{
  "model": "openclaw/default",
  "messages": [{"role":"user","content":"Скажи в одной строке: я — OpenClaw, работаю через Qwen."}],
  "stream": false
}
'@
curl http://127.0.0.1:18789/v1/chat/completions `
  -H "Authorization: Bearer $env:OPENCLAW_AUTH_TOKEN" `
  -H "Content-Type: application/json" `
  -d $body
# Ожидаемо: { "choices": [{"message":{"content":"Я — OpenClaw..."}}] }

Если упало:

  • openclaw gateway logs --tail 50 посмотри в логи
  • Проверь что Ollama-baseURL в конфиге доступен из Windows: curl http://127.0.0.1:11434/api/version

Шаг 4.5: Клонировать MCP-источники (vault + erp-skills)

OpenClaw подключает два MCP-сервера. Оба клонируются с GitHub.

# 4.5.1. Папка под исходники
$srcDir = "$env:USERPROFILE\Documents"
New-Item -ItemType Directory -Force -Path $srcDir | Out-Null
cd $srcDir
 
# 4.5.2. Obsidian vault — для документации (read-only через MCP filesystem)
if (-not (Test-Path "$srcDir\obsidian_erp")) {
  git clone https://github.com/nearbyErp/obsidian_erp.git
}
# Daily git pull (раз в сутки достаточно — Алексей коммитит редко)
$pullAction = New-ScheduledTaskAction -Execute "git" -Argument "-C $srcDir\obsidian_erp pull origin main --ff-only" -WorkingDirectory "$srcDir\obsidian_erp"
$pullTrigger = New-ScheduledTaskTrigger -Daily -At 4am
Register-ScheduledTask -TaskName "obsidian_erp daily pull" `
  -Action $pullAction -Trigger $pullTrigger -Force | Out-Null
 
# 4.5.3. erp-openclaw-skills — наш MCP-server для ERP API
cd $env:USERPROFILE
if (-not (Test-Path "$env:USERPROFILE\erp-openclaw-skills")) {
  git clone https://github.com/nearbyErp/erp-openclaw-skills.git
}
cd "$env:USERPROFILE\erp-openclaw-skills"
 
# 4.5.4. Активировать pnpm через corepack (приходит с Node 22+)
corepack enable
corepack prepare pnpm@9.15.0 --activate
 
# 4.5.5. Install + build
pnpm install --frozen-lockfile
pnpm build
 
# 4.5.6. Sanity check — скомпилирован ли server.js
Test-Path "$env:USERPROFILE\erp-openclaw-skills\dist\server.js"
# должно быть True

После этого пути в config.json5 (Шаг 3) уже подставлены — $env:USERNAME раскроется автоматически. Если у тебя другое имя пользователя — поправь руками в mcp.servers.{}.args.

Service-token уже в конфиге

Mac-Claude (Алексей) уже прописал ERP_SERVICE_TOKEN в шаблон config.json5 (Шаг 3). TTL 90 дней (выдан 2026-05-13). Менять ничего не нужно.


Шаг 5: Сервис (автозапуск при boot)

OpenClaw должен запускаться при перезагрузке Windows. Самое простое — Task Scheduler.

# 5.1. Создать scheduled task
$action = New-ScheduledTaskAction -Execute "openclaw" -Argument "gateway start"
$trigger = New-ScheduledTaskTrigger -AtLogOn
$principal = New-ScheduledTaskPrincipal -UserId "$env:USERDOMAIN\$env:USERNAME" -LogonType Interactive
$settings = New-ScheduledTaskSettingsSet -StartWhenAvailable -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1)
Register-ScheduledTask -TaskName "OpenClaw Gateway" `
  -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Force
 
# 5.2. Проверка
Get-ScheduledTask -TaskName "OpenClaw Gateway"

Шаг 6: Прокинуть HTTP API через autossh на VPS

У Алексея в WSL уже работает autossh -R 11434:localhost:11434 root@185.152.93.77 для Ollama. Добавим вторую переадресацию для OpenClaw 18789.

Текущий autossh висит в WSL — а OpenClaw на Windows native

Поэтому из WSL localhost:18789 это сама WSL, не Windows. Нужно сделать одно из:

  1. Если WSL2 в mirrored mode (Шаг 1.5) — localhost:18789 в WSL = Windows:18789 (просто работает)
  2. Иначе — autossh должен биндить к Windows IP (получить через ipconfig → vEthernet (WSL) gateway)

Самое простое — добавить второй -R в существующий autossh в WSL:

# 6.1. В WSL: остановить старый autossh
wsl -d Ubuntu -e bash -c "pkill autossh; sleep 2; pgrep autossh || echo 'no autossh'"
 
# 6.2. Запустить новый autossh с обоими тоннелями
wsl -d Ubuntu -e bash -c @"
autossh -M 0 -f -N \
  -o ServerAliveInterval=20 \
  -o ServerAliveCountMax=3 \
  -o ExitOnForwardFailure=yes \
  -o StrictHostKeyChecking=no \
  -R 11434:localhost:11434 \
  -R 18789:localhost:18789 \
  root@185.152.93.77
"@
 
# 6.3. Проверка
wsl -d Ubuntu -e bash -c "pgrep -af autossh"

Если mirrored mode WSL не включён

-R 18789:localhost:18789 будет смотреть в WSL localhost — не туда. В этом случае замени на -R 18789:<windows-IP>:18789 где Windows IP смотреть через ipconfig (вкладка vEthernet (WSL) → Default Gateway).


Шаг 7: Финальный отчёт

$report = @"
=== Windows OpenClaw Setup — Result ===
Date: $(Get-Date -Format "yyyy-MM-dd HH:mm:ss")
 
OpenClaw version: $(openclaw --version 2>&1)
Node version: $(node --version)
Config path: $env:APPDATA\openclaw\config.json5
 
Gateway:
  URL (local): http://127.0.0.1:18789
  Port: 18789
  Auth token: $env:OPENCLAW_AUTH_TOKEN
  Process running: $(if (Get-Process openclaw -ErrorAction SilentlyContinue) { 'YES' } else { 'NO' })
 
LLM Backend:
  Provider: ollama
  Base URL: http://127.0.0.1:11434 (WSL2)
  Model: qwen2.5:14b-instruct-q5_k_m
 
Tunnel:
  Tailscale IP (WSL): $(wsl -d Ubuntu -e tailscale ip --4 2>&1)
  Autossh tunnels: $(wsl -d Ubuntu -e bash -c "ss -tlnp 2>/dev/null | grep -E ':(11434|18789)'" )
 
=== Smoke test ===
GET /v1/models: $(curl -sS -H "Authorization: Bearer $env:OPENCLAW_AUTH_TOKEN" http://127.0.0.1:18789/v1/models 2>&1 | Out-String)
 
=== Для Алексея ===
1. AUTH TOKEN (для admin-bff.env на VPS):
   OPENCLAW_AUTH_TOKEN=$env:OPENCLAW_AUTH_TOKEN
 
2. На VPS должно работать:
   curl http://localhost:18789/v1/chat/completions \
     -H "Authorization: Bearer $env:OPENCLAW_AUTH_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{"model":"openclaw/default","messages":[{"role":"user","content":"hi"}]}'
 
3. Дальше — пишем custom skills для ERP API
"@
 
$report | Out-File -FilePath "$env:USERPROFILE\Desktop\openclaw-setup-result.txt" -Encoding UTF8
Write-Host $report

Покажи пользователю содержимое и попроси прислать Алексею OPENCLAW_AUTH_TOKEN.


Возможные проблемы

СимптомРешение
openclaw: command not found после установкиОткрой новое окно PowerShell. Если всё равно — добавь %LOCALAPPDATA%\openclaw\bin в PATH.
curl 127.0.0.1:11434 не отвечает с WindowsWSL2 NAT. Включи mirrored mode (Шаг 1.5) или используй WSL IP.
OpenClaw падает на стартeopenclaw gateway logs посмотри ошибку. Чаще всего — невалидный config.json5 (висячая запятая, неэкранированный символ).
curl /v1/chat/completions возвращает 401Проверь что в Authorization: Bearer <token> подставлен правильный токен из конфига.
Qwen отвечает медленно/обрываетсяПроверь что в Ollama-config keep_alive: '24h' — модель не выгружается из VRAM.
Tool calls не работаютПо docs OpenClaw — НЕ используй URL с /v1 для Ollama provider (поломает tool calling). Должно быть baseUrl: 'http://127.0.0.1:11434' БЕЗ /v1.

После завершения

Алексей продолжит на маке:

  • Возьмёт OPENCLAW_AUTH_TOKEN и пропишет в VPS envs/admin-bff.env
  • Подменит AGENT_SERVICE_URL на endpoint OpenClaw
  • Напишет 5 кастомных skills для ERP API (find_stores, find_products, create_order, get_stoplist, get_sales_summary)
  • Передеплоит admin-bff

Связанные документы