# Claude Proxy Control — полное руководство

Актуально на 2026-08-07. Описывает состояние после ревизии безопасности и перехода на пул прокси-аккаунтов.

---

## 1. Что это и зачем

CPC решает одну задачу: **заставить каждое приложение ходить в интернет по назначенному каналу, а не «как получится»**.

Windows не умеет маршрутизировать трафик по приложениям. CPC поднимает виртуальный сетевой адаптер (TUN) через `sing-box`, забирает в него весь трафик машины и раздаёт его по правилам, привязанным к имени процесса.

### Четыре канала

| Канал | Куда идёт трафик | Типичные приложения |
|---|---|---|
| **Дом** (`direct`) | Обычный интернет провайдера | Системные службы, локальные утилиты |
| **VPN** (`vpn`) | Через узел Sota (VLESS + Reality) | Браузер, мессенджеры |
| **Прокси** (`proxy`) | Через Squid по HTTP CONNECT | Claude, Cursor, node |
| **Блок** (`block`) | Никуда, соединение отклоняется | Телеметрия, нежелательное |

### Главный принцип: неизвестное блокируется

В конфиге стоит `route.final = "block"`. Приложение, которому канал не назначен, **не выйдет в интернет вообще**. Это сделано намеренно: лучше явный отказ, чем незаметная утечка мимо правил.

Новые приложения появляются в списке со статусом «ожидает» (`pending`) — их надо распределить вручную.

> **Claude — особый случай.** Он всегда идёт через Squid, канал у него сменить нельзя. Это защита от ситуации, когда Claude случайно уходит домой или в VPN.

---

## 2. Быстрый старт

### Установка

Скачайте `ClaudeProxyControl.zip`, распакуйте **целиком** (папки `python`, `desktop`, `runtime` должны лежать рядом) и запустите `Install.bat` — он попросит подтверждение администратора.

Ставить на компьютер заранее ничего не нужно: Python с tkinter, `customtkinter` и `sing-box` лежат в архиве. Интернет при установке не требуется.

Установщик копирует всё в `~\.claude-proxy-control`, поэтому распакованную папку после установки можно удалить.

Удаление — `Uninstall.bat`: снимает туннель, правило брандмауэра, оба задания планировщика, ярлык и папку продукта. **Лицензия при этом остаётся привязанной к компьютеру** — освободить её можно только кнопкой «отвязать» в кабинете.

### Первый запуск

1. **Лицензия.** Введите ключ вида `CPC-XXXXXX-XXXXXX`. Программа обратится к `api.proxy.mindq.ru`, получит срок действия и **персональные реквизиты прокси** и сохранит их в `license.json`.
2. **Узел Sota** — только если нужен канал VPN. CPC не содержит своего VPN, он переиспользует узлы клиента Sota:
   - запустите Sota, нажмите **Connect**, подождите 2–3 секунды, нажмите **Disconnect**;
   - фоновый «ловец» (`Watch-SotaCapture.ps1`) в этот момент копирует временный конфиг Sota себе;
   - узел появится на вкладке **Узлы** — выберите его и нажмите «Сделать активным».

   > Поймать конфиг Sota можно только пока **наш** туннель выключен: Sota должна подняться сама. Именно поэтому на самом первом запуске программа сначала ждёт захвата узлов и лишь потом переходит к обычному режиму. Если пропустить этот шаг, программа заработает без канала VPN.

3. **Дальше туннель поднимается сам** — см. ниже. Потребуется подтверждение UAC, **окно может спрятаться за другими**, проверьте панель задач.

Старт проходит 15 шагов с проверками. В конце должно быть `FAIL: 0`.

### Ежедневная работа

Запустили программу — туннель поднялся сам. Кнопка нужна только чтобы открыть или перезапустить Claude.

### Состояния программы

Их четыре, и они независимы:

