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

23 KiB
Raw Blame History

Reverse Xray (3x-ui) — TrueNAS ↔ Kraken

Создано: 2026-09-01. Цель: проксировать трафик локальных клиентов (сеть TrueNAS 192.168.2.x) через TrueNAS → Kraken → интернет. Kraken = точка выхода (exit node). TrueNAS = bridge/контроллер.

Архитектура

ЛОКАЛЬНЫЕ КЛИЕНТЫ (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 /vlessxray-admin:10095
    • vpn-panel.mallexxx.duckdns.orgxray-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

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 /rvsreverse_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)

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_dportdest_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 -tlnp0.0.0.0:12346 LISTEN.
  2. OpenWrt DNAT добавлен: redirect xray-reverse-12346, src_dport=12346dest_ip=192.168.2.197:12346, target=DNAT, /etc/init.d/firewall reloadDNAT_ADDED. Проверено: mallexxx.duckdns.org:12346OPEN извне.
  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:

@rvs path /rvs
reverse_proxy @rvs xray-reverse-portal:12346
  • Caddyfile на хосте: /mnt/RED_2TB/docker/caddy/Caddyfile (bind-mount; нельзя docker cpdevice 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 — ДОБАВИТЬ после проверки связности панели.