---
date: 2026-06-30
type: decision
tags: [dttb, proxmox, ai, agent, open-webui, computer-use]
---

# cptr (Open WebUI Computer) — агент-песочница, 5-й коннект chat.dttb.ru

## Контекст
Олег попросил завести [open-webui/computer](https://github.com/open-webui/computer) («cptr») и подцепить к Open WebUI. cptr = «компьютер в браузере»: файлы, терминал, git, редактор + AI-агент. Отдаёт **OpenAI-совместимый `/v1/chat/completions`**, где каждый *workspace* виден как модель `cptr/<basename>` с полным агентским доступом (терминал/ФС/web/git) к хосту, где крутится.

## Решение
Отдельный **LXC 146 `cptr`** (песочница) на Proxmox 10.0.0.250 — radius взрыва ограничен контейнером. Мозг агента = OmniRoute Opus 4.8. cptr держим **LAN-only** (авторы: «только доверенная сеть, не в публичный интернет»); публичный chat.dttb.ru ходит к нему server-side по локалке (как Hermes 8642 / openclaw 18789).

## Что развёрнуто
- **LXC 146** Debian 12, unprivileged + `nesting=1,keyctl=1`, Docker 20.10, **2 vCPU / 2 GB / 12 GB** на `work`, onboot.
- IP **10.0.0.166** (nameserver 1.1.1.1, без NetBird). См. грабли с IP ниже.
- Контейнер `ghcr.io/open-webui/computer:latest`: `docker run -d --name cptr --restart unless-stopped -p 8000:8000 -v cptr-data:/data …`. Образ сам стартует `cptr run --host 0.0.0.0 --port 8000 --headless` (из Dockerfile CMD).
- Admin `oleg`/`1qaz!QAZ` (web http://10.0.0.166:8000).
- Workspace `cptr/main` → `/data/workspaces/main` (persistent в томе).
- **5-й OpenAI-коннект Open WebUI** (idx4): `http://10.0.0.166:8000/v1` + Bearer `sk-cptr-…`. В дропдауне chat.dttb.ru появилась модель `cptr/main`.

## Headless-настройка cptr (всё через API, FastAPI — точные пути из `/openapi.json`)
1. **Startup-токен**: `cptr run` **генерит свой** 64-hex и печатает в логах (`docker logs cptr` → `…/?token=…`), env `CPTR_STARTUP_TOKEN` игнорится. Брать из логов.
2. **Создать админа**: `POST /api/auth/setup {username,password,token,display_name}` → `{ok:true}` (даёт cookie `cptr_session`).
3. **Логин**: `POST /api/auth/login {username,password}` → cookie.
4. **Ключ для `/v1`**: `POST /v1/keys {name}` (cookie-auth) → отдаёт `{key:"sk-cptr-…",id,name}` **raw один раз**.
5. **Мозг (brain)**: `POST /api/admin/connections {name,provider:"openai",base_url,api_key,models,enabled}`; проверка `POST /api/admin/connections/{id}/verify`.
6. **Workspace**: `PUT /api/state/workspace?path=/data/workspaces/main` **с JSON-телом** `{"name":"main","path":"…"}` (без тела — 500: роутер читает `request.json()`). После — `cptr/main` появляется в `GET /v1/models` (Bearer-ключ).
7. **В Open WebUI**: `POST /openai/config/update` (полное тело) — добавить URL+key в `OPENAI_API_BASE_URLS`/`OPENAI_API_KEYS` индексом 4 + `OPENAI_API_CONFIGS["4"]={enable,name:"cptr (computer agent)",connection_type:"external",model_ids:["cptr/main"]}`. НЕ затирать idx0-3.

## Грабли (за что наступали)
- ⚠️ **Конфликт IP**: сначала дали **.146** — там реальное устройство **Яндекс-Станция Миди** (MAC `AC:BA:C0:39:82:64`). Тесты прошли (ARP случайно указывал на контейнер), но это мина → Станция перехватит ARP → chat.dttb.ru 502. **Та же грабля, что у LXC 145** ([[2026-06-27-homepage-dashboard-lxc145]]). Перенесли на **.166** (`pct set 146 -net0 …ip=10.0.0.166/24` + `pct reboot`), проверено arping + ping-sweep. **Урок: сверять IP с [[../projects/dttb/network-topology]] ДО раздачи; .145/.146 заняты TP-Link/Яндексом.**
- **Пустой api_key мозга → битый заголовок**: cptr при пустом ключе шлёт `Authorization: Bearer ` (пустой) → httpx «Illegal header value» → verify=false. Лечится **любым непустым** значением (`lan-trust`) — OmniRoute на LAN всё равно отдаёт `cc/claude-opus-4-8` по произвольному Bearer (проверено: `Bearer dummy` → completion 200). Это **отличие от Open WebUI**, где ключ OmniRoute = пустая строка.
- `/v1/models` пустой, пока нет ни одного workspace (модели гейтвея = workspaces, не мозг). Завести через `PUT /api/state/workspace`.
- Workspace-dir держать в томе `/data` (переживает пересоздание контейнера), не в `/home/cptr`.

## Безопасность
Гейт = **Bearer-ключ `sk-cptr-…` (только у Open WebUI) + LAN + admin-only Open WebUI**. Агент исполняет тулы (терминал/ФС) **внутри LXC 146** — проверено: на `hostname`/`uname` агент видит хостнейм контейнера (`d01b45f09cc6`), не Proxmox-хост. Аудит-лог включён (`CPTR_AUDIT_LOG_LEVEL=INFO`). cptr **не** за NPM и без публичного домена.

## Проверено (e2e)
chat.dttb.ru → `cptr/main` → OmniRoute Opus → агент → `run_command`: `uname -a; pwd` вернул `Linux d01b45f09cc6 … x86_64` + cwd `/data/workspaces/main`. `echo cptr-live; whoami` → `cptr-live`/`cptr`.

См. [[../projects/dttb/proxmox-inventory#LXC 146 — cptr (Open WebUI Computer / агент-исполнитель)]], [[2026-06-22-open-webui-deploy]].
