Files
obsidian-vault/personal/tech/xray-reverse-tunnel-kraken-truenas.md
T

45 KiB
Raw Blame History

title, created, updated, type, namespace, tags, confidence, related, downgrade_to_26.4.25, verified_fix_2026_09_02
title created updated type namespace tags confidence related downgrade_to_26.4.25 verified_fix_2026_09_02
Xray Reverse Tunnel — Kraken ↔ TrueNAS 2026-09-01 2026-09-02 tech personal
xray
reverse
kraken
truenas
tunnel
networking
high
family/how-to/vps-qentra
family/how-to/truenas-infrastructure
family/how-to/kraken-access
family/how-to/rasputin-router
portal+bridge BOTH pinned to 26.4.25; required but insufficient by itself. Kraken bridge must use Docker network_mode: host; Docker bridge/NAT reset the VLESS reverse mux. REALITY+Vision verified end-to-end with Kraken egress.

Xray Reverse Tunnel — Kraken ↔ TrueNAS

Статус: ВНЕДРЕНО И ПРОВЕРЕНО END-TO-END (2026-09-02). TrueNAS SOCKS :12345 → VLESS Reverse TCP+REALITY+Vision → Kraken → internet работает. HTTP и HTTPS тесты оба вернули выходной IP Kraken 92.62.70.41. Истинная причина: Docker bridge/NAT на Kraken сбрасывал reverse mux; bridge должен работать с network_mode: host. Более ранние секции со статусом «не работает» и гипотезами #6612/#6242 сохранены ниже как история диагностики и суперсидированы секцией «Верифицированный фикс». Архитектурное решение: проксировать исходящий трафик локальных клиентов сети TrueNAS через TrueNAS → Kraken → интернет.

ВАЖНО (2026-09-02): xray-admin (3x-ui) на TrueNAS — это ОДНОВРЕМЕННО РАБОЧИЙ САМОСТОЯТЕЛЬНЫЙ Xray-VPN-сервер

Путаница в вопросе юзера выявила: vpn.mallexxx.duckdns.org:443 — это не только reverse-frontend, а полноценный Xray-сервер со своим собственным выходом в интернет (outbound freedom/direct → сразу через TrueNAS), НЕ зависящий от reverse-канала к Kraken. Это отдельная фича, параллельная reverse-туннелю.

  • Проверено end-to-end 2026-09-02 (временный xray-клиент с Mac): VLESS+WS через vpn.mallexxx.duckdns.org:443 → HTTP 200, выход IP 90.189.160.148 = TrueNAS. Контейнеры xray-admin (Up 21h) + caddy (Up 20h) живы.
  • Inbound in-10095-tcp (VLESS-WS): client id ce320965-6956-4759-84bb-7cb71cfc6252 (user1), security: none, path /vless, host vpn.mallexxx.duckdns.org. TLS терминирует Caddy → в клиенте network: ws + TLS на домен, без двойного TLS внутрь.
  • Полные параметры и pitfalls (вкл. удаление allowInsecure в Xray 26.7.28) — в family/how-to/truenas-infrastructure.md, раздел xray-admin.
  • Reverse к Kraken — это ОТДЕЛЬНЫЙ механизм (для проксирования локальных клиентов сети TrueNAS через Kraken-egress). Он теперь также внедрён и проверен; см. «Верифицированный фикс». 3x-ui-сервер остаётся независимым рабочим VPN-выходом через TrueNAS.

Контекст / Почему

  • VPS qentra.top (91.207.28.205) УДАЛЁН — вся прежняя Xray-инфраструктура на нём (VLESS+REALITY, OpenVPN, WebSocket v.qentra.top) больше не существует.
  • Нужен новый путь для выхода локальных клиентов сети TrueNAS в интернет через другую точку выхода (Kraken).
  • Белый IP есть только у TrueNAS (mallexxx.duckdns.org = 90.189.160.148).
  • Kraken за NAT, входящие не принимает — только исходящие соединения.

Принятая схема

Локальные клиенты (сеть TrueNAS, 192.168.2.x)
   │  шлют трафик на локальный прокси TrueNAS (SOCKS 1080 / HTTP 1081)
   ▼
TrueNAS  ←── контроллер / bridge (белый IP, mallexxx.duckdns.org), принимает
   │  TrueNAS заворачивает трафик в reverse-канал
   ▼  ▲
Kraken ──┘ держит ИСХОДЯЩИЙ reverse-канал к TrueNAS, отпускает трафик → интернет
   ▼
интернет

Тип решения: Xray reverse. Роли по Xray:

Узел Роль Держит канал? Выход в интернет?
TrueNAS bridge/контроллер (inbound reverse) слушает
Kraken outbound reverse-нода + exit исходящий к TrueNAS да
Локальные клиенты используют TrueNAS как локальный прокси-шлюз через Kraken

Ключевое физическое ограничение: Kraken за NAT не может принимать входящих. Поэтому канал держит Kraken исходящим к TrueNAS. Для передачи клиентского трафика TrueNAS → Kraken используются конструкции dokodemo-door + reverse + policy-маршрутизация (routing rules). Это чуть сложнее "поставить reverse и всё", конфиг нужен аккуратный.