| Состояние | Что значит |
|---|---|
| **Программа запущена** | Окно открыто. Само по себе ничего не значит для трафика. |
| **TUN поднят** | Работает перехват. Только в этом состоянии программа что-то видит и что-то блокирует. |
| **Sota установлена** | Есть пойманные узлы → доступен канал VPN. Без неё остальные каналы работают. |
| **Squid отвечает** | Можно запускать Claude. Без него маршрутизация остального продолжает работать. |

### Почему туннель поднимается сразу при старте

Весь перехват и вся блокировка неизвестных программ делаются самим TUN. Пока sing-box не запущен, программа **ничего не видит и ничего не закрывает** — трафик идёт мимо неё через обычный адаптер. Поэтому состояния «программа работает, но всё заблокировано» не бывает в природе: чтобы блокировать, надо поднять туннель.

Отсюда правило: программа работает — трафик под контролем. Если туннель поднять не удалось, на главном экране так и написано: «маршрутизация выключена — программа сейчас ничего не перехватывает», с причиной.

Поднятие туннеля не требует ни Sota, ни живого Squid — только активную лицензию и готовность ПК. Молчащий прокси не повод оставлять компьютер вообще без маршрутов; он лишь делает недоступным запуск Claude.

---

## 3. Кнопки и что они на самом деле делают

### «Запустить Claude»

Обычно туннель к этому моменту уже поднят самой программой, и кнопка просто открывает Claude. Если туннель почему-то не поднят — поднимет и его: собирает конфиг → проверяет его → стартует sing-box → ждёт появления адаптера → проверяет Squid и VPN → запускает Claude → убеждается, что трафик Claude реально ушёл в Squid.

Пока идёт старт, кнопка **погашена** и показывает номер шага (`Запускаю… 11/15`). Не запускайте Claude вручную в этот момент — программа откроет его сама, иначе получите два запуска.

Кнопка неактивна, когда **Squid не отвечает**: Claude ходит именно через него, и запускать его в такой момент бессмысленно. Причина написана рядом с кнопкой. Маршрутизация остальных приложений при этом продолжает работать.

### «Перезапустить Claude»

Появляется, когда туннель и Claude уже работают. Закрывает Claude, дожидается реального завершения процессов и открывает заново. **Туннель при этом не трогается.** Если Claude уже закрыт — просто открывает.

### «Применить маршруты»

Нужна после **любого** изменения, которое влияет на конфиг:

- смена канала у приложения;
- смена активного узла VPN;
- переактивация лицензии (новые реквизиты прокси).

Перед применением показывается **подтверждение с отсчётом 10 секунд**: сколько будет без сети, и что соединения Claude оборвутся и восстановятся сами. Закрывать Claude не нужно — он переживает паузу. По истечении отсчёта применение идёт само, кнопка «Отмена» доступна всё это время.

Последовательность: правило брандмауэра → остановить sing-box → дождаться исчезновения адаптера → запустить заново → снять правило.

На главном экране видно, сколько программ ждёт: «3 приложения ждут применения маршрутов — трафик заблокирован». Пока маршруты не применены, эти приложения держатся в блоке, чтобы они не продолжали ходить по старому каналу.

> **Почему нельзя «на лету».** Адрес узла, его Reality-ключи, логин и пароль Squid зашиты в конфиг, с которым запущен sing-box. Плюс адрес узла обязан присутствовать в правиле «мимо туннеля» — иначе соединение с узлом уйдёт в туннель само на себя. Подменить это в работающем процессе нечем: горячей перезагрузки у sing-box нет. Проверено на версии 1.13.14: `PUT /configs` через Clash API отвечает `204`, но конфиг не перечитывает — это заглушка ради совместимости.

### Пауза при пересборке и правило брандмауэра

Пока туннель пересобирается, маршрутов нет, и Windows отправляет трафик через обычный адаптер. Раньше это окно длилось **7.3–8.4 секунды** и было самым незащищённым моментом за всю работу программы — причём именно тогда пользователь уверен, что защищён.

