From 4bd66fb1437d0204a385ee2da929f22b80b2d017 Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Tue, 15 Sep 2026 17:35:14 +0600 Subject: [PATCH] [2026-09-15] eagle: family/how-to/truenas-infrastructure.md personal/tech/vless-space-subscription-egress.md --- family/how-to/truenas-infrastructure.md | 47 +++++++++-- .../tech/vless-space-subscription-egress.md | 77 ++++++++++++++++++- 2 files changed, 112 insertions(+), 12 deletions(-) diff --git a/family/how-to/truenas-infrastructure.md b/family/how-to/truenas-infrastructure.md index b735efd4..6a967239 100644 --- a/family/how-to/truenas-infrastructure.md +++ b/family/how-to/truenas-infrastructure.md @@ -26,6 +26,8 @@ > | `routing.rules` | `{"user":["vless-space"],"balancerTag":"space-balancer"}` | > | клиенты | `user1`, `kraken-user`, `vless-space` — целы | > +> ✅ **Доки актуализированы 2026-09-15** — сняты устаревшие статусы «`vless-space` НЕ СОЗДАН / БД откачена» и «авто-обновление не начато». +> > ### 🔑 ТРИ ПИТФОЛЛА БАЛАНСИРОВЩИКА — все три обязательны > > Ошибка `app/dispatcher: non existing outTag: space-balancer` вызывалась **тремя независимыми причинами** (каждая воспроизведена и снята отдельно): @@ -82,13 +84,15 @@ > # ожидается НЕ 90.189.160.148 > ``` > -> 🔴 **ДОСТУП:** `/mnt/RED_2TB/docker/vless-proxy/` — `root:root 755`, `config.json` примонтирован `:ro`. **`truenas_admin` писать НЕ может** (`touch` → Permission denied; `sudo` требует пароль; `root@` — publickey denied). Файл правит **Alex от root**. Агент готовит конфиг локально и отдаёт целиком. +> 🔴 **ДОСТУП (проверено 2026-09-15):** `/mnt/RED_2TB/docker/vless-proxy/` — `root:root 755`, `config.json` примонтирован `:ro`, внутри контейнера `/etc/xray/config.json` тоже `Read-only file system`. **`truenas_admin` править НЕ может** (`touch` → Permission denied; `sudo` требует пароль; `root@192.168.2.197` → publickey denied). Файл правит **только Alex от root**; агент готовит конфиг локально (`~/tmp-xray-space/vless-proxy-config-new.json`) и отдаёт целиком. +> +> ⚠️ **`docker compose up -d hermes-taiga` → `no such service`.** Сервис в `/mnt/RED_2TB/docker/hermes/docker-compose.yml` называется **`taiga`** (`hermes-taiga` — это `container_name`). Правильно: `docker compose up -d taiga`. > > 🔴 **Прежний хард-вывод «3x-ui нельзя править снаружи» — ОКОНЧАТЕЛЬНО ОПРОВЕРГНУТ.** SQLite-путь работает при двух условиях: (1) в `xrayTemplateConfig` нет инбаунда (только `api`), (2) БД правится локально на Mac и кладётся файлом с `rm -f *.db-wal *.db-shm` + `chown 950:root`. > > **⚠️ ОТДЕЛЬНАЯ НЕЗАКРЫТАЯ ПРОБЛЕМА — `kraken-user`:** не работает, потому что **сервер Kraken недоступен** (не связано с БД). Проверено 2026-09-15: `ssh-kraken.qentra.top` → `Connection timed out during banner exchange`; `kraken@10.99.1.2:22` → `Operation timed out`; DNS `kraken` → NXDOMAIN. Портал на TrueNAS жив (`xray-reverse-portal` Up, `12345`/`12346` LISTEN), но соединений от бриджа **ноль** → ждём восстановления Kraken (решение Alex «подождём, может оживет»). > -> **Остаточная задача (не начата):** авто-обновление списка серверов подписки. Outbound'ы `space-01…10` **статически вбиты в шаблон** — при смене списка у `profilegrid` всё сломается молча. Варианты: (A) cron-скрипт на NAS (sub → пересборка шаблона → рестарт), (B) штатная таблица `outbound_subscriptions` 3x-ui через панель. +> **✅ РЕШЕНО 2026-09-15 (штатная подписка).** Было: `space-01…10` статически вбиты в шаблон — при смене списка у `profilegrid` всё ломалось молча. Стало: штатная таблица **`outbound_subscriptions`** 3x-ui (`remark=vless-space`, `tag_prefix=sub1-`, `update_interval=600`) → **28 серверов `sub1-*`, авто-обновление**. Статика `space-01…10` **удалена**. Балансировщик `space-balancer`: `selector: ["sub1-"]`, `leastLoad`; наблюдение — **`burstObservatory`** с `subjectSelector: ["sub1-"]`. Ручная пересборка шаблона больше НЕ нужна. > > **Правила взаимодействия (Alex, 2026-09-15):** команды — плоские однострочники, **без `ssh … '…'`-обёртки**, **без `sleep N`**, **без кириллицы в bash**, без `execute_code`/python. Правку SQLite делать **локально на Mac**, потом заливать готовый файл. > @@ -367,11 +371,23 @@ arr, caddy, cups, filebrowser, gitea, hermes, immich, inpx-web, inpxer, library, > - ❌ **НЕТ «subscription channel» как отдельной сущности с ветками/каналами** (типа mihomo-«channel»/Nekoray-«channel»): в бинарнике `/app/x-ui` **нет ни одной строки `channel` в этом смысле** и нет API-роутов каналов. Есть категории **`subJsonURI` / `subJsonPath`** — это JSON/Mihomo-формат той же подписки, `XUI`/`subClashEnableRouting` — mihomo-специфика. То есть «channel» = **ссылка подписки + клиентский auto-update**, отдельного механизма в панели нет. > - Роуты панели по темам подписок (из `strings /app/x-ui`): `/panel/api/clients/sub`, `/panel/api/sub-balancers*`, `/panel/api/xray/outbound-subs*`. (`outbound-subs` = панель сама тянет ВНЕШНИЕ подписки в свои outbound — противоположное направление, не клиентская подписка.) > -> **🔴 ОТКРЫТЫЙ ВОПРОС БЕЗОПАСНОСТИ (задан Alex 2026-09-15, решения НЕТ):** путь `/sub/` отдаётся **без авторизации** — `/sub/abc` тоже даёт 200. Кто знает `subId` — получает рабочий ключ. Возможный фикс: подписка по токену/`subUpdates`-проверке в настройках панели либо короткий `subId` + ротация. **Ничего не менялось, ждём решения.** +> ✅ **ОТКРЫТЫЙ ВОПРОС БЕЗОПАСНОСТИ (задан Alex 2026-09-15, решения НЕТ):** путь `/sub/` отдаётся **без авторизации** — `/sub/abc` тоже даёт 200. Кто знает `subId` — получает рабочий ключ. Возможный фикс: подписка по токену/`subUpdates`-проверке в настройках панели либо короткий `subId` + ротация. **Ничего не менялось, ждём решения.** +> +> ### 🔴 ПИТФОЛЛ: подмена `x-ui.db` при ЖИВОМ контейнере ТЕРЯЕТ панельные данные (2026-09-15) +> +> **Как было потеряно:** снят `x-ui.db` при работающем контейнере → `docker stop` (панель сбросила WAL в файл) → поверх положен снятый ранее файл → **запись `outbound_subscriptions` уничтожена**. +> +> Панель пишет в `-wal`; `sqlite3 x-ui.db "SELECT …"` снаружи показывает **устаревшие** данные (0 записей при живой подписке). +> +> **Правильный порядок:** `docker stop` **ДО** скачивания БД. Если остановить нельзя — читать WAL через `strings /mnt/RED_2TB/docker/xray-admin/x-ui.db-wal` (не через `sqlite3` на файле). Признак: `SELECT COUNT(*) FROM outbound_subscriptions` → `0`, а панель запись показывает. +> +> **Восстановление:** заново добавить подписку в UI (`Xray → Outbound Subscriptions`). Бэкапы БД старше правки пусты — URL подписки в доке не хранится. --- -> ## ✅ РЕАЛИЗАЦИЯ 2026-09-15: клиент `vless-space` на ВНЕШНЕЙ outbound-подписке — АРТЕФАКТЫ ГОТОВЫ, ПРИМЕНЕНИЕ НЕ ВЫПОЛНЕНО +> ## ⚠️ ИСТОРИЯ (2026-09-15, ранние попытки) — АРТЕФАКТЫ ГОТОВЫ, ПРИМЕНЕНИЕ НЕ ВЫПОЛНЕНО +> +> **⚡ ВНИМАНИЕ: это ЛЕТОПИСЬ, а не текущее состояние.** Финальный статус — в шапке документа: клиент `vless-space` **СОЗДАН И РАБОТАЕТ**, egress через штатную подписку `sub1-*` (28 серверов, авто-обновление 600 с). Ниже — разбор промежуточных попыток (все провалившиеся), оставлен для контекста и как источник грабель. > > **Задача Alex:** добавить в `xray-admin` третьего клиента `vless-space`, чей трафик идёт через **внешнюю** Xray-подписку `profilegrid.net` с авто-обновлением серверов. `user1` и `kraken-user` **НЕ трогать**. Серверы — **«авто брать»** (все, с балансировкой). > @@ -495,8 +511,23 @@ arr, caddy, cups, filebrowser, gitea, hermes, immich, inpx-web, inpxer, library, > > --- > -> ## ⏳ ПОДЗАДАЧА 2026-09-15: `hermes-taiga` переключить с мёртвого `vless-proxy` (НЕ ВЫПОЛНЕНА) - +> ## ✅ ПОДЗАДАЧА 2026-09-15: `hermes-taiga` → `vless-proxy` → `xray-admin` — **ВЫПОЛНЕНА** +> +> **Цепочка:** `hermes-taiga → vless-proxy:1080 → vpn.mallexxx.duckdns.org:443 → xray-admin → 28 × sub1-* → интернет` +> +> `vless-proxy` переключён с мёртвого `v.qentra.top` на `vpn.mallexxx.duckdns.org` с клиентом **`vless-space`** (`a792c483-07e2-4723-9c50-78054c0abc07`), path `/vless`. Проверено фактом: egress `104.28.219.140` / `188.239.191.18` ≠ `90.189.160.148`. +> +> **Env `hermes-taiga` (`TELEGRAM_PROXY`, `DISCORD_PROXY` = `socks5://vless-proxy:1080`) не менялся** — рестарт не нужен, SOCKS-соединения устанавливаются на каждый запрос. +> +> ⚠️ **ПИТФОЛЛ проверки:** `wget` **не умеет SOCKS5** — `docker exec vless-proxy wget -qO- https://api.ipify.org` вернёт **локальный** IP контейнера `90.189.160.148` и даст ложный вывод «direct». Проверять ТОЛЬКО через SOCKS: +> ```bash +> docker run --rm --network hermes_taiga_net alpine sh -c \ +> "apk add -q curl; curl -s --max-time 20 --socks5-hostname vless-proxy:1080 https://api.ipify.org" +> ``` +> +> ⚠️ **ПИТФОЛЛ доступа:** `/mnt/RED_2TB/docker/vless-proxy/` — `root:root 755`, `config.json` примонтирован `:ro`, внутри контейнера `/etc/xray/config.json` тоже `Read-only file system`. **`truenas_admin` править НЕ может** (`touch` → Permission denied; `sudo` требует пароль; `root@` → publickey denied). Правку делает **Alex от root**; агент готовит конфиг локально (`~/tmp-xray-space/vless-proxy-config-new.json`). +> +> ⏳ **Осталось (не закрыто):** Telegram-адаптер `hermes-taiga` при `TELEGRAM_PROXY` уходил в ветку `TelegramFallbackTransport` (прямое подключение по fallback-IP) вместо честного SOCKS. Симптом — `Connecting (attempt 1/8)` и **тишина**, без `Proxy detected` в логе. Попытка фикса через `HERMES_TELEGRAM_DISABLE_FALLBACK_IPS=1` **не помогла**, переменная убрана. **Telegram РАБОТАЕТ** (проверено Alex), т.е. проблема саморазрешилась либо была в тайминге рестартов. > > **Факт:** `hermes-taiga` ходит **НЕ** через `xray-admin`/`user1`, а через **отдельный** контейнер `vless-proxy`. > - env: `TELEGRAM_PROXY=socks5://vless-proxy:1080`, `DISCORD_PROXY=socks5://vless-proxy:1080` @@ -504,7 +535,7 @@ arr, caddy, cups, filebrowser, gitea, hermes, immich, inpx-web, inpxer, library, > - `vless-proxy`: `teddysun/xray:latest`, Up, SOCKS `:1080` + HTTP `:1081`, **единственный outbound → мёртвый `v.qentra.top:443`** (VPS удалён) > - **⇒ Telegram/Discord бота сейчас без сети.** > -> **Готовый план (4 поля, `user1` и `kraken-user` не трогаются):** +> **Файлы `/mnt/RED_2TB/docker/vless-proxy/`:** `config.json` (1091 б), `config.json.bak-20260707-102922`, `config.json.bak-switch-ws-client-20260707-103233`, `docker-compose.yml` (336 б). > | Поле в `/mnt/RED_2TB/docker/vless-proxy/config.json` | Сейчас | Станет | > |---|---|---| > | `outbounds[0].settings.vnext[0].address` | `v.qentra.top` | `vpn.mallexxx.duckdns.org` | @@ -576,7 +607,7 @@ arr, caddy, cups, filebrowser, gitea, hermes, immich, inpx-web, inpxer, library, |---|---|---|---| | `user1` | `68c5cy5n5ui138yh` | `https://vpn-panel.mallexxx.duckdns.org/sub/68c5cy5n5ui138yh` | TrueNAS `90.189.160.148` | | `kraken-user` | `f43074a029dc656e` | `https://vpn-panel.mallexxx.duckdns.org/sub/f43074a029dc656e` | Kraken `92.62.70.41` | -| `vless-space` | `24df9391356b48ff` | `https://vpn-panel.mallexxx.duckdns.org/sub/24df9391356b48ff` | подписка `profilegrid.net` (10 серверов, `space-balancer` leastPing) — ❌ **НЕ СОЗДАН**, БД откачена 2026-09-15 | +| `vless-space` | `24df9391356b48ff` | `https://vpn-panel.mallexxx.duckdns.org/sub/24df9391356b48ff` | ✅ **СОЗДАН 2026-09-15**, egress через подписку `profilegrid.net` (**28 серверов `sub1-*`**, `space-balancer` **leastLoad** + `burstObservatory`) | - Sub-сервер отдаёт **base64-список** `vless://…` (проверено: HTTP 200, `text/plain`). Пример тела: `vless://ce320965-…@vpn.mallexxx.duckdns.org:443?encryption=none&host=vpn.mallexxx.duckdns.org&path=%2Fvless&security=tls&type=ws#vless-ws-user1`. - **`/sub/` отдаётся БЕЗ авторизации** — любой, кто знает `subId`, получает рабочий ключ. Открытый вопрос безопасности. diff --git a/personal/tech/vless-space-subscription-egress.md b/personal/tech/vless-space-subscription-egress.md index 986f5055..19bab49c 100644 --- a/personal/tech/vless-space-subscription-egress.md +++ b/personal/tech/vless-space-subscription-egress.md @@ -1,7 +1,7 @@ --- title: vless-space — клиент 3x-ui с egress через external-подписку created: 2026-09-15T00:00:00.000Z -updated: '2026-09-15T22:30:00.000Z' +updated: '2026-09-15T23:59:00.000Z' type: tech namespace: personal tags: @@ -10,13 +10,17 @@ tags: - x-ui - subscription - outbound + - outbound_subscriptions - profilegrid - truenas - - space - balancer - leastLoad - balancerTag - sampling + - burstObservatory + - vless-proxy + - hermes-taiga + - wal confidence: high status: done-egress-via-subscription-working related: @@ -644,8 +648,9 @@ curl -sk -o /dev/null -w "sub: %{http_code}\n" https://vpn-panel.mallexxx.duckdn - [ ] После появления клиента — routing-правило на `space-balancer` **тоже через панель** (Xray → Routing) - [ ] Проверить end-to-end: egress IP ≠ `90.189.160.148` (TrueNAS) и ≠ `92.62.70.41` (Kraken) - [ ] Решить вопрос с авторизацией на sub-ссылках (открыты без авторизации) -- [ ] Обновить [[family/how-to/truenas-infrastructure]] (новый клиент + балансировщик) -- [ ] **Отдельная задача, НЕ начата:** `hermes-taiga` ходит через `vless-proxy`, чей outbound указывает на **мёртвый** `v.qentra.top` (VPS удалён). Переключение на живой сервер — правка 5 полей в `/mnt/RED_2TB/docker/vless-proxy/config.json` (таблица в [[personal/tech/xray-outbound-subscription-3xui]] §попутные находки). Alex спрашивал — **ответ: да, можно**. +- [x] ~~Обновить [[family/how-to/truenas-infrastructure]] (новый клиент + балансировщик)~~ → **сделано 2026-09-15** +- [x] ~~**Отдельная задача:** `hermes-taiga` ходит через `vless-proxy`, чей outbound указывает на **мёртвый** `v.qentra.top`~~ → **✅ ВЫПОЛНЕНО 2026-09-15.** `vless-proxy` переключён на `vpn.mallexxx.duckdns.org:443` + `/vless`, клиент **`vless-space`** (`a792c483-07e2-4723-9c50-78054c0abc07`). Проверено фактом: egress `104.28.219.140` / `188.239.191.18` ≠ `90.189.160.148`. См. §«`vless-proxy` → `xray-admin`» ниже. +- [ ] ⏳ **Осталось (не закрыто):** Telegram-адаптер `hermes-taiga` уходил в ветку `TelegramFallbackTransport` (прямой коннект по fallback-IP) вместо SOCKS, несмотря на `TELEGRAM_PROXY`. Симптом — `Connecting (attempt 1/8)` и тишина, без `Proxy detected` в логе. Попытка фикса `HERMES_TELEGRAM_DISABLE_FALLBACK_IPS=1` **не помогла**, переменная убрана. **Telegram РАБОТАЕТ** (подтверждено Alex) — саморазрешалось, вероятно тайминг рестартов. ## 🔴🔴 ГЛАВНАЯ НАХОДКА СЕССИИ (2026-09-15, позже в тот же день): `leastPing` В XRAY 26.x НЕ РАБОТАЕТ — НУЖЕН `leastLoad` @@ -773,6 +778,70 @@ docker start xray-admin ``` **Исходное состояние (до всей работы):** `/mnt/RED_2TB/docker/backups/xray-admin-before-vless-space-20260915-012057/` +## 🔗 `vless-proxy` → `xray-admin` (2026-09-15) — ВЫПОЛНЕНО + +**Задача:** `vless-proxy` (SOCKS `:1080` + HTTP `:1081`) смотрел на **мёртвый** `v.qentra.top` (VPS удалён) → `hermes-taiga` (Telegram/Discord) без сети. Переключить на живой `xray-admin`. + +**Что изменено** — `/mnt/RED_2TB/docker/vless-proxy/config.json`: + +| Поле | Было | Стало | +|---|---|---| +| `outbounds[0].settings.vnext[0].address` | `v.qentra.top` | `vpn.mallexxx.duckdns.org` | +| `…vnext[0].users[0].id` | `2D9F24C4-21FE-4784-9843-F11C384DA67A` | `a792c483-07e2-4723-9c50-78054c0abc07` (`vless-space`) | +| `streamSettings.tlsSettings.serverName` | `v.qentra.top` | `vpn.mallexxx.duckdns.org` | +| `streamSettings.wsSettings.path` | `/qentra` | `/vless` | +| `streamSettings.wsSettings.headers.Host` | `v.qentra.top` | `vpn.mallexxx.duckdns.org` | + +`port: 443`, `security: tls`, `network: ws` — без изменений. + +**Выбор клиента — `vless-space`, НЕ `user1`.** Через `user1` egress = IP TrueNAS (`90.189.160.148`); через `vless-space` egress = IP подписки (нероссийский). Для Telegram/Discord нужен второй. + +**Итоговая цепочка:** +``` +hermes-taiga → vless-proxy:1080 → vpn.mallexxx.duckdns.org:443 → xray-admin → 28 × sub1-* → интернет +``` +Env `hermes-taiga` (`TELEGRAM_PROXY`, `DISCORD_PROXY` = `socks5://vless-proxy:1080`) **менять не нужно** — SOCKS-соединения устанавливаются на каждый запрос, рестарт не требуется. + +**Проверено фактом:** `104.28.219.140` / `188.239.191.18` ≠ `90.189.160.148` ✅ + +### 🔴 ПИТФОЛЛ ПРОВЕРКИ: `wget` не умеет SOCKS5 + +```bash +# ❌ ЛОЖНЫЙ РЕЗУЛЬТАТ — wget идёт напрямую, минуя SOCKS +docker exec vless-proxy wget -qO- https://api.ipify.org # → 90.189.160.148 (обман!) + +# ✅ ПРАВИЛЬНО — только через SOCKS-прокси +docker run --rm --network hermes_taiga_net alpine sh -c \ + "apk add -q curl; curl -s --max-time 20 --socks5-hostname vless-proxy:1080 https://api.ipify.org" +``` + +Также проверять `httpx` из venv taiga (доказательство, что SOCKS работает из python-стека): +```bash +docker exec hermes-taiga /opt/hermes/.venv/bin/python3 -c " +import asyncio, httpx +async def m(): + async with httpx.AsyncClient(proxy='socks5://vless-proxy:1080', timeout=15) as c: + r = await c.get('https://api.telegram.org'); print('OK', r.status_code) +asyncio.run(m())" +# → OK 302 +``` + +### 🔴 ПИТФОЛЛ ДОСТУПА: правку делает только Alex от root + +`/mnt/RED_2TB/docker/vless-proxy/` — `root:root 755`, `config.json` примонтирован `:ro`, внутри контейнера `/etc/xray/config.json` тоже `Read-only file system`. **`truenas_admin` править НЕ может:** `touch` → Permission denied; `sudo` требует пароль; `root@192.168.2.197` → publickey denied. + +Проверка прав (факт): +```bash +ssh truenas_admin@192.168.2.197 'ls -ld /mnt/RED_2TB/docker/vless-proxy; touch /mnt/RED_2TB/docker/vless-proxy/.wtest 2>&1 || echo CANNOT_WRITE' +ssh truenas_admin@192.168.2.197 'docker exec vless-proxy sh -c "touch /etc/xray/config.json 2>&1 || echo READONLY"' +``` + +**Рабочий приём:** агент готовит конфиг **локально на Mac** (`~/tmp-xray-space/vless-proxy-config-new.json`), отдаёт целиком; Alex копирует и делает `docker restart vless-proxy`. + +### ⚠️ ПИТФОЛЛ: `docker compose up -d hermes-taiga` → `no such service` + +Сервис в `/mnt/RED_2TB/docker/hermes/docker-compose.yml` называется **`taiga`**, не `hermes-taiga` (это `container_name`). Правильно: `docker compose up -d taiga`. + ## Связанные заметки - [[family/plans/reverse-xray-3xui-kraken]] — reverse-туннель к Кра́кену, история compose-инцидента