⚠️ Факты, проверенные 2026-09-01 (важно, ломают прежние допущения)

  1. На 443 у TrueNAS НЕ Xray. Проверено openssl s_client: на mallexxx.duckdns.org:443 отвечает обычный TLS 1.3 с валидным Let's Encrypt сертификатом для mallexxx.duckdns.org (issuer=Let's Encrypt/CN=YE2). Это Caddy/nginx reverse-proxy, НЕ Xray REALITY (у REALITY сертификат был бы чужой/поддельный). → Твоя память «на 443 висел xray server» не подтверждается.
  2. vless-proxy на TrueNAS (контейнер teddysun/xray:latest, Up 7 дней):
    • inbound: SOCKS 0.0.0.0:1080, HTTP 0.0.0.0:1081 (локально в LAN TrueNAS)
    • outbound: VLESS+WS+TLS на v.qentra.top:443, path /qentra, id 2D9F24C4-21FE-4784-9843-F11C384DA67Aуказывает на УДАЛЁННЫЙ VPS → сейчас мёртвый.
    • ⚠️ Используется Hermes-Taiga как SOCKS5-прокси (vless-proxy:1080) → Hermes-Taiga сейчас без рабочего прокси.
  3. Kraken→TrueNAS по mallexxx.duckdns.org: открыты только 22 (SSH) и 443 (HTTPS/TLS). 8443/8964/8080/9000 — closed. Порт 443 — TLS (Caddy), не сырой.
  4. Kraken: Docker установлен (/usr/bin/docker), но демон отвечает медленно/рвёт SSH (проверка docker ps не завершилась за 40s). Xray на Kraken отсутствует (which xray пусто) — нужен Docker-контейнер.
  5. Связанность Kraken↔TrueNAS по 22/443 — подтверждена (оба OPEN с Kraken).

ВНЕДРЕНО 2026-09-01: 3x-ui на TrueNAS (фронтенд + Docker Compose)

Решение Alex: использовать 3x-ui frontend + Docker Compose (управление клиентами через панель), а не ручной Caddy-pass-through с сырым Xray. Это изменило исходный план реализации (Шаг 1 ниже устарел по способу).

Развёрнут контейнер xray-admin (TrueNAS)

  • Имя контейнера: xray-admin (строго, т.к. Caddyfile резолвит xray-admin по имени в docker-сети).
  • Образ: ghcr.io/mhsanaei/3x-ui:latest (3.7.0, Xray 26.7.28).
  • Сеть: caddy_default (external) — там же Caddy, чтобы резолвить имя.
  • Volume: /mnt/RED_2TB/docker/xray-admin:/etc/x-ui (туда лёг существующий x-ui.db).
  • Порт панели: хостовый 54321 → 54321 (внутри панель реально слушает 2053 — Caddy проксирует vpn-panel.mallexxx.duckdns.orgxray-admin:2053).
  • Compose-файл: /mnt/RED_2TB/docker/xray-admin/docker-compose.yml (deployed версия с TZ=Asia/Novosibirsk, PUID/PGID=950; см. актуальный файл на TrueNAS — отличается от черновика в плане).
  • Панель доступна: https://vpn-panel.mallexxx.duckdns.org/HTTP 200.
  • Sub-сервер: [::]:443 (path /sub), панель [::]:2053, inbound vless-ws:10095 (path /vless, host vpn.mallexxx.duckdns.org).

Почему это заработало «из коробки» (важно)

