268 lines
8.3 KiB
Markdown
268 lines
8.3 KiB
Markdown
# DEV TASK: Деплой CLIProxyAPI на mva154
|
||
|
||
**Статус:** ✅ Выполнено
|
||
**Проект:** claude-cli-proxy
|
||
**BRD:** `tasks/claude-cli-proxy/BRD.md`
|
||
|
||
---
|
||
|
||
## Цель
|
||
|
||
Поднять CLIProxyAPI в Docker на mva154, подготовить к OAuth авторизации Claude Max подписки. После авторизации — OpenClaw сможет использовать Claude через подписку вместо API токенов.
|
||
|
||
## Контекст
|
||
|
||
- **CLIProxyAPI** — Go-сервер, оборачивает Claude Code CLI в OpenAI-compatible API
|
||
- **Docker image:** `eceasy/cli-proxy-api:latest`
|
||
- **Порт по умолчанию:** 8317
|
||
- **OAuth порт (для логина):** 54545
|
||
- **Доступ:** только из docker network (OpenClaw контейнер на том же хосте)
|
||
- **Один аккаунт**, без load balancing
|
||
|
||
---
|
||
|
||
## Инфраструктура
|
||
|
||
| Параметр | Значение |
|
||
|----------|----------|
|
||
| Сервер | `slin@82.22.50.71` (пароль: `motoZ@yaz2010`) |
|
||
| SSH | через Node.js ssh2 модуль |
|
||
| Docker network | та же сеть что у OpenClaw контейнера |
|
||
| Рабочая директория | `/home/slin/claude-cli-proxy/` |
|
||
|
||
---
|
||
|
||
## Задачи
|
||
|
||
### Task 1: Подготовка файлов на сервере
|
||
|
||
**Шаги:**
|
||
|
||
- [ ] **1.1** Создать директорию и config.yaml:
|
||
|
||
```bash
|
||
mkdir -p /home/slin/claude-cli-proxy/auth
|
||
cat > /home/slin/claude-cli-proxy/config.yaml << 'EOF'
|
||
port: 8317
|
||
remote-management:
|
||
allow-remote: false
|
||
secret-key: ""
|
||
auth-dir: "/root/.cli-proxy-api"
|
||
auth:
|
||
providers: []
|
||
debug: false
|
||
EOF
|
||
```
|
||
|
||
Примечание: `auth.providers: []` — отключает проверку API key, используется OAuth токен.
|
||
|
||
- [ ] **1.2** Создать docker-compose.yml:
|
||
|
||
```bash
|
||
cat > /home/slin/claude-cli-proxy/docker-compose.yml << 'EOF'
|
||
version: "3.8"
|
||
|
||
services:
|
||
cli-proxy-api:
|
||
image: eceasy/cli-proxy-api:latest
|
||
container_name: claude-cli-proxy
|
||
restart: unless-stopped
|
||
ports:
|
||
- "127.0.0.1:8317:8317"
|
||
volumes:
|
||
- ./config.yaml:/CLIProxyAPI/config.yaml
|
||
- ./auth:/root/.cli-proxy-api
|
||
networks:
|
||
- openclaw_net
|
||
|
||
networks:
|
||
openclaw_net:
|
||
external: true
|
||
EOF
|
||
```
|
||
|
||
⚠️ **ВАЖНО:** Нужно узнать имя docker network где живёт OpenClaw контейнер. Проверить:
|
||
```bash
|
||
docker network ls
|
||
docker inspect <openclaw-container-name> --format '{{range .NetworkSettings.Networks}}{{.NetworkID}}{{end}}'
|
||
```
|
||
|
||
Заменить `openclaw_net` на реальное имя сети.
|
||
|
||
- [ ] **1.3** Проверить что image скачивается:
|
||
|
||
```bash
|
||
cd /home/slin/claude-cli-proxy
|
||
docker compose pull
|
||
```
|
||
|
||
**Критерий:** Файлы на месте, image скачан.
|
||
|
||
---
|
||
|
||
### Task 2: Первый запуск и OAuth авторизация
|
||
|
||
**Шаги:**
|
||
|
||
- [ ] **2.1** Запустить контейнер в режиме логина (одноразово):
|
||
|
||
```bash
|
||
cd /home/slin/claude-cli-proxy
|
||
docker run --rm -it \
|
||
-p 54545:54545 \
|
||
-v $(pwd)/config.yaml:/CLIProxyAPI/config.yaml \
|
||
-v $(pwd)/auth:/root/.cli-proxy-api \
|
||
eceasy/cli-proxy-api:latest \
|
||
/CLIProxyAPI/CLIProxyAPI --claude-login --no-browser
|
||
```
|
||
|
||
Это выведет URL для авторизации. **Этот URL нужно передать Славе** — он откроет его в браузере и залогинится.
|
||
|
||
⚠️ Флаг `--no-browser` обязателен (headless сервер, нет GUI).
|
||
|
||
- [ ] **2.2** После успешного логина — проверить что токен сохранился:
|
||
|
||
```bash
|
||
ls -la /home/slin/claude-cli-proxy/auth/
|
||
# Должен быть файл с OAuth credentials
|
||
```
|
||
|
||
**Критерий:** OAuth токен сохранён в `./auth/`.
|
||
|
||
---
|
||
|
||
### Task 3: Запуск сервиса
|
||
|
||
**Шаги:**
|
||
|
||
- [ ] **3.1** Запустить через docker-compose:
|
||
|
||
```bash
|
||
cd /home/slin/claude-cli-proxy
|
||
docker compose up -d
|
||
```
|
||
|
||
- [ ] **3.2** Проверить что контейнер работает:
|
||
|
||
```bash
|
||
docker ps | grep claude-cli-proxy
|
||
docker logs claude-cli-proxy --tail 20
|
||
```
|
||
|
||
- [ ] **3.3** Проверить API:
|
||
|
||
```bash
|
||
# Список моделей
|
||
curl -s http://127.0.0.1:8317/v1/models | python3 -m json.tool
|
||
|
||
# Тестовый запрос
|
||
curl -s -X POST http://127.0.0.1:8317/v1/chat/completions \
|
||
-H "Content-Type: application/json" \
|
||
-H "Authorization: Bearer dummy" \
|
||
-d '{
|
||
"model": "claude-sonnet-4-20250514",
|
||
"messages": [{"role": "user", "content": "Say hello, one sentence only"}],
|
||
"stream": false
|
||
}' | python3 -m json.tool
|
||
```
|
||
|
||
- [ ] **3.4** Проверить streaming:
|
||
|
||
```bash
|
||
curl -s -X POST http://127.0.0.1:8317/v1/chat/completions \
|
||
-H "Content-Type: application/json" \
|
||
-H "Authorization: Bearer dummy" \
|
||
-d '{
|
||
"model": "claude-sonnet-4-20250514",
|
||
"messages": [{"role": "user", "content": "Count from 1 to 5"}],
|
||
"stream": true
|
||
}'
|
||
# Должен выдавать SSE chunks
|
||
```
|
||
|
||
**Критерий:** API отвечает, streaming работает.
|
||
|
||
---
|
||
|
||
### Task 4: Подключение к docker network OpenClaw
|
||
|
||
**Шаги:**
|
||
|
||
- [ ] **4.1** Определить сеть OpenClaw:
|
||
|
||
```bash
|
||
# Найти контейнер OpenClaw
|
||
docker ps | grep -i openclaw
|
||
# Посмотреть его сеть
|
||
docker inspect <container_name> --format '{{json .NetworkSettings.Networks}}' | python3 -m json.tool
|
||
```
|
||
|
||
- [ ] **4.2** Обновить docker-compose.yml с правильным именем сети (если отличается от `openclaw_net`)
|
||
|
||
- [ ] **4.3** Проверить что OpenClaw контейнер видит прокси:
|
||
|
||
```bash
|
||
# Из контейнера OpenClaw
|
||
docker exec <openclaw-container> curl -s http://claude-cli-proxy:8317/v1/models
|
||
```
|
||
|
||
**Критерий:** OpenClaw контейнер может достучаться до `claude-cli-proxy:8317`.
|
||
|
||
---
|
||
|
||
## Проверка (Acceptance)
|
||
|
||
| # | Проверка | Команда | Ожидаемый результат |
|
||
|---|----------|---------|---------------------|
|
||
| 1 | Контейнер запущен | `docker ps \| grep claude-cli-proxy` | STATUS: Up |
|
||
| 2 | Models endpoint | `curl http://127.0.0.1:8317/v1/models` | JSON с claude моделями |
|
||
| 3 | Chat completion | `curl POST /v1/chat/completions` | Ответ от Claude |
|
||
| 4 | Streaming | `curl POST stream=true` | SSE chunks |
|
||
| 5 | Доступ из OpenClaw | `docker exec openclaw curl ...` | Ответ от прокси |
|
||
|
||
---
|
||
|
||
## Ограничения и грабли
|
||
|
||
- ⚠️ SSH только через Node.js ssh2 (бинарный ssh сломан в контейнере OpenClaw)
|
||
- ⚠️ OAuth логин — **ручной шаг**, нужен браузер Славы. Dev готовит URL, Слава логинится.
|
||
- ⚠️ `--no-browser` обязателен при логине (headless сервер)
|
||
- ⚠️ `auth.providers: []` в config — без этого будет требовать API key
|
||
- ⚠️ Порт 8317 слушает только на 127.0.0.1 (не наружу!)
|
||
- ⚠️ Имя docker network нужно определить динамически — не хардкодить
|
||
- 🚫 НЕ открывать порт наружу
|
||
- 🚫 НЕ запускать несколько инстансов (риск бана)
|
||
|
||
---
|
||
|
||
## После деплоя (делает Стрим, не Dev)
|
||
|
||
После успешного Task 4 — Стрим добавит provider в OpenClaw config:
|
||
```json
|
||
{
|
||
"id": "claude-cli-proxy",
|
||
"type": "openai",
|
||
"baseUrl": "http://claude-cli-proxy:8317/v1",
|
||
"apiKey": "dummy",
|
||
"models": ["claude-sonnet-4-20250514", "claude-opus-4-20250514"]
|
||
}
|
||
```
|
||
|
||
И назначит Dev-агенту модель через этот provider.
|
||
|
||
---
|
||
|
||
## Деплой-чеклист
|
||
|
||
- [ ] Директория и файлы созданы
|
||
- [ ] Docker image скачан
|
||
- [ ] OAuth авторизация пройдена (ручной шаг Славы)
|
||
- [ ] Контейнер запущен и отвечает
|
||
- [ ] Streaming работает
|
||
- [ ] Доступен из docker network OpenClaw
|
||
- [ ] Порт НЕ открыт наружу
|
||
|
||
---
|
||
|
||
*Создано: 2026-05-14 | Автор ТЗ: Стрим | Исполнитель: Dev-агент*
|