Files
obsidian-vault/family/plans/reverse-xray-3xui-kraken.md
T

239 lines
23 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Reverse Xray (3x-ui) — TrueNAS ↔ Kraken
> Создано: 2026-09-01. Цель: проксировать трафик локальных клиентов (сеть TrueNAS 192.168.2.x) через TrueNAS → Kraken → интернет. **Kraken = точка выхода (exit node).** TrueNAS = bridge/контроллер.
## Архитектура
```text
ЛОКАЛЬНЫЕ КЛИЕНТЫ (192.168.2.x)
│ подключаются к прокси TrueNAS:1080/1081 (SOCKS/HTTP) ИЛИ на поддомен
TRUENAS = 3x-ui (Xray-сервер, bridge/контроллер) — белый IP, mallexxx.duckdns.org
│ принимает клиентский трафик; reverse-канал к Kraken
▼ ▲
KRAKEN = Xray-клиент (outbound reverse) + exit node — держит исходящий канал к TrueNAS
интернет
```
- **TrueNAS** (3x-ui): принимает от локальных клиентов + держит reverse-вход, куда подключается Kraken.
- **Kraken**: сам **инициирует** канал к TrueNAS (за NAT, не может принимать), получает по нему трафик клиентов, отпускает в интернет.
- Кра́кен за NAT ⇒ направление канала **от Kraken к TrueNAS** (Xray reverse).
## Ключевые факты (прояснены)
1. **На 443 у TrueNAS — Caddy** (reverso-proxy, валидные LE-серты), НЕ Xray REALITY. Хостовый маппинг: `0.0.0.0:8443→443` (контейнер), `2019` (admin), `8088→80`.
2. **Xray на TrueNAS** раньше был задуман как 3x-ui:
- База `/mnt/RED_2TB/docker/xray-admin/x-ui.db` (3x-ui), inbound `vless-ws` port `10095`, tag `in-10095-tcp`, path `/vless`, host `vpn.mallexxx.duckdns.org`, protocol vless.
- Композ-файла в `xray-admin/` нет; контейнер НЕ запущен.
3. **Caddyfile** уже проксирует (мёртвые ссылки на `xray-admin`):
- `vpn.mallexxx.duckdns.org``@ws path /vless``xray-admin:10095`
- `vpn-panel.mallexxx.duckdns.org``xray-admin:443` / `xray-admin:2053` (path /sub/*)
- Сертификаты для этих поддоменов уже выданы (DNS на TrueNAS IP).
4. **`vless-proxy`** (teddysun/xray) на TrueNAS — КЛИЕНТ: слушает 1080/1081 (SOCKS/HTTP), outbound на мёртвый `v.qentra.top:443` (VPS удалён). Используется Hermes-Taiga.
5. **VPS qentra.top (91.207.28.205) УДАЛЁН.** Вся старая VLESS+REALITY инфраструктура на нём недоступна.
6. Открытые порты TrueNAS наружу: **22, 443** (8443 ведёт внутрь контейнера Caddy:443 → но Caddy обрабатывает HTTPS-домены).
## Образ 3x-ui
- Официальный: `ghcr.io/mhsanaei/3x-ui:latest`
- Контейнер должен называться **`xray-admin`** (как в Caddyfile) и быть в сети **`caddy_default`** (чтобы Caddy резолвил имя).
- Volume: `/mnt/RED_2TB/docker/xray-admin:/etc/x-ui` (там лежит готовая `x-ui.db`).
- Порт панели: 54321 (web UI, через Caddy поддомен `vpn-panel.mallexxx.duckdns.org`).
- VLESS inbound 10095 принимается извне через Caddy `vpn.mallexxx.duckdns.org/vless` (WS), НО для reverse к Kraken нужен подход через панель.
## Композ-файл
Файл: `/mnt/RED_2TB/docker/xray-admin/docker-compose.yml`
```yaml
services:
xray-admin:
image: ghcr.io/mhsanaei/3x-ui:latest
container_name: xray-admin
restart: unless-stopped
volumes:
- /mnt/RED_2TB/docker/xray-admin:/etc/x-ui
environment:
- XRAY_VMESS_AEAD_FORCED=false
networks:
- caddy_default
ports:
- "54321:54321" # 3x-ui панель (web UI)
networks:
caddy_default:
external: true
```
⚠️ ПОРТЫ 10095 и 2053/443 НЕ пробрасывать на host отдельно — Caddy стоит перед 443 и маршрутизирует /vless → xray-admin:10095 по имени в общей сети. Если нужно наружу снаружи (не через Caddy), проброс отдельный — обсудить.
## Сеть: reverse к Kraken
`xray-admin` должен быть в сети `caddy_default` — там же Caddy. Проверено: caddy_default содержит caddy, syncthing, webdav, gitea.
## Reverse-схема (Xray portal/bridge) — 2026-09-01, спроектировано
Целевое: локальные клиенты сети TrueNAS (192.168.2.x) выходят в интернет через Kraken.
Роли Xray reverse (по эталону Xray-examples/ReverseProxy):
- **Kraken = BRIDGE** (reverse bridges) — держит исходящий канал к TrueNAS, публикует "интернет-выход" (freedom).
- **TrueNAS = PORTAL** (reverse portals) — принимает от локальных клиентов (external-inbound) и пересылает в Kraken по reverse-каналу (interconn).
Конкретные порты/транспорт:
| Компонент | Хост | Контейнер/роль | Транспорт | Вход/выход |
|---|---|---|---|---|
| portal | TrueNAS | `xray-reverse-portal` | VLESS-WS | interconn `:12346` → Caddy path `/rvs`; external `:12345` для клиентов сети |
| bridge | Kraken | `xray-reverse-bridge` | VLESS-WS | interconn → `vpn.mallexxx.duckdns.org` path `/rvs`; свобода → интернет |
Транспорт: VLESS + WebSocket (т.к. снаружи TrueNAS только 443 через Caddy; WS подходит для reverse поверх outbound). Отдельный путь Caddy `/rvs` (не `/vless` 3x-ui) → `xray-reverse-portal:12346`, чтобы не смешивать с inbound 3x-ui.
Caddy правка: `vpn.mallexxx.duckdns.org` добавить маршрут `@rvs path /rvs``reverse_proxy @rvs xray-reverse-portal:12346`.
## Статус деплоя (2026-09-01)
**3x-ui развёрнут на TrueNAS и работает:**
- Контейнер `xray-admin` (ghcr.io/mhsanaei/3x-ui:latest, **3.7.0**, Xray 26.7.28) в сети `caddy_default`, volume `/mnt/RED_2TB/docker/xray-admin:/etc/x-ui`.
- Панель web UI: **`https://vpn-panel.mallexxx.duckdns.org/` → HTTP 200** (Caddy резолвит `xray-admin:2053`).
- Sub-сервер: `[::]:443` (путь /sub), панель `[::]:2053` — как в Caddyfile.
- Inbound: `vless-ws` port **10095**, tag `in-10095-tcp`, path `/vless`, host `vpn.mallexxx.duckdns.org` (Caddy path /vless → xray-admin:10095).
- 3x-ui **поддерживает reverse** (в бинарнике `clientReverseTags`) — настройка через панель.
- Бэкап: `/mnt/RED_2TB/docker/backups/reverse-xray-3xui-20260901-113625/` (Caddyfile + x-ui.db + docker-inventory).
### Фактически развёрнутый compose (deployed на TrueNAS)
```yaml
services:
xray-admin:
image: ghcr.io/mhsanaei/3x-ui:latest
container_name: xray-admin
hostname: xray-admin
restart: unless-stopped
environment:
- TZ=Asia/Novosibirsk
- PUID=950
- PGID=950
volumes:
- /mnt/RED_2TB/docker/xray-admin:/etc/x-ui
ports:
- "54321:54321" # 3x-ui web UI (внутри панель реально на 2053)
networks:
- caddy_default
networks:
caddy_default:
external: true
```
> Черновик выше (секция «Композ-файл») — предварительный; фактический файл на TrueNAS содержит `hostname`, `TZ`, `PUID/PGID`. Панель внутри слушает **2053** (не 54321) — это то, что Caddyfile проксирует через `vpn-panel`. Хостовый 54321-проброс не используется панелью (панель = 2053), можно убрать.
**Следующий шаг:** ✅ Выполнено — reverse развёрнут (см. ниже). Основной doc архитектуры: `personal/tech/xray-reverse-tunnel-kraken-truenas.md`.
## Reverse деплой — ПОЛНЫЙ СТАТУС (2026-09-01) — РЕШЕН переезд на TCP+REALITY
### 🔀 РЕШЕНИЕ: WS → прямой TCP+REALITY (принято в сессии 2026-09-01)
WS-вариант reverse НЕ пропускал payload (curl через SOCKS → 000; portal логировал `accepted tcp:... [local -> reverse-out]`, но bridge не получал). Официальный Xray-reverse пример = прямой TCP + flow `xtls-rprx-vision`. Alex согласовал проброс порта → переводим reverse канал Kraken↔TrueNAS на **прямой TCP+REALITY** порт 12346.
**REALITY-ключи (для interconn :12346):** server PrivateKey `0JTjeirfviDqCr63wSnisvU7DV6SpR9_9V2l_EUHmkk`; server PublicKey (для bridge) `GhsphQLT_0fwOvK45MHeAgG3sBQsFtw7lQfUIbrLMQU`; shortId `1451ef281caf5905`; serverName/SNI `www.cloudflare.com`; flow `xtls-rprx-vision`.
**⚠️ Pitfall Xray 26.x:** VLESS без TLS/шифрования к публичному адресу ЗАПРЕЩЁН (`vless without TLS or other encryption is prohibited unless the server address is a private IP`). → bridge TCP-VLESS обязателен с REALITY.
Обновлённые конфиги (оба `Configuration OK` при `xray run -test`):
- **portal** `/mnt/RED_2TB/docker/reverse-portal/config.json`: interconn `:12346` VLESS-TCP reality (dest www.cloudflare.com:443, client a81c3179..., flow xtls-rprx-vision, reverse tag reverse-out); local `:12345` SOCKS; routing local→reverse-out.
- **bridge** `/home/kraken/xray-reverse/config.json`: outbound `conn` VLESS simplified → mallexxx.duckdns.org:12346, flow, reality (publicKey=server PublicKey, shortId, serverName www.cloudflare.com, fingerprint random), reverse tag reverse-in; direct=freedom; routing reverse-in→direct.
- **compose portal**: добавлен проброс `- "12346:12346"`.
### Доступ к роутеру OpenWrt (TrueNAS сети) — из `truenas-access`
- OpenWrt = main router сети 192.168.2.0/24, SSH `root@192.168.2.2`, пароль root **`1316261`**. Доступ с TrueNAS через docker+sshpass.
- ✅ Бэкап firewall OpenWrt: `/mnt/RED_2TB/docker/backups/openwrt-firewall-20260901-130558.txt` (212 строк).
- Порт-форвардинг: `uci add firewall redirect` ... `src_dport``dest_ip=192.168.2.197` `dest_port` `target=DNAT`; `/etc/init.d/firewall reload`.
### ✅ ВНЕДРЕНО (2026-09-01, после согласия Alex) — TCP+REALITY переход выполнен
Все 4 шага перехода на TCP+REALITY **ВЫПОЛНЕНЫ**:
1. ✅ Пересоздан `xray-reverse-portal` на TrueNAS (compose `12345:12345` + `12346:12346`, config REALITY TCP). Проверено: `ss -tlnp``0.0.0.0:12346 LISTEN`.
2. ✅ OpenWrt DNAT добавлен: redirect `xray-reverse-12346`, `src_dport=12346``dest_ip=192.168.2.197:12346`, `target=DNAT`, `/etc/init.d/firewall reload``DNAT_ADDED`. Проверено: `mallexxx.duckdns.org:12346`**OPEN** извне.
3. ✅ Пересоздан `xray-reverse-bridge` на Kraken (config REALITY TCP). Reverse-канал снова ESTABLISHED: Kraken `172.24.0.2 → 90.189.160.148:12346 ESTABLISHED` + лог `common/mux: received request for udp:reverse:0`.
4.**Тест payload НЕ прошёл даже на TCP+REALITY**: `curl --socks5 127.0.0.1:12345 http://api.ipify.org` на TrueNAS → **всё ещё `code=000`** (прямой curl → 200). Portal: `accepted tcp:8.6.112.0:80 [local -> reverse-out]`, но bridge НЕ логирует приход TCP-payload (`no accepted/received` в `reverse-in`).
### ❌ Дополнительно пробовано: снятие `flow: xtls-rprx-vision`
- Убрал `flow: xtls-rprx-vision` с обеих сторон (portal interconn client + bridge conn outbound), пересоздал оба контейнера (оба `Configuration OK`).
- Результат: **по-прежнему `code=000`**. Reverse-канал устанавливается (`udp:reverse:0`), TCP-payload до bridge не доходит.
- **Вывод: проблема НЕ в `flow` и НЕ в WS-транспорте — даже на «каноничном» TCP+REALITY payload между portal-reverse-out и bridge-reverse-in не передаётся.** Ранее выдвинутая гипотеза (WS не пропускает reverse-payload) **опровергнута** переходом на TCP.
### 💡 Обновлённая гипотеза (непроверенная)
Reverse-канал (mux `udp:reverse:0`) стабильно НЕ доставляет инициированный portal'ом inbound TCP-payload (из outbound `reverse-out`). Возможные пути решения, НЕ испробованные:
- Включить `sniffing` (http/tls/quic) на portal inbound `local` (для доменов) — routing по домену в reverse-out.
- Проверить, что свободе на portal нужен как placeholder («freedom outbound must remain, otherwise reverse-out becomes default») — НО это про обратное; тут reverse-out ВЫБРАН явно в routing.
- Возможно, для этой версии reverse требует, чтобы на portal входящий от bridge VLESS был НЕ same как клиент с reverse tag — либо VLESS reverse не пробрасывает произвольный inbound SOCKS-трафик.
- Альтернатива: Kraken тянет свой Xray-SOCKS, а TrueNAS ходит на него обычным VLESS-клиентом (простой исходящий прокси, БЕЗ reverse) — reverse может быть избыточен/несовместим здесь.
**Статус: задание НЕ завершено — end-to-end через reverse НЕ работает. Следующая сессия: продолжить с обновлённой гипотезы (sniffing / пересмотр роли reverse для исходящего прокси клиентов сети TrueNAS).**
### ⚠️ Kraken status — диск/докер были нестабильны
- Несколько `System is booting up` (pam_nologin) — Kraken перезагружался из-за USB-диска в цикле enumeration (`device descriptor read/64 error -110`, `device not accepting address error -62`, `[sda] Read Capacity(10) failed`, `0 B`).
- Итог: диск появился, Docker `active`, **30 образов целы, 0 контейнеров** (контейнеры потеряны, data-root на HDD).
- Docker Root Dir Kraken: `/srv/dev-disk-by-uuid-6194539b-.../docker-data` (UUID **6194539b**, не 49e8f586).
- Прямой интернет Kraken работает (api.ipify → 92.62.70.41). Контейнеры Kraken (jellyfin/transmission/radarr/hermes-kraken...) НЕ восстановлены — отдельная задача при необходимости.
### Историческая справка (WS-версия, суперсидившаяся)
- Канал до перехода: Kraken→TrueNAS `172.24.0.2 → 90.189.160.148:443 ESTABLISHED`; portal `172.16.1.7:12346 ← Caddy 172.16.1.3 ESTABLISHED`; bridge лог `common/mux: received request for udp:reverse:0`. payload ❌ НЕ проходил (причина перехода на TCP).
#### Развёрнутые контейнеры (WS-версия, историческая справка)
**TrueNAS — `xray-reverse-portal`** (VLESS/W S, reverse portal): `/mnt/RED_2TB/docker/reverse-portal/`
- compose в `/mnt/RED_2TB/docker/reverse-portal/docker-compose.yml`, image `teddysun/xray:latest` (Xray 26.7.28)
- конфиг `config.json` (portal reverse):
- inbound `interconn`: VLESS на `:12346`, ws path `/rvs`, host `vpn.mallexxx.duckdns.org`, client `a81c3179-312b-4c5e-8a46-6bf3c30c2941`, `"reverse":{"tag":"reverse-out"}`
- inbound `local`: SOCKS на `:12345` (для клиентов сети TrueNAS), `udp:true`
- routing: `inboundTag:["local"] → outboundTag:"reverse-out"`
- outbounds: `freedom` (placeholder)
- проброс на host: **только `12345:12345`** (SOCKS для сети). Порт 12346 в docker-сети (к нему обращается Caddy по имени `xray-reverse-portal:12346`), наружу НЕ проброшен.
- сеть `caddy_default`, папку создавал через `docker run --rm -v /:/host alpine sh -c "mkdir -p ...; chown 950:950 ..."` (truenas_admin не имеет прав на `/mnt/RED_2TB/docker/`).
**TrueNAS — Caddy**: в блок `vpn.mallexxx.duckdns.org` добавлен маршрут `/rvs`:
```caddy
@rvs path /rvs
reverse_proxy @rvs xray-reverse-portal:12346
```
- Caddyfile на хосте: `/mnt/RED_2TB/docker/caddy/Caddyfile` (bind-mount; **нельзя `docker cp`**`device or resource busy`; править на хосте через alpine `cp /host/tmp/...`).
- Бэкап перед правкой: `Caddyfile.pre-reverse` в той же папке. Caddy валидация: `docker exec caddy caddy validate --config /tmp/Caddyfile.new` → "Valid configuration". Перезапуск: `docker restart caddy` (безопасно).
- Проверка маршрута: `curl -sk https://vpn.mallexxx.duckdns.org/rvs` → HTTP 400 (ожидаемо для WS-эндпоинта Xray при не-WS GET).
**Kraken — `xray-reverse-bridge`** (VLESS-WS reverse bridge): `/home/kraken/xray-reverse/`
- compose + `config.json` (bridge reverse):
- outbounds: `direct` = `freedom` + `"finalRules":[{"action":"allow","network":"tcp,udp","ip":["0.0.0.0/0"]}]`; `conn` = VLESS simplified style (НЕ vnext) → `vpn.mallexxx.duckdns.org:443`, ws `/rvs`, `"reverse":{"tag":"reverse-in"}`, security tls
- routing: `inboundTag:["reverse-in"] → outboundTag:"direct"`
- **Питфолл:** VLESS-outbound для reverse ДОЛЖЕН быть в *упрощённом* стиле (`settings.address/port/id/encryption/reverse`) — при использовании `vnext[]/users[]` Xray 26.x ругается: `VLESS users: please use simplified outbound's config style to use "reverse"`.
- `loglevel debug` включён для диагностики.
- Порт 443 на Kraken свободен; образ `teddysun/xray:latest` скачан.
### Развёрнутый reverse-канал — работает
- Kraken → TrueNAS: `netstat` на Kraken показывает `172.24.0.2:xxxxx → 90.189.160.148:443 ESTABLISHED`.
- Portal (TrueNAS): `::ffff:172.16.1.7:12346 ::ffff:172.16.1.3:52616 ESTABLISHED` (172.16.1.3 = Caddy, передающий WS от Kraken).
- Bridge логи: `common/mux: received request for udp:reverse:0` — reverse-канал установлен (TCP+UDP).
### ❌ НЕ работает: payload (end-to-end curl 000)
- `curl --socks5 127.0.0.1:12345 http://api.ipify.org` на TrueNAS → `code=000` (прямой curl с того же хоста → 200).
- Portal логи: `accepted tcp:8.47.69.0:80 [local -> reverse-out]` — portal отправил запрос в reverse-out.
- **Bridge НЕ логирует accepted/received для этого TCP-payload** — данные теряются между portal reverse-out и bridge reverse-in.
- Kraken имеет прямой интернет (api.ipify → `92.62.70.41`, code=200), поэтому проблема НЕ в egress Kraken.
### 💡 Гипотеза по неработающему payload (ВЕРОЯТНАЯ)
**WebSocket-транспорт НЕ пропускает reverse-payload должным образом.** В официальном Xray reverse-примере используется **прямой TCP** + `flow: xtls-rprx-vision` (REALITY) для канала bridge↔portal. Обратный UDP reverse создаётся (`udp:reverse:0`), но TCP-payload по WS не доходит до bridge.
**Решение (предполагаемое):** перевести reverse-канал на **прямой TCP**: на TrueNAS VLESS-inbound interconn на отдельном TCP-порту (напр. 12346 наружу) + проброс на роутере `внешний :12346 → 192.168.2.197:12346`; bridge VLESS-outbound → TCP (не WS). Выполнение отложено — Alex согласовал проброс порта («не проблема»), но внедрение не завершено.
## Порядок работ (отметки → фактический статус 2026-09-01, финал)
1. ✅ Бэкап: `/mnt/RED_2TB/docker/backups/reverse-xray-3xui-20260901-113625/` (Caddyfile + x-ui.db + docker-inventory).
2. ✅ Создан `/mnt/RED_2TB/docker/xray-admin/docker-compose.yml` (deployed версия — см. «Фактически развёрнутый compose»).
3. ✅ Поднят `docker compose up -d` → контейнер Up.
4. ✅ Проверено: панель `https://vpn-panel.mallexxx.duckdns.org/` → HTTP 200, inbound vless-ws:10095 активен.
5. ✅ Создан portal-контейнер `xray-reverse-portal` на TrueNAS (interconn :12346 + SOCKS `local`:12345) + Caddy маршрут `/rvs`. [Затем: переведён на TCP+REALITY, см. секции «Reverse деплой».]
6. ✅ Создан bridge-контейнер `xray-reverse-bridge` на Kraken (→ TrueNAS, egress direct). Reverse-канал установлен. [Затем: переведён на TCP+REALITY.]
7.**End-to-end НЕ работает** (curl через SOCKS 12345 → 000). Проверено на WS И на TCP+REALITY (flow и без flow) — payload от portal-reverse-out до bridge-reverse-in **не передаётся** (bridge не логирует приход TCP). Гипотеза про WS опровергнута. **Статус: задание НЕ завершено — продолжить со sniffing / пересмотром роли reverse (см. «Обновлённая гипотеза»).**
8. ⏳ Обновить Obsidian: truenas-infrastructure.md, kraken-access.md, vps-qentra.md. **TODO для следующей сессии.**
## Ограничения / риски
- Кра́кен в NAT ⇒ только исходящие соединения; reverse-канал держит Kraken.
- Не ломать существующий Caddy/домены (бэкапить Caddyfile, перезапуск Caddy аккуратно).
- `vless-proxy` (Hermes-Taiga) не трогать — настроен под local SOCKS.
- Внешний Xray-порт: через Caddy по пути `/vless` (WS). Для полноценного reverse возможно потребуется отдельный VLESS+Reality inbound на отдельном порту + проброс на роутере для Kraken — ДОБАВИТЬ после проверки связности панели.