База /mnt/RED_2TB/docker/xray-admin/x-ui.db уже была настроена под эту Caddy-интеграцию (раньше 3x-ui уже задумывался на TrueNAS): inbound vless-ws port 10095 tag in-10095-tcp, subDomain vpn-panel.mallexxx.duckdns.org, subPort 443, subScheme https. Caddyfile уже содержал (мёртвые до подъёма) блоки:

  • vpn.mallexxx.duckdns.org@ws path /vlessxray-admin:10095 (WS)
  • vpn-panel.mallexxx.duckdns.org@sub path /sub/*xray-admin:443 + fallback xray-admin:2053
  • LE-сертификаты для этих поддоменов уже выданы.

3x-ui поддерживает reverse

В бинарнике /app/x-ui присутствует clientReverseTags → reverse-настройка реализуема через панель 3x-ui (3.7.0).

Бэкап (сделан до изменений)

/mnt/RED_2TB/docker/backups/reverse-xray-3xui-20260901-113625/ — содержит: caddy/Caddyfile (копия из контейнера, 90 строк), xray-admin/x-ui.db, docker-inventory.txt.

Мелочь/питфолл

Скопированный в volume docker-compose.yml оказался внутри контейнера /etc/x-ui/ (т.к. volume смонтирован туда) — удалить лишний файл из контейнера: docker exec xray-admin rm -f /etc/x-ui/docker-compose.yml.

ВНЕДРЕНО 2026-09-01: Reverse portal (TrueNAS) + bridge (Kraken) — VLESS-WS

После 3x-ui развёрнут полноценный reverse. Ключевое открытие: Xray 26.x заменил legacy reverse на "VLESS Reverse Proxy" — старая схема reverse.bridges/portals (Xray-examples/ReverseProxy) не работает в этой версии (ошибка The feature "legacy reverse" has been removed and migrated to "VLESS Reverse Proxy"). Новая схема: reverse.tag в VLESS-клиентах/аутбаундах (примеры — xtls.github.io/en/document/level-2/vless_reverse.html, use case "Home Broadband Egress").

Роли (новая терминология VLESS Reverse)

  • Internal device (Kraken) = BRIDGE: VLESS-outbound с "reverse":{"tag":"reverse-in"} → активно устанавливает канал к TrueNAS; на своей стороне создаётся виртуальный inbound reverse-in, чей трафик направляется в freedom (интернет).
  • Public server (TrueNAS) = PORTAL: VLESS-inbound с "reverse":{"tag":"reverse-out"} у клиента → создаёт routable-маутбаунд reverse-out; локальные клиенты (SOCKS) маршрутизируются в reverse-out.
  • reverse.tag на двух сторонах не обязаны совпадать — соответствие через общий UUID соединения.

TrueNAS — xray-reverse-portal (папка /mnt/RED_2TB/docker/reverse-portal/)

compose: image teddysun/xray:latest (26.7.28), сеть caddy_default, volume config.json:/etc/xray/config.json:ro, проброс host 12345:12345. config.json:

  • inbound interconn (:12346, VLESS, ws path /rvs, host vpn.mallexxx.duckdns.org, client id a81c3179-312b-4c5e-8a46-6bf3c30c2941, "reverse":{"tag":"reverse-out"})
  • inbound local (:12345, SOCKS noauth udp:true) — точка входа для клиентов сети TrueNAS
  • routing: inboundTag:["local"] → outboundTag:"reverse-out"
  • outbounds: freedom (placeholder — обязателен, иначе reverse-out станет default и весь трафик уйдёт в reverse)
  • Порт 12346 НЕ проброшен наружу — к нему обращается Caddy по имени xray-reverse-portal:12346 в docker-сети.

TrueNAS — Caddyfile (bind mount /mnt/RED_2TB/docker/caddy/Caddyfile)

Добавлен маршрут в блок vpn.mallexxx.duckdns.org:

@rvs path /rvs
reverse_proxy @rvs xray-reverse-portal:12346

Питфоллы: Caddyfile нельзя править docker cp в контейнер (volume → device or resource busy) — править на хосте через docker run --rm -v /:/host alpine cp /host/tmp/.... Валидация docker exec caddy caddy validate --config /tmp/Caddyfile.new → "Valid configuration". Перезапуск docker restart caddy безопасен. Бэкап: Caddyfile.pre-reverse.

Kraken — xray-reverse-bridge (папка /home/kraken/xray-reverse/)

compose: image teddysun/xray:latest, volume config.json:/etc/xray/config.json:ro. config.json:

  • outbound direct = freedom + "finalRules":[{"action":"allow","network":"tcp,udp","ip":["0.0.0.0/0"]}] (интернет-egress Kraken)
  • outbound conn = VLESS упрощённого стиля (settings.address/port/id/encryption/reverse — НЕ vnext[]!) → vpn.mallexxx.duckdns.org:443 ws /rvs "reverse":{"tag":"reverse-in"}, security tls, tlsSettings.serverName vpn.mallexxx.duckdns.org
  • routing: inboundTag:["reverse-in"] → outboundTag:"direct"
  • Питфолл: VLESS-outbound с reverse должен быть упрощённого стиля. Если через vnext[]/users[] → Xray 26.x: VLESS users: please use simplified outbound's config style to use "reverse".
  • loglevel debug (для диагностики).

Reverse-канал: установлен

  • Kraken netstat: 172.24.0.2:... → 90.189.160.148:443 ESTABLISHED
  • Portal: ::ffff:172.16.1.7:12346 ::ffff:172.16.1.3:52616 ESTABLISHED (172.16.1.3 = Caddy)
  • Bridge logs: common/mux: received request for udp:reverse:0

End-to-end payload НЕ работает

  • 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] — запрос ушёл в reverse-out.
  • Bridge НЕ логирует received для этого TCP-payload — данные теряются между reverse-out (portal) и reverse-in (bridge).
  • Kraken имеет прямой интернет (api.ipify92.62.70.41), проблема не в egress.

ВНЕДРЕНО (2026-09-01) — TCP+REALITY переход, все шаги выполнены

WS-транспорт не пропускал reverse-payload; переведён на прямой TCP + REALITY (Alex согласовал проброс). Все 4 шага ВЫПОЛНЕНЫ:

  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 + common/mux: received request for udp:reverse:0.
  4. Тест payload НЕ прошёл даже на TCP+REALITY: curl --socks5 127.0.0.1:12345 http://api.ipify.orgcode=000. Portal: accepted tcp:8.6.112.0:80 [local -> reverse-out], но bridge НЕ логирует приход TCP-payload.

Дополнительно пробовано: снятие flow: xtls-rprx-vision

Убрал flow: xtls-rprx-vision с обеих сторон (portal interconn client + bridge conn outbound), пересоздал контейнеры (оба Configuration OK). Результат: по-прежнему code=000. Reverse-канал устанавливается, TCP-payload до bridge не доходит.

Вывод: проблема НЕ в flow и НЕ в WS. Даже на «каноничном» TCP+REALITY payload от portal-reverse-out до bridge-reverse-in не передаётся (bridge не получает inbound-TCP). Гипотеза про WS опровергнута.

🔑 КОРЕНЬ ПРОБЛЕМЫ НАЙДЕН (2026-09-01, интернет-поиск) — issue XTLS/Xray-core #6612

Симптомы точно совпадают с #6612: reverse-канал устанавливается (udp:reverse:0 на месте), но TCP-payload не проходит; portal логирует accepted tcp:... -> reverse-out, а bridge НЕ получает входящих reverse-in-соединений; curl → 000.

Причина: начиная с Xray v26.5+ (PR #6027) у outbound freedom/direct появилась дефолтная политика безопасности, которая блокирует ВСЕ цели для трафика VLESS Reverse, если не задан явный finalRules. Контрольный reverse-канал при этом продолжает устанавливаться — поэтому «всё выглядит подключённым», но реальный payload молча отбрасывается. Это ровно наш случай на версии 26.7.28.

Точный фикс — добавить в freedom direct на BRIDGE (место реального egress из reverse-in в интернет):

{
  "protocol": "freedom",
  "tag": "direct",
  "settings": {
    "domainStrategy": "AsIs",
    "finalRules": [ { "action": "allow" } ]
  }
}

Issue говорит прямо: проблема воспроизводится с обычным Freedom без finalRules вообще, и добавление безусловного allow чинит на 26.7.28.

Релевантные ссылки:

  • #6612 — главный фикс: https://github.com/XTLS/Xray-core/issues/6612
  • #6027 — корень (finalRules у Direct/Freedom): https://github.com/XTLS/Xray-core/pull/6027
  • Документация freedom: https://xtls.github.io/en/config/outbounds/freedom.html
  • 3x-ui разбор под reverse: https://github.com/MHSanaei/3x-ui/issues/4782
  • #2664 — если finalRules не поможет: flow: xtls-rprx-vision на BRIDGE-outbound + REALITY может ломать доставку (держите flow:"" на reverse-клиенте): https://github.com/XTLS/Xray-core/issues/2664
  • Регрессия роутинга reverse v26.5+ (если фикс не поможет): #6242, #6195, #6248 — временный кварк: пинить v26.4.25.

Важные детали из поиска (проверить при продолжении):

  • Портал ДОЛЖЕН иметь placeholder-freedom (у нас есть) — иначе reverse-out станет default. Плейсхолдеру не нужен finalRules:allow (он обслуживает только несопоставленный трафик).
  • Роутинг inboundTag:["reverse-in"] -> direct на bridge — нужен (у нас есть).
  • У VLESS outbound поле encryption обязательно ("none" или парный PQ-ключ к серверному decryption) — у нас "none", ок.

ФИКС ПРИМЕНЁН, но заблокирован (2026-09-01)

Новый bridge-конфиг с finalRules:[{action:"allow"}] в direct залит на Kraken (/home/kraken/xray-reverse/config.json, 1098 байт, проверено cat | head -5). НО:

  • Kraken по docker НЕДОСТУПЕН: systemctl is-active dockeractivating (не active), демон застрял, накоплено множество зависших docker-процессов (ps/run/compose).
  • Причина: USB-HDD снова не поднялсяlsblk /dev/sda0B (без раздела). Docker data-root = /srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/docker-data (на этом HDD) → daemon ждёт диск и застревает.
  • ⚠️ Замечено расхождение UUID: сейчас data-root указывает на /srv/dev-disk-by-uuid-49e8f586-..., а в контексте ранее фигурировал смонтированный HDD /srv/dev-disk-by-uuid-6194539b-... (sda1 1.8T). Текущий sda = 0B без раздела.
  • docker compose down/up для bridge не выполнен — контейнер всё ещё со старым конфигом (больше не деплоится, daemon не отвечает).

Шаг для продолжения (требует подтверждения Alex): починить HDD/docker на Kraken (повторить утренний сценарий: sudo reboot или физическое переподключение USB-диска), затем пересоздать bridge-контейнер (cd /home/kraken/xray-reverse && docker compose down && docker compose up -d), затем тест curl --socks5 127.0.0.1:12345 http://api.ipify.org на TrueNAS → ожидаем выход с IP Kraken.

Статус: задание НЕ завершено — остаётся применить bridge-фикс после восстановления docker на Kraken.

2026-09-02: Kraken восстановлен (диск/docker) + фикс #6612 применён — НО payload всё равно мёртв → ИСТИННЫЙ КОРЕНЬ #6242 (bridge-side v26.5+)

Kraken полностью поднялся (проверено живьём по SSH)

  • Uptime 2 мин — Kraken перезагрузился (USB-HDD-сценарий). systemctl is-active docker был activating первые минуты (ждал поднятия диска), затем стал active.
  • Диск /dev/sda1 поднялся: 1.8T, смонтирован к /srv/dev-disk-by-uuid-6194539b-03e0-4f33-986b-4da09834e82f, 235G свободно (87% занято). (В отличие от 2026-09-01, когда sda был 0B.)
  • Все контейнеры восстановились (в прошлый раз — 0): transmission, sonarr, prowlarr, homeassistant, jellyfin, radarr, hermes-kraken, portainer, rclone, cloudflared, flaresolverr, watchtower, xray-reverse-bridge. Docker Root Dir /srv/dev-disk-by-uuid-6194539b-.../docker-data.
  • Bridge-конфиг содержит фикс #6612: /home/kraken/xray-reverse/config.jsonfreedom/direct с "finalRules":[{"action":"allow"}].
  • Reverse-канал к TrueNAS жив: bridge лог 2026-09-02 13:12: dialing TCP to mallexxx.duckdns.org:12346tunneling requestreceived request for udp:reverse:0. Bridge = Xray 26.7.28 (teddysun/xray:latest).

Portal (TrueNAS) — состояние

xray-reverse-portal Up 22h, reverse-канал от Kraken держится. Лог portal: accepted tcp:8.6.112.0:80 [local -> reverse-out] — запрос с локального SOCKS-входа уходит в reverse-out (в сторону Kraken). Конфиг portal без изменений (interconn :12346 REALITY client a81c3179... reverse-out; local :12345 SOCKS; routing local→reverse-out; placeholder-freedom). Сеть caddy_default, curl-контейнер в ней резолвит xray-reverse-portal:12345 = 172.16.1.7.

End-to-end payload по-прежнему НЕ проходит (даже с фиксом #6612)

Тест временным контейнером curlimages/curl в сети caddy_default на TrueNAS:

docker run --rm --network caddy_default curlimages/curl:latest curl -sv --socks5-hostname xray-reverse-portal:12345 -m 20 http://api.ipify.org

→ verbos: Opened SOCKS connection from 172.16.1.8 port ... to api.ipify.org port 80 (via 172.16.1.7 port 12345)Request completely sent offEmpty reply from server (соединение закрыто без ответа). Трафик доходит до portal, уходит в reverse-out, НО не возвращается от bridge → ответ теряется.

🔑 ИСТИННЫЙ КОРЕНЬ (2026-09-02, интернет-поиск): issue XTLS/Xray-core #6242 — регрессия bridge в v26.5+

Симптомы точно совпадают с issue #6242 (закрыта "not planned"):

  • Регрессия только на стороне BRIDGE (outbound-initiating), версия portal не важна.
  • С v26.5+ (и 26.6.x) bridge стартует без ошибок, reverse-канал вроде устанавливается (udp:reverse:0), но трафик не маршрутизируется через reverse tunnel. Ровно наш случай на 26.7.28.
  • Понижение ТОЛЬКО bridge до v26.4.25 мгновенно возвращает полную работу без изменений конфига.
  • Связано с #5750 (BurstObservatory не успевает health-check динамически регистрируемых rproxy-* outbound'ов — до 10 мин) и обсуждением #5962 (stale-tunnel mappings после рестартов). PR #5101 прямо предупреждал: "reverse sub-protocol unstable, will break, кросс-версий совместимости НЕ гарантировано".
  • Почему фикс #6612 не помог: #6612 (finalRules:allow) лечит ДРУГУЮ проблему (Freedom блокирует payload) — мы её уже устранили. Но осталась регрессия маршрутизации #6242, которую finalRules не обходит.

Решение/кварк: сдаунгрейд bridge до Xray 26.4.25 (образ teddysun/xray:26.4.25, существует на Docker Hub / GitHub Container Registry ghcr.io/xtls/xray-core:26.4.25). Portal-сторона (26.7.28) остаётся.

План внедрения (согласован с Alex — что НЕ трогать vpn.mallexxx и xray-admin)

  1. На Kraken: остановить xray-reverse-bridge контейнер.
  2. В /home/kraken/xray-reverse/docker-compose.yml сменить образ teddysun/xray:latestteddysun/xray:26.4.25.
  3. cd /home/kraken/xray-reverse && docker compose up -d (пересоздаст bridge на 26.4.25).
  4. Проверить reverse-канал: bridge лог udp:reverse:0.
  5. Контрольный end-to-end: временный curl-контейнер в сети caddy_default на TrueNAS через xray-reverse-portal:12345 → ожидаем выход с IP Kraken (92.62.70.41), НЕ IP TrueNAS. НЕ трогать: xray-admin / vpn.mallexxx / Caddy / portal.

⚠️ Важное прояснение для будущих сессий (из этого диалога)

Запрос юзера "не могу подключиться к xray на truenas до наших измерений" — это была путаница между тремя разными сущностями:

  1. vless-proxy (teddysun/xray, SOCKS :1080/:1081, outbound на удалённый VPS qentra.top) — мёртв из-за удаления VPS 2026-09-01.
  2. xray-admin (3x-ui) = самостоятельный рабочий Xray-VPN из интернета через vpn.mallexxx.duckdns.org:443 (см. секцию «ВАЖНО 2026-09-02» выше). Жив, end-to-end проверен.
  3. reverse-туннель TrueNAS↔Kraken (portal xray-reverse-portal + bridge на Kraken) — это про проксирование egress ЛОКАЛЬНЫХ клиентов сети TrueNAS через Kraken. НЕ связан с vpn.mallexxx.

ИСТОРИЯ ДИАГНОСТИКИ 2026-09-02: downgrade сам по себе не помог

⚠️ ВАЖНО: вопреки секции «ИСТИННЫЙ КОРЕНЬ #6242» выше (которая была гипотезой, ещё не проверенной полностью), полный downgrade обеих сторон до Xray 26.4.25 payload НЕ починил. Это зафиксировано здесь как фактический итог.

Что было сделано (выполнено по факту, alive-диагностика)

По согласованию с Alex (не трогая vpn.mallexxx / xray-admin) выполнено:

  1. Bridge (Kraken): /home/kraken/xray-reverse/docker-compose.yml → образ teddysun/xray:26.4.25. Docker Pull прошёл, контейнер на 26.4.25 (Xray 26.4.25 ... go1.26.2 linux/arm64). Бэкап: docker-compose.yml.bak-26.7.28.
  2. Portal (TrueNAS): /mnt/RED_2TB/docker/reverse-portal/docker-compose.yml → тоже teddysun/xray:26.4.25 (Linux amd64, образ 21.59MB Pull). Бэкап: docker-compose.yml.bak-26.7.28. Контейнер xray-reverse-portal пересоздан.
  3. Portal config.json loglevel поднят на debug (для диагностики), залит в /mnt/RED_2TB/docker/reverse-portal/config.json.
  4. Локальные копии файлов на Mac (для правки): ~/xray-test/docker-compose.bridge.yml, docker-compose.portal.yml, portal.config.json, config.json (тестовый клиент vpn.mallexxx, удалить не нужно).
  5. После смены версии bridge перезапущен (для переустановки reverse-канала к новому portal).

Результат end-to-end теста (обе стороны 26.4.25)

  • Reverse-канал у bridge устанавливается: лог dialing TCP to mallexxx.duckdns.org:12346tunneling request to unknownreceived request for udp:reverse:0. Portal принимает (лог: proxy/vless/inbound: received request for tcp:v1.rvs.cool:0dispatching request to udp:reverse:0).
  • НО payload по-прежнему НЕ проходит: тест curl через xray-reverse-portal:12345Empty reply from server / exit=52.
  • Portal (TrueNAS) debug-лог полностью проясняет картину:
    • При запросе: [118463829] proxy/socks: TCP Connect request to tcp:api.ipify.org:80[118463829] app/dispatcher: taking detour [reverse-out] for [tcp:api.ipify.org:80]и НИЧЕГО дальше (ни ошибки, ни dial к bridge). Dispatch в reverse-out молча глотается.
    • Фоновые разрывы: common/mux: failed to read metadata > read tcp 172.16.1.7:12346->92.62.70.41:3266: connection reset by peer — portal пытается что-то слать к bridge, но канал рвётся.
  • Критично: на TrueNAS НЕТ постоянного ESTABLISHED TCP-соединения от bridge на :12346 (ss -tn sport=:12346 пусто). Reverse-канал НЕ держится постоянным — устанавливается эфемерно (per контрольный UDP прочёт), и data-stream по нему не доходит до bridge.
  • Bridge (Kraken) никогда не логирует приём reverse-in TCP-payload (только контрольный udp:reverse:0).

Вывод

Проблема НЕ регрессия #6242 фиксируемая версией bridge — иначе downgrade до рабочей по issue пары 26.4.25↔26.4.25 решил бы. После полного downgrade payload по-прежнему мёртв. Настоящая причина: reverse-канал portal↔bridge не удерживается постоянным на TCP-уровне (нет стабильного ESTABLISHED :12346), поэтому dispatch портала в reverse-out не находит живой транспорт до bridge и молча теряет данные.

Это согласуется с предупреждением PR #5101: новый VLESS Reverse sub-protocol itself нестабилен («will break, кросс-версий совместимость не гарантирована») — по-видимому канал между двумя разнесёнными docker-реализациями (Kraken arm64 ↔ TrueNAS amd64, обе 26.4.25) не держится стабильно.

Дальнейшие гипотезы (НЕ проверены, треб.WB)

  1. Транспортный REALITY mismatch arm64(26.4.25 bridge) ↔ amd64(26.4.25 portal) даёт нестабильный mux → попробовать не-REALITY (простой TCP, т.к. канал только между сервисами TrueNAS↔Kraken, не извне) — убрать REALITY, оставить VLESS-TCP без camouflage.
  2. Перепроверить, что bridge реально удерживает единственное mux-соединение (в xray reverse bridge обычно держит persistent канал, у нас его нет → пере-аудит конфиг bridge: возможно не хватает чего-то, заставляющего держать канал постоянно).
  3. Запросить консультацию/повторно изучить рабочую конфигурацию сбора из живого разбора темы (потому что каноничные примеры из доки и issues не дали полного рабочего egress-конфига).

⚠️ ТЕКУЩЕЕ СОСТОЯНИЕ СИСТЕМ (на момент записи, 2026-09-02)

  • Версии: BOTH portal и bridge сейчас на teddysun/xray:26.4.25 (исходно были на :latest = 26.7.28). Откат при необходимости: поменять образ в compose обратно на teddysun/xray:latest и docker compose up -d.
  • Конфиг portal имеет loglevel: debug (пока). Bridge config.json содержит фикс #6612 finalRules:allow.
  • vpn.mallexxx.duckdns.org / xray-admin / Caddy — НЕ тронуты, работают (см. секцию «ВАЖНО 2026-09-02»).
  • Reverse к Kraken НЕ внедрён/не работает end-to-end — это остаётся открытой задачей.

Открытые вопросы по reverse (требуют ответа/действия Alex)

План реализации (история; Шаг 1 устарел — см. «ВНЕДРЕНО» выше)

Шаг 1 — TrueNAS: Xray reverse-server поверх Caddy

  • Способ (рекомендован): Caddy TLS-pass-through. Добавить в Caddy TCP-правило: поддомен xray.mallexxx.duckdns.org:443 → внутренний порт Xray-контейнера (напр. localhost:8443). Caddy передаёт сырой TLS-стрим дальше. Xray на TrueNAS принимает VLESS+Reality/TLS. Kraken ходит на xray.mallexxx.duckdns.org:443.
    • Плюс: переиспользуем уже открытый/проброшенный 443 на роутере, не трогаем роутер, туннель маскируется под HTTPS.
    • Альтернатива: пробросить отдельный порт на роутере (напр. 8443) → требует доступа к роутеру. Менее предпочтительно.
  • Новый/доразвернутый Xray-контейнер:
    • inbound reverse/dokodemo-door на 8443 (извне по pass-through)
    • local inbound SOCKS/HTTP (уже есть 1080/1081)
    • routing: трафик клиентов → в reverse-канал к Kraken

Шаг 2 — TrueNAS: бэкап перед изменением

  • Снять копию текущего конфига vless-proxy (config.json), в /mnt/RED_2TB/docker/<app>/backup/ (паттерн как с cups-splix).

Шаг 3 — Kraken: Xray outbound reverse в Docker

  • Контейнер Xray на Kraken (docker run --restart unless-stopped, как остальные).
  • outbound vless → xray.mallexxx.duckdns.org:443 (через Caddy pass-through).
  • inbound SOCKS/HTTP на Kraken — точка выхода.
  • reverse-конфиг: Kraken регистрирует «сервис» (весь трафик через dokodemo-door) наружу через канал к TrueNAS.

Шаг 4 — Проверка связности

  • Kraken → xray.mallexxx.duckdns.org:443 (TCP).
  • Локальный клиент → TrueNAS:1080 → curl через прокси → должен выйти с IP Kraken.

Шаг 5 — Обновить Obsidian после внедрения

  • Дополнить family/how-to/truenas-infrastructure.md (Xray reverse-настройка), family/how-to/kraken-access.md; обновить personal/tech/vps-qentra.md (VPS удалён, ссылки на него).

Открытые вопросы (требуют ответа Alex)

  1. (решено) Проброс порта для reverse — переведён на TCP+REALITY, ВСЁ ВЫПОЛНЕНО (portal пересоздан с REALITY, OpenWrt DNAT внешний:12346 → 192.168.2.197:12346 добавлен, bridge на Kraken пересоздан). См. секции «ВНЕДРЕНО — TCP+REALITY» выше. Компанент работает, но payload НЕ проходит (см. пункт 4).
  2. Какой трафик TrueNAS пустить через Kraken — весь исходящий интернет, или конкретные сервисы/подсети? (Влияет на маршрутизацию на Kraken.) — всё ещё открыто.
  3. Kraken docker — РАБОТАЕТ, ВОССТАНОВИЛСЯ 2026-09-02: systemctl is-active dockeractive, диск /dev/sda1 1.8T смонтирован к /srv/dev-disk-by-uuid-6194539b-..., 235G свободно (87% занято). Все контейнеры восстановились (в отличие от 2026-09-01, когда было 0): transmission, sonarr, prowlarr, homeassistant, jellyfin, radarr, hermes-kraken, portainer, rclone, cloudflared, flaresolverr, watchtower, xray-reverse-bridge (Up).
  4. End-to-end payload проходит. #6612/#6242 оказались неполными гипотезами. Верифицированный корень — Docker bridge/NAT на Kraken; решение — Xray 26.4.25 + network_mode: host на bridge. См. authoritative-секцию ниже.

Верифицированный фикс 2026-09-02 (authoritative)

Эта секция суперсидирует все более ранние выводы «payload мёртв», «нет persistent ESTABLISHED» и предполагаемые корни #6612/#6242. Фикс найден и проверен живыми A/B-тестами.

Истинная причина

xray-reverse-bridge на Kraken работал в обычной Docker bridge-сети. Docker bridge/NAT на этом узле сбрасывал long-lived VLESS reverse mux после успешной регистрации udp:reverse:0. Поэтому portal создавал reverse-out, но payload не доходил до reverse-in.

Ключевой A/B-тест:

  1. Тот же JSON на temporary bridge amd64 внутри TrueNAS заработал сразу → portal/config/routing исправны.
  2. Тот же Xray 26.4.25 arm64 + тот же JSON на Kraken в --network host заработал сразу → CPU architecture и WAN исправны, отличие только в Docker network mode.
  3. После возврата REALITY+Vision туннель остался рабочим → проблема не в REALITY, Vision или TCP transport.

Постоянная конфигурация

Kraken: /home/kraken/xray-reverse/docker-compose.yml

services:
  xray-reverse-bridge:
    image: teddysun/xray:26.4.25
    network_mode: host

Bridge config возвращён к защищённому VLESS TCP + REALITY + flow: xtls-rprx-vision. direct сохраняет finalRules: [{"action":"allow"}]. Portal на TrueNAS также на teddysun/xray:26.4.25, REALITY+Vision. xray-admin, Caddy и vpn.mallexxx.duckdns.org не менялись.

network_mode: host расширяет сетевые права bridge-контейнера. В этом конфиге у него нет физических listening inbounds; reverse-in — виртуальный inbound Xray. Не добавлять в этот контейнер обычные inbounds без аудита bind address/firewall.

Финальная проверка

2026-09-02 после permanent Compose deploy:

  • docker inspect xray-reverse-bridge → image teddysun/xray:26.4.25, network host, status running, restart count 0.
  • Bridge лог: received request for udp:reverse:0, затем TCP payload принят в reverse-in -> direct.
  • HTTPS через SOCKS xray-reverse-portal:1234592.62.70.41.
  • HTTP через тот же SOCKS → 92.62.70.41.
  • 92.62.70.41 — публичный egress Kraken; TrueNAS egress 90.189.160.148 не использовался.

Бэкапы и rollback

Kraken:

  • /home/kraken/xray-reverse/docker-compose.yml.bak-bridge-network-20260902-1147
  • /home/kraken/xray-reverse/config.json.bak-plain-host-working-20260902-1146
  • /home/kraken/xray-reverse/config.json.bak-reality-vision-20260902-1142

TrueNAS:

  • /mnt/RED_2TB/docker/reverse-portal/config.json.bak-plain-host-working-20260902-1146
  • /mnt/RED_2TB/docker/reverse-portal/config.json.bak-reality-vision-20260902-1142

Rollback network fix: вернуть compose-бэкап на Kraken и выполнить docker compose up -d. Это вернёт нерабочий Docker bridge mode, поэтому делать только для диагностики/отката.

Per-user egress на vpn.mallexxx.duckdns.org (2026-09-02)

В существующий VLESS-WS inbound in-10095-tcp добавлен второй клиент. Маршрутизация теперь различает клиентов по email:

Client email Client ID Egress
user1 ce320965-6956-4759-84bb-7cb71cfc6252 direct → TrueNAS 90.189.160.148
kraken-user 93a5dc4b-1b8d-4af5-9363-eb0091734293 via-kraken → portal SOCKS xray-reverse-portal:12345 → Kraken 92.62.70.41

В persistent 3x-ui Xray template (settings.key = xrayTemplateConfig) добавлен SOCKS outbound:

{
  "protocol": "socks",
  "tag": "via-kraken",
  "settings": {
    "address": "xray-reverse-portal",
    "port": 12345
  }
}

После глобальных geoip:private -> blocked и bittorrent -> blocked добавлено правило:

{
  "type": "field",
  "user": ["kraken-user"],
  "outboundTag": "via-kraken",
  "ruleTag": "kraken-user-via-reverse"
}

Проверка одним и тем же локальным Docker-клиентом xray-test-client, менялся только client ID:

  • user1 → HTTPS api.ipify.org90.189.160.148 (TrueNAS direct).
  • kraken-user → HTTP и HTTPS api.ipify.org92.62.70.41 (Kraken reverse).

Локальный /Users/admin/xray-test/config.json оставлен на kraken-user. Бэкап direct-клиента: /Users/admin/xray-test/config.json.bak-user1-direct-20260902-1227.

Бэкапы TrueNAS до и после изменения: /mnt/RED_2TB/docker/backups/xray-per-user-20260902-1200/ (x-ui.db, x-ui.post-change.db, runtime configs, reverse portal config/compose). Temporary full-admin API token не создавался; api_tokens осталась пустой.

Связанные заметки