Сейчас на это время ставится блокирующее правило брандмауэра `CPC-KillSwitch-TunRebuild`. Трафик не уходит мимо маршрутов, а просто встаёт. Само окно сокращено: фиксированное ожидание заменено опросом «адаптер исчез?», а тяжёлая чистка через PnP запускается только если он не ушёл сам.

Правило снимается в трёх местах, потому что переживает процесс, который его поставил:

1. в `finally` скрипта — покрывает любую ошибку по пути;
2. перед постановкой нового — снимает остатки прошлого раза;
3. отдельным `Clear-KillSwitch.ps1` — для случая, когда программа умерла внутри паузы.

Плюс файл-маркер `merged/killswitch.active`: при старте программа замечает недоснятое правило и предлагает убрать его. Если не получится — покажет команду для ручного снятия:

```powershell
Remove-NetFirewallRule -DisplayName "CPC-KillSwitch-TunRebuild"
```

### «Остановить Claude» / «Закрыть программу»

Гасят туннель (`Quit-Product.ps1`, нужен UAC) и закрывают Claude. После этого сеть работает обычным образом, без всяких правил. **Это же — аварийный выход**, если что-то пошло не так.

Формулировка подтверждения здесь намеренно другая, чем при применении маршрутов. Там Claude лишь теряет соединение на пару секунд и восстанавливается сам. Здесь он закрывается вместе с программой и **сам не вернётся**, а маршрутизации не будет вовсе — весь трафик пойдёт обычным путём, мимо программы.

---

## 4. Раздача каналов приложениям

Вкладка **Приложения**. Сверху те, кто был активен последние 2 минуты, снизу — остальные по алфавиту.

- зелёный кружок — приложение выходило в сеть в последние ~45 секунд;
- **ожидает** — канал не назначен, приложение сейчас **заблокировано**;
- правый клик по строке → выбор канала.

После смены канала обязательно **«Применить маршруты»**.

### Служебные записи, которых нет в списке

- `Claude.exe`, `cowork-svc.exe` — всегда прокси, менять нельзя;
- `cpc-probe-direct.exe`, `cpc-probe-vpn.exe`, `cpc-probe-squid.exe` — собственные проверки CPC, у них жёстко закреплённые каналы (см. §6).

---

## 5. Защита от утечек

Всё включается в `settings.json` и по умолчанию **включено**. Отключать стоит только при диагностике.

| Параметр | Что делает | Если выключить |
|---|---|---|
| `strict_route` | Правила файрвола, не дающие приложению обойти туннель | Приложение, привязавшееся к физическому интерфейсу, уйдёт мимо всех правил, и `block` его не увидит |
| `tunnel_ipv6` | Заводит IPv6 в туннель | На сети с IPv6 «заблокированные» и «прокси» приложения спокойно выйдут по v6 |
| `secure_dns` | DNS по DoH вместо открытого UDP | Провайдер видит все домены, которые вы посещаете, независимо от канала |
| `clash_api_port` | Локальный API для живой проверки (см. §7) | Пропадёт возможность сверить конфиг с реальностью |

Дополнительно, без настроек:

- **UDP заблокирован** для Claude и прокси-приложений — иначе QUIC ушёл бы мимо HTTP-прокси;
- **IPv6 заблокирован** для Claude и прокси-приложений — у Squid-сервера нет глобального IPv6, попытка просто сожгла бы время;
- **DNS-резолвер прибит к `direct`** — иначе `final: block` заблокировал бы сам DNS и туннель встал бы намертво;
- **Fail-closed**: если Squid недоступен — Claude и прокси-приложения уходят в `block`, а не домой. Если узел VPN мёртв — то же самое для VPN-приложений. Продукт скорее откажет, чем незаметно выпустит трафик не туда.

---

## 6. Как проверяется, что всё работает

### Три независимые пробы

CPC создаёт три копии `curl` под своими именами в `%USERPROFILE%\.claude-proxy-control\bin\`. Каждая прибита в конфиге к одному каналу:

```
cpc-probe-direct.exe → direct        cpc-probe-vpn.exe → sota-vless
cpc-probe-squid.exe  → claude-squid
```

Монитор запрашивает ими `ifconfig.me` и получает **три разных IP**:

```
direct = 136.169.210.100   ← домашний провайдер
vpn    =  64.137.54.220    ← узел Sota
squid  = 141.11.197.107    ← Squid
```

Если IP канала совпал с домашним — это **утечка**, и монитор так и напишет, а не покрасит в зелёный.

> Проба Squid намеренно **не** использует `-x`. Claude тоже не задаёт прокси — его ведёт sing-box. Проверка с `-x` тестировала бы путь, которым Claude никогда не ходит.

Если живой туннель ещё не знает про пробы (например, конфиг пересобран, но не применён), монитор честно пишет «канал не проверяется» вместо ложной зелёнки.

### Живая сверка через Clash API

sing-box поднимает локальный API на `127.0.0.1:9095` (реквизиты в `merged/clash-api.json`). Через него видно, **что туннель делает на самом деле**, а не что написано в конфиге:

```
claude.exe   → claude-squid
chrome.exe   → sota-vless
rustdesk.exe → direct
```

После каждого применения маршрутов CPC сверяет живые каналы с конфигом и пишет расхождения в лог (`apply.live_verify`). Это единственная проверка, которая способна поймать расхождение — снимок `applied-channels.json` строится из того же конфига и с ним разойтись не может.

---

## 7. Где что лежит

### Код продукта

```
%USERPROFILE%\.claude-proxy\product\
├── desktop\          интерфейс (Python + CustomTkinter)
│   ├── claude_proxy_app.py   главное окно, старт/применение/выход
│   ├── app_rules.py          каналы приложений
│   ├── net_monitor.py        проверки и пробы
│   ├── clash_api.py          живая сверка каналов
│   ├── nodes_db.py           база узлов Sota
│   └── tun_ready.py          проверка готовности ПК к TUN
├── runtime\          PowerShell (всё, что требует администратора)
│   ├── Start-VpnClaude.ps1   старт из 15 шагов
│   ├── Reload-VpnRoutes.ps1  перезапуск туннеля при применении
│   ├── Quit-Product.ps1      остановка
│   ├── _env.ps1              общие функции
│   ├── Install-Product.ps1   установка (-FilesOnly — проверка сборки без следов)
│   ├── Uninstall-Product.ps1 удаление
│   └── merged\build_sota_merged_config.py   сборка конфига sing-box
├── tools\
│   └── Build-PortablePython.ps1   переносимый интерпретатор для архива
├── Pack-Release.ps1  сборка _dist\ClaudeProxyControl.zip
└── docs\
```

Собрать архив: `.\Pack-Release.ps1` (интерпретатор кешируется в `_dist\python`, пересобрать — `-FreshPython`). Сборка сама проверяет комплектность, отсутствие кириллицы в `.bat` и BOM у скриптов; что попало в архив — написано в `BUILD.txt` внутри него.

> Старый личный путь `~\.claude-proxy\app\` **трогать нельзя** — это не продукт.

### Данные пользователя

```
%USERPROFILE%\.claude-proxy-control\
├── license.json              ключ, срок, реквизиты прокси
├── settings.json             настройки и переключатели защиты
├── proxy.env                 реквизиты Squid для сборщика (СОДЕРЖИТ ПАРОЛЬ)
├── bin\                      cpc-probe-*.exe
├── logs\cpc-trace.log        подробный лог работы программы
└── merged\
    ├── vpn-claude-config.json   конфиг sing-box (СОДЕРЖИТ ПАРОЛЬ)
    ├── status.json              живой TUN, pid sing-box, режим
    ├── app-rules.json           каналы приложений
    ├── applied-channels.json    что залито в туннель
    ├── clash-api.json           доступ к локальному API
    ├── vpn-claude-tun.log       лог sing-box (каждое соединение)
    └── sota-captured\latest.json  снимок выбранного узла
```

**`proxy.env` и `vpn-claude-config.json` содержат пароль от прокси в открытом виде.** Не пересылайте их в чаты и тикеты.

---

## 8. Диагностика

### Куда смотреть

| Симптом | Файл |
|---|---|
| Не применяются маршруты, не стартует | `logs\cpc-trace.log` |
| Приложение не выходит в сеть | `merged\vpn-claude-tun.log` (ищите `outbound/block`) |
| Проблемы старта | `merged\last-start.log` |
| Что видит монитор | `merged\monitor-status.json` |

### Читаем `cpc-trace.log`

Записи применения маршрутов идут по шагам:

```
apply.step 7 elevate Reload-VpnRoutes (UAC)
apply.elevate_done   result_ok=True      ← норма: 10–15 секунд
apply.verify_tun     adapter_ok=True
apply.live_verify    mismatch={}         ← живая сверка сошлась
apply.claude_relaunch → launch ok=True
```

Префиксы: `[BOOT]` — запуск с правами администратора, `[LAUNCHER]` — запускающий скрипт, `[RELOAD]` — сам перезапуск туннеля. Если после `[BOOT]` ничего нет — не подтвердили UAC.

### Типичные проблемы

**«Не применилось: не дождался ответа»** — не подтверждён UAC. Окно бывает за другими окнами.

**Приложение не выходит в сеть.** Скорее всего у него канал «ожидает» — назначьте канал и примените маршруты. Проверить, кого блокирует прямо сейчас, можно через Clash API (в логе `blocked_now`).

**После смены узла ничего не изменилось.** Нужно «Применить маршруты» — программа об этом сама напомнит и предложит применить сразу.

**«Reconnecting» в Cursor.** Cursor на канале прокси, значит каждый обрыв до Squid он показывает явно. Смотрите таймауты в `vpn-claude-tun.log`. Это, как правило, проблема сети до сервера, а не CPC.

**Всё сломалось после изменения настроек защиты.** «Закрыть программу» — туннель снимется, сеть вернётся в обычный режим. Затем поправьте `settings.json`.

---

## 9. Серверная часть

### Squid — 141.11.197.107:13128

Аутентификация обязательна (`basic_ncsa_auth`, файл `/etc/squid/passwd`), в конце `http_access deny all`.

Ключевые настройки:

```
connect_timeout 15 seconds           # дефолтные 60 с вешали клиента на минуту
tcp_outgoing_address 141.11.197.107  # только IPv4: глобального IPv6 у сервера нет
```

> `dns_v4_first` в Squid 5 устарел и игнорируется — предпочтение IPv4 задаётся именно через `tcp_outgoing_address`.

**Пул аккаунтов.** У каждой лицензии свой логин (`cpc01`, `cpc02`, …), а не общий на всех. Благодаря этому Squid пишет имя пользователя в `access.log` (8-е поле), и видно, кто именно и куда ходил:

```
1786108... 0 136.169.210.100 TCP_TUNNEL/200 ... cpc01 HIER_DIRECT/...
```

Добавить аккаунтов: `htpasswd -i -m /etc/squid/passwd cpcNN` на сервере, затем импорт в базу API.

### Лицензионный API — api.proxy.mindq.ru

FastAPI в Docker (`claude_proxy_api`) на MSK-сервере, база SQLite `data/product.db`.

| Эндпоинт | Назначение |
|---|---|
| `POST /v1/license/activate` | Проверка ключа, привязка устройства, **выдача реквизитов прокси** |
| `GET /v1/license/status` | Срок действия, текущие реквизиты |
| `POST /v1/heartbeat` | Отметка «жив», обновляет время устройства |
| `/cabinet` | Кабинет клиента: ключи, продление |
| `/admin` | Админка |

**Таблицы:** `users`, `licenses`, `payments`, `proxy_accounts` (пул), `devices`, `heartbeats`, `magic_tokens`.

### Пул и лимиты

- Аккаунт выдаётся из пула **атомарно**: `UPDATE ... WHERE status='free'` служит замком, две одновременные покупки не получат один аккаунт.
- **Нет свободных — покупка отклоняется** во всех трёх местах: API, кабинет и админка. Лучше отказать, чем выдать нерабочую лицензию или посадить двоих на один логин.
- Удаление лицензии возвращает аккаунт в пул.

### Одна лицензия — один компьютер

Ключ привязывается к первой машине, на которой его активировали. Попытка активировать тот же ключ на другом компьютере отклоняется:

```
device_limit:1:key_already_bound
```

Уже привязанная машина проходит активацию всегда — сколько угодно раз, при переустановке программы, смене конфига и т.п. Заблокировать работающий компьютер этим лимитом нельзя.

**Перенос лицензии на новый компьютер** — осознанное действие администратора: в админке нажать «отвязать» у старого устройства, после чего ключ активируется на новом. Отвязка не удаляет запись, а проставляет `revoked_at` — в базе остаётся след, а старая машина по этому ключу больше не пройдёт.

Нужны два компьютера — нужны две лицензии, каждая со своим прокси-аккаунтом. Это же и делает статистику осмысленной: один логин Squid = один человек за одной машиной.

### Админка

Вход только для адресов из `ADMIN_EMAILS` в `.env` (сейчас `admin@proxy.mindq.ru`).

Показывает: счётчики пула (краснеет при нуле, желтеет при ≤3), выдачу ключей, таблицу лицензий с прокси-аккаунтом и устройствами (индикатор «онлайн» + кнопка «отвязать»), полную таблицу пула.

---

## 10. Обслуживание

**Расширить пул.** Нарезать учётки на прокси-сервере → импортировать в `proxy_accounts`. Следите за счётчиком в админке: при нуле продажи встают.

> **Открытый вопрос по ёмкости.** `CAPACITY.md` задаёт ориентир **5 активных лицензий на один прокси-IP**, а сейчас все 20 аккаунтов пула сидят на единственном `141.11.197.107`. Пока клиент один — это не проблема, но при росте продаж либо аккаунты надо разносить по новым IP (по ~5 на каждый), либо пересмотреть сам ориентир, замерив реальную нагрузку. Сервер слабый: 1 ядро, 1 ГБ RAM, Squid однопоточный.

**Ротация паролей.** Пароль лицензии меняется заменой строки в `proxy_accounts` **и** в `/etc/squid/passwd`. Клиенту нужно переактивировать ключ, иначе он останется со старым.

**Логи.** `cpc-trace.log`, `monitor-history.jsonl` и `vpn-claude-tun.log` ротируются при старте программы по достижении 8 МБ. Лог sing-box пишет каждое соединение и растёт быстро — порядка 10 МБ в час при активной работе.

**Обновление кода API.** Код запечён в образ (`COPY` в Dockerfile), примонтирована только `./data`. После правки — `docker compose up -d --build`. Базу перед миграциями копируйте.

---

## 11. Известные ограничения

- **Правила по имени процесса.** Совпадение идёт по имени файла: любой процесс с именем `chrome.exe` получит канал, назначенный Chrome. От случайностей защищает, от намеренного обхода — нет.
- **Только Windows.** Завязано на wintun, PowerShell 5.1 и UAC.
- **VPN не свой.** Узлы берутся из клиента Sota. Нет Sota — нет канала VPN (остальные работают).
- **Применение требует перезапуска туннеля.** Claude на несколько секунд закрывается — иначе он мог бы утечь мимо правил в момент пересборки.
- **Статистика трафика по клиентам** в админке пока не выводится. Данные уже пишутся в `access.log` с именами — осталось только агрегировать.
