[2026-09-26] eagle: family/how-to/kraken-access.md family/how-to/truenas-infrastructure.md family/projects/aide-kraken-backend.md personal/projects/balda/balda-mm-delegation-plan.md personal/projects/balda/balda-valera.md personal/projects/balda/fast-rlm-integration.md personal/tech/docker-data-root-mount-race.md personal/tech/inter-site-throughput-taiga-to-mac.md personal/tech/inter-site-throughput-taiga-to-mac.md.bak-nedstab2 personal/tech/multistream-single-flow-limit.md

This commit is contained in:
Alexey Martemyanov committed 2026-09-26 00:37:38 +06:00
1 parent 335478ef65
commit 1456511d3a
13 files changed
+1316 -15

No files matched your search

+6 -3
View File
@@ -125,7 +125,7 @@
>
> **Обновлено: 2026-09-04**
> Updated: 2026-09-01 23:00 — диск/докер кракена восстановились после перезагрузки.
> Updated: 2026-09-01 23:00 — диск/докер кракена поднялись после перезагрузки (тогда причина ещё не была известна; истинная — гонка docker↔mount, найдена 2026-09-20).
## Как зайти
@@ -134,9 +134,12 @@
- **Дома** — напрямую по LAN (`192.168.1.15`)
- **Снаружи** — ⚠️ через WireGuard (`10.99.1.2`) **БОЛЬШЕ НЕ РАБОТАЕТ**: VPS-узло (10.99.0.1/10.99.1.1) qentra.top **удалили 2026-09-01**. Альтернатива внешнего доступа обсуждается через Xray reverse (см. [[tech/xray-reverse-tunnel-kraken-truenas]]).
> ⚠️ **Kraken-диск был нестабилен 2026-09-01**: USB-диск TOSHIBA в цикле enumeration (`device descriptor read/64 error -110`, `device not accepting address error -62`, `[sda] Read Capacity(10) failed` → `0 B`), Kraken перезагружался (`System is booting up / pam_nologin`). **После повторной перезагрузки диск зарегистрировался**: `sda` 1.8T, `sda1` смонтирован в `/srv/dev-disk-by-uuid-6194539b-...`. Docker стал `active`.
> 🔴 **2026-09-15 — ПРИЧИНА НАЙДЕНА 2026-09-20: гонка docker ↔ монтирование диска.** Диск не «нестабилен» — он **монтируется медленно (~130 с)**, dockerd обгоняет. См. секцию выше.
> ⚠️ **Kraken Docker на 2026-09-01:** Server 29.4.3, Docker Root Dir `/srv/dev-disk-by-uuid-6194539b-03e0-4f33-986b-4da09834e82f/docker-data`. **30 образов сохранены, но 0 контейнеров** (all прежние контейнеры — jellyfin/transmission/radarr/hermes-kraken и т.д. — потеряны и НЕ пересозданы после сбоя; data-root на HDD был в цикле enumeration). При необходимости — пересоздать из образов.
> ⚠️ **Kraken Docker на 2026-09-01:** Server 29.4.3, Docker Root Dir `/srv/dev-disk-by-uuid-6194539b-03e0-4f33-986b-4da09834e82f/docker-data`. **30 образов сохранены, но 0 контейнеров** (все прежние контейнеры — jellyfin/transmission/radarr/hermes-kraken и т.д. — не были видны daemon'ом после старта без диска). Причина — та же mount-race, НЕ дефект диска; после фикса 2026-09-20 такого не повторяется.
>
> 🔴 **Диск НЕ нестабилен.** Формулировка «USB-диск нестабилен» — ошибочное обобщение разового инцидента 2026-09-01 (циклы USB enumerate, `error -110/-62`, `Read Capacity(10) failed`). Истинная причина проблем с контейнерами — **mount race**: диск монтируется ~130 с, dockerd стартует раньше. Фикс (`RequiresMountsFor`) применён 2026-09-20, проверен живым reboot'ом — все контейнеры поднялись сами. **Не возвращать формулировку «диск нестабилен»** (Alex требовал её убрать, 2026-09-25).
> Реальные ограничения HDD: 5400rpm, ~95 МБ/с на чтение — лимит механики, не USB и не дефект.
## Portainer (локально)
+2 -2
View File
@@ -115,13 +115,13 @@
> - **✅ НЕАКТУАЛЬНО с 2026-09-14:** USB-адаптеры (CH340 ZONT/вентиляция) **физически перенесены на t610** → на TrueNAS узлов `/dev/ttyZONT` / `/dev/ttyVent` **нет вообще**, а сами контейнеры `mbusd`, `modbus-bridge`, `ser2net` **погашены** (`stop` + `--restart=no`). Проверка: `ls /dev/ttyUSB*` → пусто; `/sys/bus/usb/devices` содержит только принтер Samsung `04e8:3425` (**`lsusb` на TrueNAS не установлен** — использовать `/sys/bus/usb/devices`).
> - **Актуальная гонка udev живёт на t610** — см. [[family/how-to/zont-modbus-bridge-udev-race-protection]].
> - ⚠️ **Историческая справка (если когда-нибудь откатывать):** `restart: unless-stopped` НЕ перезапускает контейнер, упавший на `start` из-за отсутствующего device-узла (отказ до старта процесса, ExitCode 128/255, RestartCount=0); лечилось ручным `docker start modbus-bridge mbusd` после готовности симлинков.
> **⚠️ ДРУГОЕ (открытое):** пул `DEST` (IronWolf) на 2026-08-24 `DEGRADED` — разобраться, почему (отвалился mirror-член). TimeMachine (~277G) не возвращён (бэкапы macOS, вероятно не нужен — решение Alex не подтверждено). SSH с Mac по 192.168.2.197 нестабилен — использовать `mallexxx.duckdns.org`.
> **⚠️ ДРУГОЕ (открытое):** пул `DEST` (IronWolf) на 2026-08-24 `DEGRADED` — разобраться, почему (отвалился mirror-член). TimeMachine (~277G) не возвращён (бэкапы macOS, вероятно не нужен — решение Alex не подтверждено). SSH с Mac по `192.168.2.197` — подключение давало `Connection reset` / `kex_exchange_identification` (вероятен конфликт сессий при активном входе на консоль) — рабочий путь: `mallexxx.duckdns.org`.
> ## 🔒 ИСТОРИЯ: статус до восстановления (2026-08-24)
> **Пул RED_2TB пересоздан и УЖЕ зареган в TrueNAS** — `zpool status` ONLINE (`mirror-0{sdc,sdf}`+`mirror-1{sde,sdd}`), `midclt call pool.query` id=1 RED_2TB ONLINE. rsync возврата данных ЗАВЕРШЁН (storage 3.29T, immich 353G, backup 287G, Edu 214G, Photos 146G, old-bu 65G, docker, docker.bak, system — все смонтированы).
> **`.ix-apps` датасет (docker storage, был 24G) НЕ перенесён** — rsync шёл из `/mnt/RED_2TB/*` и не включал монтируемый в `/mnt/.ix-apps` системный датасет. Образы = кеш → перекачаются из registry сами; конфиги целы в `/mnt/RED_2TB/docker/<app>`.
> **Контейнеры запускались через `docker-compose`, НЕ через TrueNAS Apps (TrueCharts/Custom App).** daemon.json `data-root:/mnt/.ix-apps/docker`. `.ix-apps` = просто data-root docker, не TrueNAS Apps.
> **⚠️ ДРУГОЕ (проверено 2026-08-24):** пул `DEST` (IronWolf, источник спасения) на момент проверки `DEGRADED` в `zpool list` — стоит разобраться, почему (вероятно отвалился mirror-член). Также SSH с Mac к TrueNAS по 192.168.2.197 нестабилен (`Connection reset/reset by peer`, `kex_exchange_identification read`), возможен конфликт сессий при активном входе на консоль — использовать `mallexxx.duckdns.org` и ретраи.
> **⚠️ ДРУГОЕ (проверено 2026-08-24):** пул `DEST` (IronWolf, источник спасения) на момент проверки `DEGRADED` в `zpool list` — стоит разобраться, почему (вероятно отвалился mirror-член). SSH с Mac к TrueNAS по 192.168.2.197 давал `Connection reset` / `kex_exchange_identification read` (вероятен конфликт сессий при активном входе на консоль) — использовать `mallexxx.duckdns.org` и ретраи.
> ## ⚠️ СТАТУС на 2026-08-21: пул RED_2TB — данные СПАСЕНЫ, пул OFFLINE, пересоздаём
> **Выгрузка успешно завершена** (подтверждено Alex): данные RED_2TB (4.56T) на IronWolf (пул `DEST`, `/mnt/IRONWOLF`). **Пул RED_2TB — статус OFFLINE** в БД TrueNAS, НЕ импортирован. Конфиги docker (caddy, transmission, HA, immich и т.д.), Obsidian vault и git-репо спасены на `/mnt/IRONWOLF` (`system/`, `docker.bak/`, `docker/`, `storage/obsidian`, `storage/git`).
+2 -2
View File
@@ -108,9 +108,9 @@ curl -s https://kraken.qentra.top/health
## Заметки по эксплуатации
### Туннель нестабилен — `sendmsg: network is unreachable`
### Cloudflared: циклические ошибки `sendmsg: network is unreachable`
Иногда после старта cloudflared начинает циклически падать с ошибкой `write udp: sendmsg: network is unreachable` — проблема с IPv6/UDP на RPi5.
Иногда после старта cloudflared начинает циклически падать с ошибкой `write udp: sendmsg: network is unreachable` — IPv6/UDP на RPi5 (у Кракена нет глобального IPv6, а cloudflared пробует QUIC по IPv6).
**Решение:** пересоздать контейнер с флагом `--protocol http2`:
```bash
@@ -1,8 +1,13 @@
# Balda 2.0 — Mattermost + распределённое делегирование (план)
> Создан 2026-09-25. Статус: **черновик, ждёт апрува Alex**.
> Задача: поднять свежую Балду из `normahq/balda` (без наших коммитов), завязать на Mattermost,
> Задача: поднять свежую Балду из `baldaworks/balda` (без наших коммитов), завязать на Mattermost,
> построить распределённое делегирование (дешёвый оркестратор + подписочные CLI в VM).
>
> **Оценка объёма (проверено 2026-09-25):** это ~10-14 рабочих дней, а не «пара вечеров».
> Апстрим переписан полностью (900 файлов), Mattermost-адаптера в нём нет вообще.
> Реалистичная разбивка: MM на Kraken 2-3 ч · MM-адаптер 2-4 дня · оркестратор на Kraken 1-2 дня ·
> исполнитель + мост на Mac 2-3 дня · связка и приёмка 1 день.
---
@@ -211,7 +216,7 @@ Mattermost (Alex) — итог + артефакты
|---|---|---|
| Бан подписочного аккаунта за «unusual traffic» | средний | только официальный бинарь; не более 1-2 параллельных задач; не проксировать токен; мониторить письма Anthropic |
| MM-адаптер разъедется с апстримом | высокий | держать как отдельный fork-патч, ребейзить на каждый релиз; либо предложить в апстрим PR |
| Kraken: USB-диск нестабилен, mount-race | известный | учесть в compose (см. `docker-data-root-mount-race`), volume не на data-root |
| Kraken: USB-HDD монтируется ~130 с, есть mount-race | известный | drop-in `RequiresMountsFor` уже применён и проверен reboot'ом; volume не на data-root |
| RPi5 не тянет сборку Балды | средний | собирать образ на Mac arm64, на Kraken только `pull`/`up` |
| Утечка секретов в MM-канал | средний | `balda.permissions.mode: ask`; redaction в job-events уже есть в апстриме |
| Mattermost free-лицензия ограничивает нужное | низкий | проверить лимиты до установки |
@@ -222,7 +227,7 @@ Mattermost (Alex) — итог + артефакты
1. **Mattermost:** поднимаем self-hosted Team Edition (free) или есть платный/облачный аккаунт?
2. **VM vs Docker:** начинаем с Docker-контейнера на Mac (быстро) или сразу VM (UTM/Parallels)?
3. **Kraken:** MM на USB-HDD-разделе или на SD (риск износа)? Учитывая нестабильность USB-диска — возможно, вынести MM на SD с бэкапом.
3. **Kraken:** MM на USB-HDD-разделе или на отдельном томе? Диск **не нестабилен** — просто медленно монтируется (~130 с, mount-race закрыт drop-in'ом). Единственный реальный минус HDD — 5400rpm, ~95 МБ/с на чтение. Альтернатива — SD, но там риск износа.
4. **Провайдер оркестратора:** DeepSeek (как сейчас у Валеры) или другой дешёвый?
5. **Судьба текущей Валеры/Клавдия:** гасим или держим параллельно на время миграции?
@@ -241,3 +246,12 @@ Mattermost (Alex) — итог + артефакты
## История
- **2026-09-25**: создан по итогам разведки апстрима и юридической проверки подписок.
- **2026-09-25**: добавлена оценка объёма (10-14 дней); уточнено, что диск Kraken НЕ нестабилен
(только медленный mount ~130 с) — формулировку «диск нестабилен» Alex потребовал удалить из
доков и памяти. См. `personal/tech/docker-data-root-mount-race.md` §«Диск НЕ нестабилен».
## Связанные заметки
- [[personal/tech/docker-data-root-mount-race]] — mount-race на Kraken (закрыт, reboot-безопасен)
- [[personal/projects/balda/balda-valera]] — текущая эксплуатация Балды/Валеры (форк, старая архитектура)
- [[personal/projects/balda/fast-rlm-integration]] — fast-rlm MCP sidecar (наша ветка)
- [[personal/tech/hermes-fork-vs-upstream]] — аналогичный опыт сравнения форка с апстримом
+47
View File
@@ -172,6 +172,53 @@ docker logs balda-agent-valera-1 2>&1 | grep "norma-tools"
### stream_only_with_session
Фикс: написать `@Валера <текст>` чтобы создать сессию.
## Как инвентаризировать форк перед сверкой с апстримом (проверено 2026-09-25)
Если снова встанет вопрос «что у нас есть, чего нет в апстриме» — этот порядок даёт полную картину
без догадок:
```bash
# 1. Подтянуть метаданные апстрима (не менять рабочую копию!)
cd ~/Developer/balda
git fetch --all --tags --prune
# 2. Насколько мы отстали / опередили
git rev-list --left-right --count HEAD...upstream/main # ожидаем "N M"
# 3. Наши уникальные коммиты по КАЖДОЙ ветке (главное)
for ref in origin/main backup/our-main-before-upstream feat/zulip-transport feat/zulip-events-polling; do
echo "--- $ref ---"; git log --oneline upstream/main.."$ref"
done
# 4. Размер расхождения по файлам
git diff --stat $(git merge-base upstream/main origin/main)..upstream/main | tail -5
# 5. Что апстрим сделал с файлами, которые мы правили
git log --oneline --all -- pkg/runtime/hostedagent/openai.go
```
**Результат для нашего форка (2026-09-25):**
| Репо | Отставание | Наши уникальные коммиты |
|---|---|---|
| `~/Developer/balda` | 900 файлов | `05159d15` (промежуточные статусы Zulip, `handlers/balda.go`), `bc5fd03c` (то же + Telegram + messageID), `feat/zulip-events-polling` (Events API long-poll) |
| `~/Developer/norma-local` | 26 коммитов | `56a6e1e`=`91c2c0a` (DeepSeek tool_calls в `hostedagent/openai.go`) |
**Важно про `5ad65955` в balda** — это НЕ фича, а `replace normahq/norma => ./norma-local` в `go.mod`.
При переезде на чистый апстрим его нужно удалить, иначе сборка не пройдёт (файлов `norma-local` там нет).
**Что апстрим сделал с нашими файлами:**
- `norma v2` (`f8a7336`) **удалила целиком** `pkg/runtime/hostedagent/` и `pkg/runtime/agentfactory/`.
Наш DeepSeek-фикс не переносится патчем. Перед переносом проверить, есть ли поддержка tool_calls
для OpenAI-совместимых провайдеров в `normahq/runtime/v2 v2.0.11` — если да, фикс не нужен вовсе.
- В balda наши `handlers/*` заменены на `handlersfx/*`; Zulip переехал в `channel/zulip/*`.
Наш фикс промежуточных статусов надо переписывать под `handlersfx/zulip_ingress.go`.
**Питфоллы при сверке:**
- `origin` у `norma-local` — это `normahq/norma` (реальный апстрим), а у `balda` `origin` — **наш** `mallexxx/balda`,
апстрим живёт в `upstream`. Не путать: «тянуть до апстрима» для balda ≠ `git pull origin main`.
- Стэши теряются (не переживают `git gc`/клоны) — выносить в ветку до любых операций сброса.
## Известные грабли
### OPENAI_BASE_URL — обязательная env var
@@ -114,10 +114,13 @@ mcp_servers:
## Откат
`cd /Users/admin/Docker/fast-rlm-mcp && docker-compose down` + убрать entry из config.yaml + `restart` Балды → состояние до начала.
### 0.7 Mattermost — новый транспорт (2026-09-25)
Планируется завязать Балду на **Mattermost**. В апстриме (`baldaworks/balda`) MM **отсутствует полностью** (0 совпадений по `mattermost`). Каналы апстрима: `telegram`, `zulip`, `slackagent`, `webhook`. Значит MM — новый транспортный адаптер по контракту `docs/architecture/transport-presentation-boundary.md`; образец для копирования `channel/zulip/adapter.go` (331 стр.) + `client.go` (289 стр.). План: [[personal/projects/balda/balda-mm-delegation-plan]].
## Признанные галлюцинации в этой сессии
1. msg 58792-58795: фабрикация "Container Started / Ready" — реально ничего не создавалось.
2. Утверждение что `fast-rlm serve --port 3333` существует — такой команды НЕТ. fast-rlm — только клиент.
3. Старая запись в памяти про "Балда на Кракене" — устаревшая, противоречит документации. Балда на Eagle.
3. Старая запись в памяти про "Балда на Кракене" — **устаревшая и ошибочная**. Балда живёт **на Eagle (Mac M4)**, в Docker Desktop: контейнер `balda-agent-valera-1`, compose в `~/Docker/balda-agent/`. **Кра́кен к Балде отношения не имеет** (там Jellyfin/arr-стек/transmission). ✅ Перепроверено 2026-09-25, формулировка «Балда на Кракене» удалена из доков и памяти.
4. Попытка писать доку через native `Write`/`Edit` в `/Users/admin/obsidian/...` из Linux-контейнера — файл попадает в контейнерную ФС, не в реальный vault. **Правильный путь — `mcp_obsidian_write_note` / `mcp_obsidian_patch_note`**.
5. Утверждение `from fast_rlm.config import RLMConfig` — такого пути в библиотеке нет, импорт top-level: `from fast_rlm import RLMConfig`.
6. `docker compose` (v2) на хосте не установлен — нужен `docker-compose` (v1).
@@ -101,6 +101,25 @@ ssh kraken 'docker ps -q | wc -l' # ожидаем ~12, НЕ 0
Общий питфолл для сервисов на этом узле: если Kraken лежал, cron-задачи (бэкап `0 4 * * *`, t610-подобные) **пропускаются без компенсации**. Для критичных — добавлять `@reboot`-строку с проверкой «артефакт за сегодня уже есть?».
## 🔴 Диск НЕ нестабилен — «нестабильность» была ошибочным диагнозом (2026-09-25)
Формулировку **«USB-HDD на Kraken нестабилен»** нельзя использовать: это обобщение разового инцидента
2026-09-01 (циклы USB enumeration: `device descriptor read/64 error -110`, `device not accepting address
error -62`, `[sda] Read Capacity(10) failed` → `0 B`), который позже был **объяснён и закрыт**.
**Истинная причина всех симптомов «диск отвалился» — гонка монтирования** (этот документ, раздел выше):
диск монтируется ~130 с, `dockerd` стартует раньше и видит пустой `data-root`. Фикс
(`RequiresMountsFor` drop-in) применён 2026-09-20 и **проверен живым reboot'ом** — все контейнеры
поднялись сами, ручных `docker start` не потребовалось.
**Реальные характеристики диска (не дефекты):**
- 5400rpm 2.5" механика → ~95 МБ/с на чтение. Это лимит механики, не USB (линк USB3 = 5000 Mbps подтверждён).
- Медленный подъём при boot (~130 с) — свойство, а не поломка; обрабатывается зависимостью в systemd.
**Правило для будущих сессий:** при «контейнеры пропали / сервис не поднялся после reboot» — проверять
гонку (`docker info` vs содержимое `docker-data/containers/`), а не списывать на «нестабильный диск».
Не давать оценку «диск нестабилен» без новых доказательств (raw USB-ошибок в `dmesg` за пределами boot).
## Связанные заметки
- [[personal/tech/jellyfin-db-schema-mismatch]] — jellyfin после reboot: сервер старше БД (503)
@@ -95,7 +95,7 @@ Speedtest гоняет **8 параллельных TCP-сессий**, кажд
- Честный путь к «несколько путей» — только **второй независимый линк** (мобильный 4G/5G backup-WAN на TrueNAS) + MPTCP/OpenMPTCProuter.
**3. «VLESS/REALITY-туннель уберёт лимит».**
Уже проверено 2026-09-02 (см. раздел «Замеры скорости туннелей» в `[[xray-reverse-tunnel-kraken-truenas]]`): direct через `vpn.mallexxx` = **~37 Мбит**, reverse через Kraken = **~45 Мбит** (нестабилен). Оба — в том же коридоре, что и прямой путь (28 Мбит single-flow). Туннель идёт тем же маршрутом; REALITY/Vision добавляет обёртки и обычно чуть хуже прямого. **Строить «реальный VPN в 192.168.2.x» смысла нет — он уже есть (`vpn.mallexxx`), и он не помог.**
Уже проверено 2026-09-02 (см. раздел «Замеры скорости туннелей» в `[[xray-reverse-tunnel-kraken-truenas]]`): direct через `vpn.mallexxx` = **~37 Мбит**, reverse через Kraken = **~45 Мбит**. Оба — в том же коридоре, что и прямой путь (28 Мбит single-flow). Туннель идёт тем же маршрутом; REALITY/Vision добавляет обёртки и обычно чуть хуже прямого. **Строить «реальный VPN в 192.168.2.x» смысла нет — он уже есть (`vpn.mallexxx`), и он не помог.**
### ✅ Что реально работает — ранжировано
@@ -0,0 +1,279 @@
---
title: Межсайтовая пропускная способность — TrueNAS (Taiga) ↔ Mac/TV
created: '2026-09-02'
updated: '2026-09-21'
type: tech
namespace: personal
tags: [network, truenas, throughput, rtt, tcp, jellyfin, xray, bottleneck, webos, moonfin, breezyfin, prefetch, single-flow]
related:
- "[[xray-reverse-tunnel-kraken-truenas]]"
- "[[../how-to/truenas-infrastructure]]"
- "[[../family/how-to/kraken-network]]"
---
# Межсайтовая пропускная способность — TrueNAS ↔ Mac/TV
> Контекст: после восстановления стека медиа/права на Taiga (см. `family/documents/vault-sync/2026-09-02-restore-privilege-scope.md`) Jellyfin запустился и файлы читаются, но **прямое воспроизведение с ТВ «грузится кусками»**. Диагностика 2026-09-02 установила: это **НЕ транскодинг и НЕ тариф**, а ограничение сети между двумя физически разнесёнными локальными сетями.
## Cетевой layout (фактический)
| Узел | LAN | Шлюз | Egress IP | Провайдер |
|---|---|---|---|---|
| Mac / TV (дом) | `192.168.1.57` | `192.168.1.1` | динамический | ТТК (92.62.x / 185.20.x) |
| **TrueNAS (Taiga)** | `192.168.2.197` | `192.168.2.2` | `90.189.160.148` (`mallexxx.duckdns.org`) | Ростелеком (194.186.x → 217.107.x) |
**Ключевое:** TrueNAS НЕ в локальной сети Мака/ТВ. Трафик ТВ→Jellyfin идёт целиком по интернету между двумя разными операторами/домохозяйствами.
## Замеры (2026-09-02)
### Задержка / маршрут
- RTT Mac → TrueNAS: **~104 мс**.
- Traceroute: хопы 1–7 моего ISP (ТТК) — **3–6 мс** ✅ чисто. **На хопе 8 (`194.186.168.65`) прыжок до ~54 мс** — межоператорская передача в сеть Ростелекома, где живёт TrueNAS. Хоп 10 (`217.107.108.41`) ~60 мс.
- Этот +50 мс — физическое/пиринговое расстояние между региональными операторами, НЕ петля. Перенастройка маршрута полностью RTT не уберёт.
- Примечание: **дальние сети в целом** (8.8.8.8 ~100 мс) у ТТК тоже идут через ~50 мс переход — деградация на стороне выхода, а не только до TrueNAS.
### Пропускная способность (распутали про «тариф»)
- Mac download с CDN: **~78 Мбит/с** (линия Мака в порядке).
- **TrueNAS сторона**: NIC `enp3s0` 1 Gb/s, до шлюза 0.2–0.8 мс 0% loss. NAS→Cloudflare: **download ~184 Мбит/с, upload ~117 Мбит/с**. → **Лимита тарифа на TrueNAS НЕТ.**
- Mac → TrueNAS (SCP 200MB): **~28 Мбит/с** одним потоком.
- Mac → TrueNAS, **4 параллельных SCP потока: ~28 → ~51 Мбит/с** (агрегат растёт с параллельностью).
## Вывод (важно)
Ограничение — **НЕ по суммарной полосе транзита, а по одному TCP-потоку из-за высокого RTT (~104 мс) + BDP / congestion-window**. Доказательство: 4 потока дали рост ×1.8 (28→51) — при жёстком лимите линии рост не произошёл бы.
**Почему Jellyfin дёргается прямо:** Jellyfin отдаёт видео одним последовательным HLS-потоком (один TCP). Один поток душится RTT-штрафом до ~28–50 Мбит, а BluRay-файл в пиках идёт к 20+ Мбит → с 104 мс RTT сегменты не успевают → стоп-кары. Файл The.Jungle.Book.1967.720p.BluRay ≈ 7.1GB/~78мин → средний ~12 Мбит/с, пики выше.
## Факты ИЗ ЛОГОВ Jellyfin (подтверждают: транскодинг не причина в этих тестах)
- Реальный транскод с `libx264` + reduce был только на "Snatch" (тестовые короткие старты каждые ~5 с — клиент переподключался).
- "Один день в Стамбуле"/"Рождественские хроники" — ремукс `-codec:v:0 copy` в HLS (не перекодирование), стоп на ~2-3 сек.
- В моменте (пока ТВ крутит 720p) — ffmpeg-дочерних процессов нет, папка transcodes пуста → **прямой stream/direct, транскодинг не идёт**.
## 🧭 2026-09-21: развилка решена — многопоточный HLS не существует в Jellyfin/webOS
Перепроверено по первоисточникам (см. [[personal/tech/multistream-single-flow-limit]]):
- Jellyfin «multiple parallel connections» — **Planned** 5 лет, кода нет (230 голосов).
- hls.js multi-segment prefetch (#6753) — открыт, не реализован.
- webOS-приложения используют **нативный media pipeline** → подменить логику загрузки нельзя.
- **Несколько xray-туннелей не помогут** — один физический путь, одно congestion window.
- Speedtest 120 Мбит = 8 параллельных сессий. Одна сессия упирается в **~28–45 Мбит** (подтверждено замерами ниже).
**Рабочие пути:** ограничить битрейт в клиенте / Moonfin с буфером / **Lampac на Кра́кене**
(буфер 50–100 МБ + GStreamer транскод) / prefetch-proxy. Полный разбор — в
[[personal/tech/multistream-single-flow-limit]].
## Решение / направление
1. **Правильное лекарство** (не мультипоток ради мультипотока, а либо снижение латентности, либо запас по битрейту под single-flow): лимит транскода ~12–18 Мбит, ЛИБО гнать трафик ТВ→TrueNAS через **xray tunnel** (`vpn.mallexxx.duckdns.org`, смотри `[[xray-reverse-tunnel-kraken-truenas]]`) вместо прямого межоператорского пути.
2. Jellyfin **не умеет** штатно разбивать один плейбек на параллельные TCP. Параллельность (28→51 Мбит) достижима только поднятием файла способом «качалка в N коннектов» + прокси, либо через туннель.
3. Задача замера скорости через **`xray-test-client`** контейнер (teddysun/xray, SOCKS `127.0.0.1:1080`) — НЕ завершена: команда замера была заблокирована юзером; способ/endpoint (стучались на внутренний `192.168.2.197:8096`) предложен неверно.
## Связанный локальный кейс (Kraken, same-LAN)
> Тот же симптом «ТВ Jellyfin Direct Play дёргается» 2026-09-02, но в **локальной сети** (Kraken RPi5, дом) — причина ДРУГАЯ. См. `family/how-to/kraken-network.md`.
> **Как отличать кейсы:** если Jellyfin-хост в одной LAN с ТВ (ping < ~10 мс) → дёрганье Direct Play почти всегда из-за **линка 100 Мбит/с** на сервере, а НЕ полосы/RTT. Проверка: `cat /sys/class/net/<iface>/speed` (это Kракен упал 1G→100M). Если хост в другой сети/операторе (ping ~104 мс, как Taiga) → ограничение по одному TCP-потоку из-за RTT. «99 Mbps» в UI = битрейт 4K remux-файла (обычно ~60–100 Mbps), НЕ скорость сети/линка.
### Endpoint-факты для замера туннеля
- Локальный тестовый xray-клиент на Mac: контейнер **`xray-test-client`** (`127.0.0.1:1080->1080/tcp`), конфиг `/Users/admin/xray-test/config.json`, оставлен на `kraken-user`.
- Per-user egress на `vpn.mallexxx.duckdns.org`: `user1` → direct TrueNAS `90.189.160.148`; `kraken-user` → reverse через Kraken `92.62.70.41`.
- Конфиг клиента лежит на Mac отдельно (не в vault); бэкап direct-клиента: `/Users/admin/xray-test/config.json.bak-user1-direct-20260902-1227`.
---
## 🔴 2026-09-21 — РАЗБОР: почему speedtest 120 Мбит ≠ Jellyfin не тормозит. Что делать
> Контекст: Alex (Бишкек) сообщил, что плейбек Jellyfin на ТВ тормозит даже по проводу, но **speedtest через reverse-туннель показал до 120 Мбит**. Гипотеза Alex: «поднять реальный VPN в 192.168.2.x через VLESS и проверить, может заработает». Ниже — разбор, почему это не поможет, и что реально может.
### ❌ Что опровергнуто этой сессией
**1. «Speedtest доказал, что 120 Мбит физически можно — значит туннель/multi-tunnel даст столько же».**
Speedtest гоняет **8 параллельных TCP-сессий**, каждая со своим congestion window. 8 × ~15 Мбит = 120 Мбит. Это доказывает, что канал **пропускает** 120 Мбит суммарно. Это **НЕ** доказывает, что **одна** сессия получит 120 Мбит. Наши замеры это уже показывали: 1 поток = 28 Мбит, 4 потока = 51 Мбит (×1.8). Скорость TCP ≈ окно / RTT; при RTT 104 мс для 120 Мбит нужно окно ≈ **1.5 МБ «в полёте»**, одна сессия до такого не разгоняется при потерях на межоператорском стыке.
**Правильная модель (не «узкая труба», а «кассы»):** канал пропустит 120, но **только если запрашивать 8 потоками одновременно**. У Jellyfin — один покупатель в одной кассе.
**2. «Поднять несколько xray-туннелей и распараллелить».**
Не сработает: **физический путь один** (ТТК → Ростелеком, хоп 8 = +50 мс). N туннелей по одному пути делят один congestion window → суммарно не больше, чем один, плюс накладные расходы. Это MPTCP/bonding-территория, а он агрегирует **разные** пути. Аналогия Alex «узкое место — линк между провайдерами» — верно; вывод «значит, надо прокинуть больше туннелей» — нет, линк пропускает 120 Мбит, но не одному потоку.
- Честный путь к «несколько путей» — только **второй независимый линк** (мобильный 4G/5G backup-WAN на TrueNAS) + MPTCP/OpenMPTCProuter.
**3. «VLESS/REALITY-туннель уберёт лимит».**
Уже проверено 2026-09-02 (см. раздел «Замеры скорости туннелей» в `[[xray-reverse-tunnel-kraken-truenas]]`): direct через `vpn.mallexxx` = **~37 Мбит**, reverse через Kraken = **~45 Мбит** (нестабилен). Оба — в том же коридоре, что и прямой путь (28 Мбит single-flow). Туннель идёт тем же маршрутом; REALITY/Vision добавляет обёртки и обычно чуть хуже прямого. **Строить «реальный VPN в 192.168.2.x» смысла нет — он уже есть (`vpn.mallexxx`), и он не помог.**
### ✅ Что реально работает — ранжировано
| # | Подход | Механизм | Усилие | Шанс |
|---|---|---|---|---|
| 1 | **Лимит битрейта в клиенте** (10–15 Мбит) | Транскод на TrueNAS; один поток 10 Мбит проходит с запасом ×3 | 2 мин | **Высокий** |
| 2 | **Moonfin / Breezyfin** (webOS-клиенты) | Нативный pipeline + транскод-лимит в UI + лог «кто отказал в Direct Play» | ~30 мин (Homebrew Channel) | Средний (диагностика) |
| 3 | **Prefetch-proxy на стороне клиента** | Прокси тянет файл/HLS **8 параллельными Range-запросами**, отдаёт клиенту из локального кэша → клиент видит «быстрый сервер» | Высокое (писать/настраивать) | Средний |
| 4 | **BBR + HTTP/3 на TrueNAS** | BBR вместо CUBIC держит cwnd на long-haul; Caddy умеет HTTP/3, но webOS-клиент его не использует | 30 мин | +20–50%, не ×4 |
| 5 | **Второй ISP + MPTCP** | Настоящая агрегация разных путей | Очень высокое / деньги | **Ноль** без второго линка |
### 🔑 Ключевое различие для варианта 3 (и почему он единственный «правильный»)
Параллелизм рождается от **независимых HTTP-запросов** (каждый = своё TCP-окно), а НЕ от мультиплексирования транспорта.
- ✅ **Клиент/prefetch-proxy делает 8 Range-запросов** → 8 независимых окон → 120 Мбит возможно.
- ❌ **8 xray-туннелей + mux** → одно логическое окно, порезанное на 8 → head-of-line blocking, выигрыша нет.
Prefetch-proxy **обязан стоять на стороне клиента** (Mac/ТВ в Бишкеке), не на TrueNAS — иначе параллельные запросы всё равно идут через узкий канал по отдельности, выигрыш частичный.
### 🔴 КРИТИЧНО: клиент Alex — LG webOS (`Jellyfin for WebOS 1.2.2`)
Официальный webOS-клиент — **обёртка вокруг веб-интерфейса**, внутри **один HTML5 `<video>` element = один TCP-поток**. Ни настройки числа соединений, ни Range-префетча.
### 📋 Исследование альтернативных webOS-клиентов (2026-09-21)
**Оба проверены по первоисточникам (GitHub/вики).**
| | **Moonfin** | **Breezyfin** |
|---|---|---|
| Проект | `Moonfin-Client/Smart-TV` (общий код Tizen+webOS), 409★, 1153 коммита, 58 форков | `botagas/Breezyfin`, 63★, 6 форков |
| Версия | 2.5.1 | v0.2.1 (21 авг 2026), **beta**, 112 коммитов сверх upstream |
| Сайт | moonfin.io | breezyfin.app |
| webOS | **3.0+ / 2016+** | 5.0+ |
| Движок | Enact/Sandstone + **Starfish** (нативный webOS pipeline) | Enact Sandstone, HTML5 + нативный webOS player |
| **Параллельные потоки** | ❌ **НЕТ** (один HTML5 video element) | ❌ **НЕТ** |
| Транскод-лимит в UI | ✅ **есть** (*Playback & SyncPlay → Video Playback Preferences → Transcoding Limits*: Max Streaming Bitrate / Max Resolution) | не заявлено явно |
| Лог «кто отказал в Direct Play» | ✅ **есть** (*Settings > About > Diagnostics & Logging*; отчёт называет причину отказа) | Есть diagnostics/logs, формулировка не заявлена |
| Fallback-цепочка | Direct Play → native transcode → **hls.js** | Direct Play → Direct Stream → Transcode + explicit consent перед HDR/DV-даунгрейдом |
| Jellyfin backend | минимум **10.9.0**; **Jellyfin 12 совместим** (`ApiKey`) | 12 auth fix: legacy `X-Emby-Authorization`/`X-Emby-Token` за флагом `EnableLegacyAuthorization` (по умолчанию off) |
| Emby | ✅ | ❌ |
| codec-профиль | per-TV профиль, сообщается серверу; на webOS транскод fallback **HEVC→H264**, когда сервер запрещает HEVC; FLAC direct play в MP4/MKV на **webOS 5+** (до 8 каналов) | adaptive; JASSUB Canvas2D для сабтитров (WebGL на webOS ненадёжен) |
| Аудио passthrough | DTS/DTS-HD/TrueHD bitstream; **на webOS — экспериментально**; Force TrueHD/Atmos | не заявлено |
| Сабтитры | PGS client-side, ASS/SSA через **libass**, DVD/DVB burn-in сервером, отдельный стиль для HDR | configurable client/bitmap |
| Live TV/DVR | ✅ (webOS 5+) | ❌ |
| SyncPlay | ✅ | ✅ (native Jellyfin SyncPlay + JellyWatchParty) |
| Установка | **Homebrew Channel** (не истекает) или Dev Manager Desktop / `ares-install` | Homebrew catalog или IPK |
| Лицензия | MPL 2.0 | GPL-3.0-only |
**Ключевой факт по установке:** LG Developer Mode **истекает каждые 50 часов** → sideloaded-приложения удаляются. **Homebrew Channel-путь НЕ истекает** (root-эксплойт, не Dev Mode). Оба клиента есть в основном каталоге Homebrew Channel (`repo.webosbrew.org`). → Установка через Homebrew Channel убирает главный минус sideload.
**Проверка через Homebrew-каталог:** `https://repo.webosbrew.org/apps/com.breezyfin.app/`, `https://repo.webosbrew.org/apps/org.jellyfin.webos/`.
### ⚠️ Честный вывод по клиентам
Moonfin/Breezyfin **НЕ дадут 120 Мбит** — они не распараллеливают поток. Их ценность:
1. **Endpoint-лимит битрейта в UI** — то же лекарство, что ручной лимит, но штатно.
2. **Лог «почему не Direct Play»** — диагностика, которой у официального клиента нет. Сразу различит «сеть душит» vs «кодек/аудио отказали».
3. Нативный pipeline вместо веб-обёртки → меньше оверхеда.
4. Homebrew Channel = без истечения Dev Mode.
**Настоящее распараллеливание остаётся только за prefetch-proxy (вариант 3) — клиенты его не заменяют.**
### Готовые инструменты для prefetch-proxy (найдены 2026-09-21)
- **`aria3`** (PyPI) — multi-threaded streaming proxy с кэшем и умным prefetch.
- **`node-HLS-Proxy`** (warren-bank) — prefetch `.ts`-сегментов, hook-функции для управления префетчем.
- **`jspeedstreamer`** (conorh) — Java-прокси, multiple parallel requests.
- **nginx `proxy_cache` + `slice`** — кэширует byte-ranges, а не файлы целиком (штатный механизм под Range-prefetch).
- **`JellyfinCache`** (ArnyminerZ) — прокси-кэш между клиентом и Jellyfin-сервером. ⚠️ Ставится на стороне **клиента**, не сервера.
### Предложенный план (НЕ начат, ждёт решения Alex)
1. Проверить версию Jellyfin на TrueNAS (нужно ≥10.9.0 для Moonfin). *~2 мин, ничего не меняет.*
2. Поставить **Moonfin** через Homebrew Channel. *~30 мин.*
3. Включить Diagnostics & Logging, проиграть проблемный файл.
4. Прочитать лог: кто отказал в Direct Play и почему.
5. По результату: сеть → лимит битрейта или prefetch-proxy; кодек → подбор профиля.
**Статус: план предложен, Alex решения не дал. Ничего не менялось — ни на TrueNAS, ни на ТВ, ни в туннелях.**
---
## ❌ «Поднять несколько xray-туннелей» — почему НЕ поможет (разобрано 2026-09-21)
**Прямой вопрос Alex:** *«что помешает поднять несколько xray tunnels и использовать их? в тесте speedtest 120mbit показывало через наш реверс туннель»*
**Ответ: ничего не помешает поднять, но скорости это не даст.**
`speedtest` = **8 параллельных TCP-сессий**, каждая со своим congestion window → 8 × ~15 Мбит = 120.
Это доказывает, что **канал** пропускает 120 Мбит. НЕ доказывает, что **одна** сессия их возьмёт.
**Скорость одной TCP-сессии ≈ окно / RTT.** Для 120 Мбит при RTT 104 мс нужно ~1.5 МБ неподтверждённых данных «в полёте».
Одна сессия так разгоняется только при отсутствии потерь; на межоператорском стыке потери есть → окно режется вдвое →
стабилизируется на 28–45 Мбит (наши замеры 2026-09-02). Jellyfin отдаёт видео **одним потоком** → упирается в это.
| Подход | Независимых окон | Даст 120 Мбит? |
|---|---|---|
| speedtest (8 сессий) | ✅ 8 | ✅ |
| **Клиент с Range-запросами / prefetch-proxy** | ✅ N | ✅ **правильный путь** |
| Jellyfin webOS штатный | ❌ 1 | ❌ ~28–45 |
| **8 xray-туннелей + mux** | ❌ одно логическое окно | ❌ head-of-line blocking |
| MPTCP по одному физическому пути | ❌ | ❌ |
**MPTCP/bonding агрегируют РАЗНЫЕ физические пути.** У нас путь один: ТТК → Ростелеком (хоп 8, +50 мс).
N туннелей по одному пути делят один congestion window → суммарно **не больше одного**, плюс оверхед инкапсуляции.
**Единственный честный путь к реальной агрегации — второй независимый ISP.**
### ⚠️ Питфолл объяснения: аналогия «узкая труба» НЕ работает
Первое объяснение было через метафору трубы — Alex: *«ниче не понял в твоей аналогии с трубой»*.
Метафора прятала механизм. **Рабочая формулировка — через ЧИСЛО СЕССИЙ:**
«канал пропускает 120 Мбит, но только если запрашивать 8 потоками ОДНОВРЕМЕННО; одна сессия возьмёт ~28–45, потому что
не может разогнать своё окно на 104 мс RTT». Объяснять механизмом, не метафорой.
### 🔴 Многопоточный HLS в Jellyfin / hls.js — есть в планах, НЕ реализован
| Где | Статус | Факт |
|---|---|---|
| **Jellyfin** feature request #2171, 230 голосов | ✅ **Planned** (maintainer Joshua M. Boniface) | *«Jellyfin currently streams using only one connection»*. Но issue #3206 (2020) закрыт как **stale**, #6724 — как feature request. **За 5 лет кода нет.** |
| **hls.js** issue #6753 (окт 2024) | milestone 1.8.0, «Top priorities», **PR отсутствует** | Предлагает префетч **2–5 сегментов одновременно** («Concurrent Loading»). Ровно наш механизм — но не сделано |
| **ExoPlayer** issue #5978 | proposal | Параллельные DASH/HLS-сегменты. Android, не webOS |
| **webOS-клиенты** | ❌ невозможно | Нативный video element = чёрный ящик, число соединений не настраивается. Moonfin/Breezyfin/официальный — все однопоточны |
**Вывод: ждать нечего.** Ни от обновления Jellyfin, ни от новых клиентов. Реальные многопоточные решения —
только **внешние прокси/префетчеры** (см. «Готовые инструменты для prefetch-proxy»).
---
## 🆕 Lampac — самохостируемый backend для Lampa (рассмотрен 2026-09-21, НЕ внедрён)
**`lampac-nextgen/lampac`** (форк `immisterio/Lampac`) — ASP.NET Core (.NET 10), MIT, `linux/amd64`+`linux/arm64`.
Порт по умолчанию **9118**. Ставится **одним контейнером** и отдаёт плагины самой Lampa.
**Закрывает сразу всё, что разбиралось по частям:**
| Компонент | Что даёт |
|---|---|
| **TorrServer** | встроен как subprocess — отдельный контейнер не нужен |
| **JacRed** | агрегатор торрент-индексаторов, **Jackett-совместимый** |
| **GStreamer** | **HLS/fMP4 транскод** (заменяет legacy FFmpeg, плагин `/gst.js`) — решает MKV/HEVC-проблему webOS |
| **LampaWeb** | хостит саму Lampa UI + собирает widgets: `/lg.ipk` для LG webOS, `/samsung.wgt` для Tizen |
| **TmdbProxy** | локальный кэш TMDB API |
| **DLNA/UPnP**, Tracks, Sync, TimeCode, Playwright, WAF, GeoIP | прочее |
**Установка (Docker):**
```bash
git clone https://github.com/lampac-nextgen/lampac.git && cd lampac
mkdir -p lampac-docker/config lampac-docker/plugins
cp config/example.init.conf lampac-docker/config/init.conf
printf '%s' 'пароль_root' > lampac-docker/config/passwd
# раскомментировать volumes в docker-compose.yaml
docker compose up -d
curl -fsS "http://localhost:9118/version?type=hash" # проверка
# плагин для Lampa: http://<IP>:9118/online.js
```
⚠️ В контейнере рабочий каталог `/lampac`, файлы читаются **из корня**, не из `config/`. Volumes по умолчанию закомментированы.
### 🔴 Главное ограничение — Lampac НЕ решает проблему узкого канала сам по себе
TorrServer внутри Lampac работает **на том же хосте, что и Lampac**.
```
Lampac на Кра́кене: пиры → Кра́кен → [УЗКИЙ КАНАЛ, 1 TCP] → ТВ ← лимит остаётся
Lampac в Бишкеке: пиры → Mac → [быстрая локалка] → ТВ ← лимит обойдён
```
Alex **отверг вариант с Mac**: *«нахуя нам блядь на маке что-то! на кракене блядь бэкенд»*.
Значит Lampac на Кра́кене решает только участок «пиры → Кра́кен».
**Но у Lampac есть то, чего не было в других вариантах:** встроенный **GStreamer HLS-транскод** →
можно отдать ТВ поток 10–15 Мбит одним потоком, и он пройдёт. Это **не «обойти лимит», а «сделать поток лёгким»** —
другое решение той же проблемы.
### 🚧 Блокер на момент рассмотрения (снят 2026-09-21)
Диск Кра́кена был **100%** (0 байт) → Lampac не поставить, TorrServer некуда кэшировать.
Плюс `/` (SD-карта) — всего 8.4 ГБ свободно, кэш торрентов туда не влезет.
**Диск освобождён до 77% / 404 ГБ** (см. [[family/plans/watchlist-disk-overflow-fix]]) — блокер снят,
но решение по Lampac **ещё не принято**.
### Альтернатива: TorrServer прямо на ТВ
**`6ebeng/torrserver-webos`** — TorrServer как webOS-приложение (.ipk), webOS 4.x–9.x, rooted и unrooted.
Управление с любого устройства на `http://<tv-ip>:8090`. Бинарник зашит в .ipk (32-bit ARM), работает offline.
⚠️ **Плеер — встроенный HTML5 `<video>`:** *«webOS has no API to hand stream URL to native player. MP4/H.264 plays
most reliably; MKV support depends on TV's Chromium»* → **MKV может не заиграть**. Торрент тянется многопоточно
(N пиров = N окон), но контент берётся из **публичных раздач**, не из библиотеки на TrueNAS.
**Итог по Lampac/TorrServer: концепция рабочая, решение не принято. Требует ответа Alex —
что важнее: своя библиотека (тогда prefetch-proxy) или «просто смотреть кино» (тогда торрент-путь).**
@@ -56,7 +56,7 @@ related:
**Замеры 2026-09-02 через `xray-test-client`:**
| Режим | Egress | Down | Стабильность |
|---|---|---|---|
| `kraken-user` (reverse) | `92.62.70.41` (Kraken) | ~45 Мбит | нестабилен, падал к 2 МБ/с |
| `kraken-user` (reverse) | `92.62.70.41` (Kraken) | ~45 Мбит | 2.0–6.98 МБ/с (разброс замеров) |
| `user1` (direct/REALITY) | `90.189.160.148` (TrueNAS) | ~37 Мбит | 3.67–5.63 МБ/с |
| Контроль (Mac → Cloudflare напрямую) | — | ~55 МБ/с | — |
@@ -0,0 +1,209 @@
---
title: Многопоточный стриминг и обход single-flow лимита (Jellyfin / webOS / TorrServer)
created: '2026-09-21'
updated: '2026-09-22'
type: research
namespace: personal
status: research-complete
tags:
- jellyfin
- webos
- streaming
- tcp
- lampa
- torrserver
- bandwidth
related:
- '[[personal/tech/inter-site-throughput-taiga-to-mac]]'
- '[[personal/tech/xray-reverse-tunnel-kraken-truenas]]'
- '[[family/how-to/kraken-network]]'
---
# Многопоточный стриминг — что реально существует
> **Контекст:** Jellyfin на TrueNAS (Новосибирск) тормозит при просмотре из Бишкека.
> Speedtest через reverse-туннель показывает **до 120 Мбит/с**, но видео дёргается.
> Разбор: почему, и какие пути обхода существуют. Дата: 2026-09-21.
---
## 1. Почему speedtest 120 Мбит, а видео тормозит
**Speedtest открывает 8+ параллельных TCP-сессий.** Каждая независимо разгоняется своим congestion window.
8 сессий × ~15 Мбит = 120 Мбит. Это доказывает, что **канал физически пропускает 120 Мбит**.
**Но одна TCP-сессия не берёт 120 Мбит.** Скорость ≈ окно / RTT. При RTT ~104 мс для 120 Мбит нужно
окно ≈ 1.5 МБ «в полёте», не подтверждённых. Одна сессия разгоняется не сразу, при потерях окно режется
вдвое, на межоператорском стыке потери почти всегда есть.
**Замеры межсайтовой пропускной способности (2026-09-02):**
| Режим | Пропускная способность |
|---|---|
| Mac → TrueNAS, 1 SCP-поток | ~28 Мбит/с |
| Mac → TrueNAS, 4 параллельных | ~51 Мбит/с (×1.8) |
| Speedtest (8 потоков) | до 120 Мбит/с |
Рост ×1.8 при 4 потоках **доказывает**: ограничение — не полоса транзита, а **один TCP-поток при высоком RTT**.
**Аналогия (уточнена Alex):** не «узкая труба», а **8 касс, где канал пропустит 120 чел/мин —
если открыты все 8. Один покупатель с одной корзиной в одной кассе уедет не быстрее этой кассы.**
Узкое — не канал, а **одно соединение на длинном пути**.
---
## 2. Почему туннели не помогают
**Замеры 2026-09-02 через `xray-test-client`:**
| Режим | Egress | Down | Стабильность |
|---|---|---|---|
| `kraken-user` (reverse) | `92.62.70.41` (Kraken) | ~45 Мбит | нестабилен, падал к 2 МБ/с |
| `user1` (direct/REALITY) | `90.189.160.148` (TrueNAS) | ~37 Мбит | 3.67–5.63 МБ/с |
| Контроль (Mac → Cloudflare напрямую) | — | ~55 МБ/с | — |
**VLESS/REALITY идёт через тот же маршрут** ТТК → Ростелеком (хоп 8, +50 мс). Меняется инкапсуляция,
не физика. REALITY/Vision добавляет обёртки → обычно **чуть хуже** прямого, не лучше.
### 🔴 Несколько xray-туннелей НЕ дадут скорости
Это MPTCP/bonding — он агрегирует **разные физические пути**. Путь **один**.
N туннелей по одному пути разделят тот же congestion window — суммарно не больше одного, плюс оверхед.
Подтверждено замерами: reverse 45 и direct 37 — один коридор, не ×2.
**Реальная агрегация требует второго независимого линка** (мобильный 4G/5G как backup-WAN).
---
## 3. Многопоточный HLS — существует, но не реализован
| Решение | Статус |
|---|---|
| **Jellyfin** feature request «multiple parallel connections» | ✅ **Planned**, 230 голосов (features.jellyfin.org/posts/2171). Issue #3206 (2020) закрыт как stale. **5 лет, кода нет** |
| **hls.js** issue #6753 (multi-segment prefetch) | Открыт Oct 2024, milestone 1.8.0, «Top priorities». **Кода нет, PR отсутствует** |
| **ExoPlayer** #5978 (parallelize DASH/HLS) | Android, не webOS |
**Механизм, которого все ждут:** клиент тянет N сегментов одновременно → N независимых TCP-окон → 120 Мбит.
**Ровно то, что нужно. Но нигде не реализовано.**
⚠️ **На webOS это безнадёжно:** приложения используют **нативный media pipeline** (Starfish / HTML5 `<video>`).
Это чёрный ящик — подменить логику загрузки нельзя. Все клиенты (официальный, Moonfin, Breezyfin) одинаково
однопоточны.
**Вывод: ждать нечего — ни от Jellyfin, ни от новых клиентов.**
---
## 4. Что реально умеет многопоток
| Решение | Многопоток | Пригодность |
|---|---|---|
| **aria2 / aria3** | ✅ до 16 соединений | Качает файл, не стримит в плеер |
| **jspeedstreamer**, **node-HLS-Proxy** | ✅ параллельный prefetch сегментов | ✅ работает |
| **nginx `proxy_cache` + `slice`** | ✅ кэш byte-ranges | ✅ база для prefetcher |
| **Infuse (Apple TV)** | ✅ параллельные Range | ✅ но не webOS |
| **Торрент (много пиров)** | ✅ N пиров = N соединений | ✅ по природе |
| Jellyfin / Moonfin / Breezyfin | ❌ 1 соединение | — |
| 8 xray-туннелей + mux | ❌ одно логическое окно | — |
| MPTCP по одному пути | ❌ | — |
**Ключевое:** все рабочие многопоточные решения — **внешние прокси/префетчеры**, не клиенты.
Прокси стоит рядом с клиентом, тянет параллельно, отдаёт из локального кэша.
---
## 5. Lampa + TorrServer + Lampac (webOS)
### TorrServer
`YouROK/TorrServer` (3.0k★, GPL-3.0). Качает торрент, отдаёт HTTP-поток, управляет размером кэша.
- Docker: `ghcr.io/yourok/torrserver:latest`, порт **8090**
- Health check: `http://<ip>:8090/echo` → версия сервера
- Флаги: `-d PATH` (БД/конфиг), `-a` (HTTP Auth), `-m BYTES` (макс. размер потока), `-t DIR` (автозагрузка), **`--gst`** (GStreamer HLS/fMP4 транскод, сборки 141.10+), `--proxyurl`
- **Многопоточность по природе торрента** (каждый пир = отдельное соединение)
### Lampa
UI-каталог. Установка на LG webOS: **Media Station X** или LG Content Store.
⚠️ Установка `.ipk` с флешки на розничных LG **не работает**.
- Настройки → **TorrServer** → «Использовать основную ссылку» → `kraken:8090`
- **Проверка:** `http://<ip>:8090/echo`
- **Буфер настраивается: 50–100 МБ** (Настройки → Плеер) ← **этого нет в webOS Jellyfin-клиенте**
- Качество по скорости: до 10 Мбит → 720p; 10–25 → 1080p; >25 → 4K
- Plugin API открыт (`window.Lampa`): `Lampa.Component.add`, `Lampa.Activity.push`, `Lampa.Controller.add`, `Lampa.Player.play`, `Lampa.Scroll`
- Плагины: `etor` (TorrServer), `kinopoisk.js` (папка «Буду смотреть», **лимит 50**), `synology_dlna.js` (DLNA)
### 🔥 Lampac — всё в одном контейнере
`immisterio/Lampac` / `lampac-nextgen/lampac` (MIT, .NET 10, порт **9118**).
Внутри: **TorrServer** (subprocess) + **JacRed** (Jackett-совместимый индексатор) + **GStreamer транскод** +
**DLNA** + **TmdbProxy** + **LampaWeb** (хостит UI, отдаёт `/lg.ipk` для LG).
- Плагин для Lampa: `http://<IP>:9118/online.js`
- Проверка: `curl -fsS "http://localhost:9118/version?type=hash"`
- ⚠️ В контейнере рабочий каталог `/lampac`, файлы читаются **из корня**, не из `config/`. Volumes по умолчанию закомментированы
### ⚠️ Торрент-стримеры НЕ смотрят твою библиотеку
Показывают **публичные раздачи**, не файлы локальной библиотеки. Popcorn Time на webOS нэйтивно не было.
---
## 6. 🔴 TorrServer/Lampac на Кра́кене проблему НЕ решает
**Многопоточность торрента работает только на участке «пиры → TorrServer».**
Участок **«Lampac/TorrServer → ТВ» — тот же один TCP-поток** через узкий линк.
```
Lampac на Кра́кене: пиры → Кра́кен → [УЗКИЙ ЛИНК, single-flow] → ТВ ❌
```
**Но** Lampac даёт то, чего не было: **буфер 50–100 МБ** + **GStreamer HLS-транскод** — можно отдать
ТВ лёгкий поток 10–15 Мбит, который проходит одним соединением.
**Это другое решение той же проблемы:** не «обойти узкий канал», а **«сделать поток достаточно лёгким»**.
---
## 7. Ранжированные пути (актуальный вывод)
| # | Путь | Усилие | Шанс |
|---|---|---|---|
| 1 | **Ограничить битрейт** в webOS-клиенте (10–15 Мбит) | 2 мин | Средний, работает сегодня |
| 2 | **Moonfin / Breezyfin** — нативный pipeline, буфер | ~30 мин sideload | Средний |
| 3 | **Lampac на Кра́кене** — буфер + GStreamer транскод | Среднее | Средний |
| 4 | **Prefetch-proxy** (nginx slice / node-HLS-Proxy) | Высокое (пилить) | Высокий, но сложно |
| 5 | **Второй ISP на TrueNAS** + MPTCP | Дорого | Единственный честный путь к агрегации |
### 🟡 Развилка: Lampac НЕ смотрит локальную библиотеку
Путь №3 подходит для **«просто кино»** — публичные раздачи через TorrServer.
Для **«своей библиотеки»** нужно отдельное решение: Lampac/TorrServer файлы библиотеки не отдают
→ идти в путь №4 (prefetch-proxy) либо в шаг 7 плана (плагин библиотеки).
⚠️ **Развилка помечена 2026-09-22 как выдуманная мной, а не поставленная Alex.**
Alex на неё ответил «Чё блядь». **Не требовать от Alex ответа на этот вопрос повторно.**
Делать шаги 1–6 плана — они от развилки не зависят.
Разбор и отвергнутые варианты: [[personal/plans/lampac-kraken]].
---
## Факты webOS-клиентов (проверено)
| | **Moonfin** | **Breezyfin** |
|---|---|---|
| Версия | 2.5.1, 409★ | v0.2.1 (авг 2026), 63★, beta |
| webOS | 3.0+ (2016+) | 5.0+ |
| Движок | Starfish (нативный) | HTML5 + Enact Sandstone |
| Транскод-лимит в UI | ✅ явно есть (`Transcoding Limits`) | не заявлен |
| Диагностика «кто отказал в Direct Play» | ✅ **есть** (Diagnostics & Logging) | есть |
| Jellyfin backend | 10.9.0+, Jellyfin 12 ✅ | 12 auth fix |
| Установка без истечения | ✅ **Homebrew Channel** (не Dev Mode) | ✅ Homebrew catalog |
⚠️ **Dev Mode на LG истекает через 50 часов** → sideloaded app исчезает. **Homebrew Channel не истекает** —
оба клиента есть в его каталоге.
⚠️ **Ни один не распараллеливает поток.** Кодеки определяет железо ТВ, не клиент.
---
## Связанные заметки
- [[personal/tech/inter-site-throughput-taiga-to-mac]] — замеры RTT/полосы Taiga ↔ Mac
- [[personal/tech/xray-reverse-tunnel-kraken-truenas]] — reverse-туннель, замеры egress
- [[personal/plans/lampac-kraken]] — план развёртывания Lampac + блокер «не библиотека»
- [[family/how-to/kraken-network]] — линки ТВ, история торможения 4K
- [[family/projects/media-toolbox-taiga]] — медиа-стек TrueNAS
@@ -710,10 +710,10 @@ Rollback network fix: вернуть compose-бэкап на Kraken и выпо
| Режим | egress IP | Средний down | Разброс | Комментарий |
|---|---|---|---|---|
| `kraken-user` (reverse) | `92.62.70.41` (Kraken) | ~5.7 МБ/с (~45 Мбит) | 2.0–6.98 МБ/с | нестабилен, убывающий по ходу |
| `kraken-user` (reverse) | `92.62.70.41` (Kraken) | ~5.7 МБ/с (~45 Мбит) | 2.0–6.98 МБ/с | убывающий по ходу замера |
| `user1` (direct/REALITY) | `90.189.160.148` (TrueNAS) | ~4.6 МБ/с (~37 Мбит) | 3.67–5.63 МБ/с | cachefly 4×10MB |
Вывод: оба egress-режима туннеля дают ~35–45 Мбит/с с нестабильностью — **не кратно быстрее** прямого межоператорского пути (~28 Мбит single-flow), туннель не даёт надёжного запаса под stрим пиковых битрейтов BluRay (~20+ Мбит). Для jellyfin-стрима на ТВ туннель не решает проблему дёрганья.
Вывод: оба egress-режима туннеля дают ~35–45 Мбит/с (разброс 2.0–6.98 МБ/с) — **не кратно быстрее** прямого межоператорского пути (~28 Мбит single-flow), туннель не даёт надёжного запаса под stрим пиковых битрейтов BluRay (~20+ Мбит). Для jellyfin-стрима на ТВ туннель не решает проблему дёрганья.
Контроль (не туннель, Mac напрямую до Cloudflare): ~55 МБ/с. Туннель ~в 10× медленнее прямого локального интернета.
@@ -0,0 +1,727 @@
---
title: Xray Reverse Tunnel — Kraken ↔ TrueNAS
created: '2026-09-01'
updated: '2026-09-23'
type: tech
namespace: personal
tags:
- xray
- reverse
- kraken
- truenas
- tunnel
- networking
confidence: high
related:
- '[[family/how-to/vps-qentra]]'
- '[[family/how-to/truenas-infrastructure]]'
- '[[family/how-to/kraken-access]]'
- '[[family/how-to/rasputin-router]]'
- '[[personal/tech/xray-outbound-subscription-3xui]]'
downgrade_to_26.4.25: >-
portal+bridge BOTH pinned to 26.4.25; required but insufficient by itself.
verified_fix_2026_09_02: >-
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
> ## ✅ 2026-09-23 — КАНАЛ ЖИВ, ПРОВЕРЕНО END-TO-END ПОСЛЕ ПОЧИНКИ 20.09. IP КРА́КЕНА ИЗМЕНИЛСЯ.
>
> **Первая проверка канала после фикса гонки docker↔mount (2026-09-20). Результат — работает.**
>
> | Проверка | Результат |
> |---|---|
> | SOCKS `xray-reverse-portal:12345` → `api.ipify.org` (из контейнера в сети `caddy_default`) | **`92.62.77.233`** |
> | TrueNAS напрямую `curl https://api.ipify.org` | `90.189.160.148` |
> | Вывод | IP разные ⇒ **payload идёт через Кра́кен**, канал живой |
> | Portal `netstat` | `::ffff:172.16.1.7:12346 ← ::ffff:92.62.77.233:32529 ESTABLISHED` |
> | `xray-reverse-bridge` (Кра́кен) | Up, образ `teddysun/xray:26.4.25`, `network_mode: host`, uptime с 2026-09-20 16:30 |
>
> 🔴 **IP Кра́кена ИЗМЕНИЛСЯ: `92.62.70.41` → `92.62.77.233`.** Прежний `92.62.70.41` зафиксирован во множестве мест этого документа и в `family/how-to/*` — при проверках брать актуальный из живого запроса, а не из доков.
>
> **Команды проверки (воспроизводимо, с TrueNAS):**
> ```bash
> ssh truenas_admin@mallexxx.duckdns.org \
> 'docker run --rm --network caddy_default curlimages/curl:latest curl -s --max-time 20 \
> --socks5-hostname xray-reverse-portal:12345 https://api.ipify.org'
> # ожидаем IP Кра́кена (92.62.77.233), НЕ 90.189.160.148 (TrueNAS)
>
> ssh truenas_admin@mallexxx.duckdns.org \
> 'docker exec xray-reverse-portal netstat -an | grep 12346'
> # ожидаем ESTABLISHED от IP Кра́кена
> ```
>
> ### Вывод для `kraken-user`
> Правило `kraken-user-via-reverse` (user `kraken-user` → outbound `via-kraken` → SOCKS `xray-reverse-portal:12345`) **прописано в шаблоне 3x-ui** и, судя по живому каналу, должно работать. **End-to-end с клиентом `kraken-user` в этой сессии НЕ перепроверялся** — проверен только сам канал через SOCKS портала. Это разные вещи: канал может быть жив, а клиентский маршрут — нет.
>
> ### Новый план использования этого канала — ❌ ЗАКРЫТ
> Задача «доступ к `192.168.2.x` как к локальным адресам» (запрос Alex 2026-09-23) разобрана в плане **[[personal/plans/lan-access-via-reverse-tunnel]]**. Итог: **через Xray reverse не реализуется** — портал отклоняет как forward-proxy (см. раздел «🚫 АРХИТЕКТУРНЫЙ ПРЕДЕЛ» ниже). Эксперимент откачен 2026-09-23.
>
> ### 🔧 ЭКСПЕРИМЕНТ 2026-09-23: ОТКАЧЕН, КАНАЛ НЕ ТРОНУТ (детали — в плане)
> Обе правки конфигов были **выполнены, завалидированы** (`xray run -test` → `Configuration OK.`) и протестированы. Сквозной проход **НЕ получился** — вскрыт архитектурный предел (см. раздел ниже). По решению Alex **всё откачено 2026-09-23**; канал `kraken-user` вернулся в исходное рабочее состояние.
>
> | Что | Файл | Изменение (ОТКАЧЕНО) |
> |---|---|---|
> | ~~Бридж (Кра́кен)~~ | `/home/kraken/xray-reverse/config.json` | ~~inbound `lan-in`: `dokodemo-door`, `0.0.0.0:12345`, `followRedirect:true` + routing `lan-in → conn`~~ → **возвращён исходный (`inbounds: false`)** |
> | ~~Портал (TrueNAS)~~ | `/mnt/RED_2TB/docker/reverse-portal/config.json` | ~~outbound `direct` + routing `192.168.2.0/24 → direct`~~ → **возвращён исходный (`local → reverse-out`)** |
> | ~~Хост Кра́кена~~ | iptables | ~~`nat PREROUTING REDIRECT --to-ports 12345`~~ → **правило удалено**, `PREROUTING` чист |
>
> Бэкапы (сохранены): `/home/kraken/xray-reverse/config.json.bak-lan-in-20260923-130541`, `config.json.bak-v3-20260923-132753`, `/home/kraken/backups/iptables.bak-20260923-130541`, `/mnt/RED_2TB/docker/reverse-portal/config.json.before-lanroute`.
## 🚫 АРХИТЕКТУРНЫЙ ПРЕДЕЛ Xray REVERSE: forward-proxy в приватную сеть ЗАПРЕЩЁН (2026-09-23)
> Это **не** баг конфига, **не** версия и **не** REALITY. Это **намеренная защита Xray**, и её надо знать до того, как планировать подобные схемы.
**Попытка:** завернуть трафик клиентов `192.168.1.0/24` в адреса `192.168.2.x` (сеть TrueNAS) через reverse-канал Кра́кен↔TrueNAS.
**Результат — цепочка доходит до портала и там умирает:**
| Шаг | Лог | Итог |
|---|---|---|
| Mac → Кра́кен `lan-in` | `accepted tcp:192.168.2.197:80 [lan-in -> conn]` | ✅ перехват, трафик ушёл в туннель |
| Туннель → портал | `received request for tcp:192.168.2.197:80` | ✅ дошло до TrueNAS |
| Портал выпускает | `for safety reasons, user a81c3179-… is not allowed to use forward proxy` | ❌ **отклонено** |
**Официальное обоснование** (дока Xray, outbound `freedom`):
> Traffic from **VLESS reverse proxy** blocks **all targets** by default. VLESS/VMess/Trojan/Shadowsocks inbounds block **private and reserved IP ranges** by default. To allow clients access to internal services, explicitly configure `allow` rules.
**Почему это не обходится правкой правила:** портал видит «клиент просит сходить на `192.168.2.197`» и классифицирует это как **forward proxy** — попытку использовать сервер как открытый прокси. `finalRules`-allow в принципе позволяет обойти, **но** тогда «домашней» (внутренней) стороной обязан быть **Кра́кен**, а целевой сетью — **его** локалка `192.168.1.x`. Цель `192.168.2.x` при этом недостижима: reverse-канал выдаёт `reverse-out` на портале и `reverse-in` на бридже, а не наоборот.
**Вывод:** направление задачи («в подсеть TrueNAS из сети Кра́кена») **не совпадает** с направлением, которое поддерживает reverse-архитектура. Через Xray reverse это **не реализуется** — нужна другая технология (WireGuard / обычный forward-прокси на клиенте).
**Релевантный use case из доки — только «Remote Return Home»** (`xtls.github.io/en/document/level-2/vless_reverse.html`, Use Case 2): клиент → **публичный сервер** → `reverse-out` → туннель → **внутреннее устройство** → его локалка. Ровно это и описано выше.
**Рассмотренные и отклонённые альтернативы (2026-09-23):**
| # | Вариант | Почему не выбран |
|---|---|---|
| 1 | Отказаться, откатить | ✅ **выбрано Alex** |
| 2 | SOCKS на стороне клиента (Mac) через `vless-proxy :1080` / `xray-admin` | не «через ASUS»; нужен SOCKS-aware клиент или routing на Mac; не работает для других устройств |
| 3 | **WireGuard на TrueNAS** (белый IP + порт есть) | даёт полный IP-стек (ICMP, UDP, Samba-обзор) — **открытый вариант**, если задача вернётся; минус — новая служба на TrueNAS (RAM 17/21 ГБ, на пределе) |
### Питфоллы, добытые в этом эксперименте (применимы к любой подобной задаче)
| Питфолл | Суть |
|---|---|
| `dokodemo-door` + `127.0.0.1` **не принимает** REDIRECT-трафик | Пакет приходит с внешнего адреса клиента (`192.168.1.57`) — bind на loopback его отвергает (`HTTP 000` за 0.005 с). Нужен `listen: 0.0.0.0` (+ firewall). |
| `iptables nat PREROUTING` **не действует** на локально-исходящий трафик | Проверка `curl` с того же хоста, где стоит правило = **ложный негатив**: счётчик 0. Нужен посторонний хост либо транзит (netns / контейнер с кастомным маршрутом). |
| `redirect: ""` в `freedom` — невалидно | Пустая строка ломает конфиг. Не использовать как «не менять адрес». |
| `xray run -test` читает stdin | Под SSH **виснет** без `< /dev/null`. Касается и валидации, и любого `sudo`. |
| `sudo` через SSH на Кра́кене | Требует `< /dev/null`; иначе `Connection closed by remote host` / `Broken pipe`. Документированный питфолл — повторён дважды за сессию. |
| На Кра́кене **нет `ifconfig`** | Каждый вызов печатает `command not found` в stderr (засоряет вывод, безвредно). Использовать `ip`/`ip addr`. |
| Тест `PHY`/транзита на однохостовой машине | Для эмуляции «другого хоста в сети» использован `ip netns` + veth — рабочий приём; **обязательно** убирать за собой (`ip netns del`, `ip link del`). |
> ## ✅ 2026-09-20 — КОРЕНЬ 2026-09-15 НАЙДЕН: ГОНКА Docker ↔ mount, НЕ конфиг и НЕ версия
>
> **Симптом:** `kraken-user` не выходил (portal на TrueNAS жив, но от бриджа — ноль звонков на `12346`).
>
> **Истинная причина (не имеет отношения к Xray/REALITY/версиям):** `dockerd` на Kraken стартовал на **26 с раньше**, чем смонтировался USB-HDD с `data-root`, поэтому загрузил **0 контейнеров** — включая `xray-reverse-bridge`. Бриджа просто не было запущено → канал не поднимался → `reverse-out` не создавался → `curl` через SOCKS пусто.
>
> | Событие | Время |
> |---|---|
> | Boot Kraken | Sep 15 **17:29:17** |
> | dockerd (PID 1324) старт | **17:31:01** |
> | Диск `sda1` смонтирован | **17:31:27** |
>
> **Доказательства целостности:** `docker-data/containers/` = 4.7G, **35 контейнеров целы**, включая `xray-reverse-bridge` и `cloudflared`; образ `teddysun/xray:26.4.25` на месте. `docker info` врёт `Containers=0`.
>
> **Дефекты конфига, породившие гонку:** `docker.service` без `RequiresMountsFor=`; дубль строки `6194539b` в `/etc/fstab`.
>
> **Что это НЕ:** это **не** регрессия #6242, **не** REALITY mismatch, **не** `network_mode` — все прежние гипотезы по 2026-09-15 снимаются. Проверенный фикс 2026-09-02 (`26.4.25` + `network_mode: host`) остаётся в силе и не трогается.
>
> **План и статус (обновлено 2026-09-20): ✅ ВЫПОЛНЕНО И ПРОВЕРЕНО.**
> 1. ✅ Backup → `/home/kraken/backups/docker-recovery-20260920-105228/`.
> 2. ✅ `systemctl restart docker` → 25 контейнеров загружены, 12 Up (в т.ч. `xray-reverse-bridge`).
> 3. ✅ Drop-in `/etc/systemd/system/docker.service.d/mounts.conf` с `RequiresMountsFor=` + `After=` маунт-юнита → проверено `systemctl show docker -p Requires -p After` (маунт в обоих). **Гонка закрыта, reboot-безопасно.**
> 4. ✅ fstab: убран дубль строки `6194539b` (+ дубль bind-mount journal).
> ⚠️ `docker start` вручную **не потребовался**: RestartPolicy в daemon state есть (`unless-stopped`), контейнеры поднялись сами. Ранее записанное «RestartPolicy=null» — ошибка чтения `hostconfig.json` (он не отражает живую политику).
> Полный план и команды — [[family/how-to/kraken-access]], секция «2026-09-20».
>
> **Урок диагностики:** если portal пишет `non existing outTag: reverse-out` и «ноль соединений на 12346» — **сначала проверять, жив ли контейнер `xray-reverse-bridge` на Kraken** (`docker ps`), а не конфиг. 2026-09-15 этот шаг был пропущен: записали «Kraken недоступен → ждать», хотя машина была жива по LAN (`192.168.1.15`), а не запущен был только docker-контейнер бриджа.
> ## 🔴 2026-09-15 — ТУННЕЛЬ НЕ РАБОТАЕТ: KRAKEN НЕДОСТУПЕН (не конфиг) [СУПЕРСИДЕНО 2026-09-20 — см. выше]
>
> **Клиент `kraken-user` перестал выходить в интернет.** Причина — **не** конфиг портала и **не** 3x-ui: **хост Kraken недоступен по всем путям** (SSH через `ssh-kraken.qentra.top` → `timed out during banner exchange`; `10.99.1.2:22` → `Operation timed out`; DNS `kraken` → NXDOMAIN).
>
> | Что | Состояние |
> |---|---|
> | `xray-reverse-portal` (TrueNAS) | ✅ Up 13 дней, `12345` + `12346` в LISTEN, конфиг цел |
> | Соединения от бриджа на `12346` | ❌ **ноль** — от Kraken никто не звонит |
> | Выход через SOCKS `12345` | ❌ пусто (норма — `92.62.70.41`) |
>
> **Диагностика (короткая):**
> ```bash
> docker exec xray-reverse-portal netstat -an | grep 12346 # пусто = бридж молчит
> curl -s --max-time 20 --socks5-hostname 127.0.0.1:12345 https://api.ipify.org
> ```
>
> ⚠️ **Не принимать за поломку:** в логах портала будет `app/dispatcher: non existing outTag: reverse-out` — это **ожидаемо**, пока бридж не подключён. Тег `reverse-out` объявлен в `inbounds[interconn].clients[0].reverse.tag` (не в `.outbounds`) и создаётся Xray'ем автоматически только при живом бридже. **Конфиг портала править НЕ нужно.**
>
> **Дальше:** проверять Kraken через панель хостинга/консоль провайдера. Решение Alex (2026-09-15): «подождём, может оживет». Статус прошлой проверки (2026-09-02) — ниже.
> ## 🔀 НЕ ПУТАТЬ с egress-подпиской (2026-09-15)
> У `xray-admin` **три независимых механизма выхода**, их легко перепутать:
> | Механизм | Кто выходит | Док |
> |---|---|---|
> | `user1` → outbound `direct` | клиент выходит через **TrueNAS** `90.189.160.148` | ниже |
> | `kraken-user` → `via-kraken` → **этот** reverse-туннель | клиент выходит через **Кра́кен** `92.62.70.41` | **этот док** |
> | `vless-space` → `space-balancer` (`space-01…10`) | клиент выходит через **внешнюю подписку** `profilegrid.net` | [[personal/tech/xray-outbound-subscription-3xui]] |
>
> Reverse-туннель (portal на TrueNAS + bridge на Кра́кене) — отдельные контейнеры, `xray-admin` его лишь **использует** как outbound `via-kraken` (SOCKS `xray-reverse-portal:12345`). Подписочный клиент `vless-space` reverse-туннель **не задействует**.
> **Статус: ✅ ВНЕДРЕНО И ПРОВЕРЕНО 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.
> ## 🔴 2026-09-20 — ВЕРХНЯЯ ТОЧКА ВХОДА: оба туннеля были down из-за ГОНКИ DOCKER↔СМОНТИРОВАНИЕ ДИСКА. ФИКС ПРИМЕНЁН.
>
> **Симптом:** `vless reverse proxy kraken→truenas` не работает И `cloudflared ssh tunnel` down. Kraken доступен по LAN (`192.168.1.15`, hostname `kraken`).
>
> **Корень — НЕ конфиги Xray и НЕ cloudflared. Одна причина на оба симптома:**
> `dockerd` стартовал **раньше**, чем монтировался USB-диск с `docker-data`, и загружал пустое состояние → 0 контейнеров в памяти.
>
> | Событие | Время (boot Sep 15) |
> |---|---|
> | Boot Kraken | 17:29:17 |
> | `sda1` виден ядром | +130 с → 17:31:27 |
> | **dockerd PID 1324 стартовал** | **17:31:01** ← на 26 с РАНЬШЕ диска |
> | Диск смонтирован | 17:31:27 |
>
> **Почему оба туннеля:** `cloudflared` и `xray-reverse-bridge` просто не были загружены. Не падали — их не существовало для daemon.
>
> **Ничего не потеряно:** `containers/` = 4.7G, **35 контейнеров целы**, образы, 32 volume. Daemon их просто не видел.
>
> **Диагностический признак (запомнить):** `docker ps -a` пусто, но `docker-data/containers/` полон → это **всегда** гонка data-root, а не потеря данных. Проверять: `docker info --format "{{.DockerRootDir}} | containers={{.Containers}}"` vs содержимое `docker-data/containers/`.
>
> ### ✅ ФИКС (применён, проверен)
> 1. **Backup:** `/home/kraken/backups/docker-recovery-20260920-105228/` (fstab, daemon.json, xray-reverse).
> 2. **Немедленно:** `sudo systemctl restart docker` → диск уже смонтирован → все контейнеры загрузились.
> 3. **Защита от повтора при reboot** — создан drop-in `/etc/systemd/system/docker.service.d/mounts.conf`:
> ```ini
> [Unit]
> RequiresMountsFor=/srv/dev-disk-by-uuid-6194539b-03e0-4f33-986b-4da09834e82f/docker-data
> After=srv-dev\x2ddisk\x2dby\x2duuid\x2d6194539b\x2d03e0\x2d4f33\x2d986b\x2d4da09834e82f.mount
> ```
> Проверено: `systemctl show docker -p Requires -p After` → маунт-юнит в **Requires И After**. dockerd физически не стартует раньше диска.
> 4. **fstab** — убран ДУБЛЬ строки для 6194539b (внизу была ручная `UUID=6194539b...` вне OMV-блока → «Duplicate entry in fstab» в journal) и дубль bind-mount `/var/log/journal`. Осталось 1 вхождение (OMV-блок). Грепом проверено.
>
> ### Проверка после фикса
> `sudo systemctl restart docker` → `containers=25`, 11-12 Up. Критичные поднялись автоматом: cloudflared, xray-reverse-bridge, jellyfin, sonarr, radarr, prowlarr, portainer, transmission, rclone, watchtower, flaresolverr.
> ⚠️ `hermes-kraken` — `Restarting (1)` (crash-loop, не связан с этой задачей, был до правок).
>
> **Питфолл:** `RestartPolicy` в `hostconfig.json` показывает `null` (reflection исходного `docker run`), но в state policy есть — при рестарте daemon контейнеры поднимаются сами. Не пугаться `null`.
>
> **Питфолл диагностики:** `ls docker-data` требует sudo (root:root 711). `sudo -n` работает без апрува — использован `sudo -n ls/jq`.
>
> **Урок:** USB-диск на этом узле поднимается ~130 с. Любой сервис, зависящий от `docker-data` на этом диске, ОБЯЗАН иметь `RequiresMountsFor`. Без него — та же гонка.
## Контекст / Почему
- **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.org` → `xray-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 /vless` → `xray-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`:
```caddy
@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.ipify` → `92.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 -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` + `common/mux: received request for udp:reverse:0`.
4. ❌ **Тест payload НЕ прошёл даже на TCP+REALITY**: `curl --socks5 127.0.0.1:12345 http://api.ipify.org` → **`code=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 в интернет):
```json
{
"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 docker` → **`activating`** (не `active`), демон застрял, накоплено множество зависших docker-процессов (ps/run/compose).
- **Причина: USB-HDD снова не поднялся** — `lsblk /dev/sda` → **`0B`** (без раздела). 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.json` → `freedom/direct` с `"finalRules":[{"action":"allow"}]`.
- **Reverse-канал к TrueNAS жив**: bridge лог 2026-09-02 13:12: `dialing TCP to mallexxx.duckdns.org:12346` → `tunneling request` → `received 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 off` → **`Empty reply from server`** (соединение закрыто без ответа). Трафик доходит до portal, уходит в reverse-out, НО не возвращается от bridge → ответ теряется.
### 🔑 ИСТИННЫЙ КОРЕНЬ (2026-09-02, интернет-поиск): issue XTLS/Xray-core #6242 — регрессия bridge в v26.5+
Симптомы точно совпадают с [issue #6242](https://github.com/XTLS/Xray-core/issues/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:latest` → `teddysun/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-15 (вечер): KRAKEN НЕДОСТУПЕН — `kraken-user` отвалился НЕ из-за правок БД
> **Симптом:** Alex сообщил «не работает больше `vless-ws-kraken-user`, даже из бэкапа». Логичное подозрение — мои правки БД 3x-ui. **Подозрение опровергнуто фактами.**
**Диагностика (по порядку, все — факт):**
| Проверка | Результат |
|---|---|
| `docker ps` на TrueNAS | `xray-reverse-portal` **Up 13 days**, `xray-admin` Up, `caddy` Up. `xray-reverse-bridge` **отсутствует** (он на Kraken) |
| порт `12345` (SOCKS) | LISTEN ✅ |
| порт `12346` (interconn) | LISTEN ✅ |
| выход через SOCKS :12345 → `api.ipify.org` | ❌ **пусто** (ни IP, ни ошибки) |
| `netstat` соединений на 12345 | много **`CLOSE_WAIT`** от `172.16.1.5` — сессии оборваны, новых нет |
| соединений от бриджа на `12346` | ❌ **НОЛЬ** (бридж не звонит) |
| логи портала | `app/dispatcher: non existing outTag: reverse-out` + `from tcp:172.16.1.5:… [local -> reverse-out]` |
| TrueNAS напрямую | `90.189.160.148` ✅ (интернет на NAS есть) |
| `ssh kraken@10.99.1.2` | ❌ **Operation timed out** |
| `ssh ssh-kraken.qentra.top` (cloudflared) | ❌ **Connection timed out during banner exchange** |
| DNS `host kraken` | ❌ **NXDOMAIN** |
> **🔴 ВЫВОД: хост Kraken недоступен по ОБОИМ задокументированным путям** (WG-адрес `10.99.1.2` и cloudflared-туннель `ssh-kraken.qentra.top`). `kraken-user` не работает, потому что **машина Kraken выключена/недоступна**, а не из-за правок в `x-ui.db`. Совпадение по времени.
**ВАЖНО про `non existing outTag: reverse-out`:** это **НЕ дефект конфига портала**. В reverse-схеме Xray тег `reverse-out` объявляется **не в `outbounds[]`**, а в `clients[].reverse.tag` инбаунда `interconn` — и создаётся **только когда бридж подключён**. Ошибка = бридж не подключён. Конфиг портала (`/mnt/RED_2TB/docker/reverse-portal/config.json`, 1287 б, бинд-маунт `:ro`) **корректен**, проверено 2026-09-15.
> ⚠️ **Сделано по ходу диагностики (требует внимания):** выполнен `docker restart xray-reverse-portal` — портал перезапущен, но `CLOSE_WAIT` ушли, а новых соединений от Kraken **не появилось** (ожидаемо: машины нет). Портал после рестарта — Up, оба порта LISTEN. **Рестарт портала сам по себе проблему не решает** — она на стороне Kraken.
**Что проверять, когда Kraken вернётся:**
```bash
# 1) канал поднялся?
docker exec xray-reverse-portal sh -c 'netstat -an' | grep 12346
# 2) output жив?
curl -s --max-time 20 --socks5-hostname 127.0.0.1:12345 https://api.ipify.org
# ожидаем: 92.62.70.41
```
**Питфолл диагностики:** `curl --socks5-hostname 127.0.0.1:12345` на TrueNAS **не** проверяет туннель, если портал сам не может выйти — надо сравнивать с `curl` напрямую (`90.189.160.148`), иначе не отличить «портал сломан» от «Kraken недоступен».
## ❌ ИСТОРИЯ ДИАГНОСТИКИ 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:12346` → `tunneling request to unknown` → `received request for udp:reverse:0`. Portal принимает (лог: `proxy/vless/inbound: received request for tcp:v1.rvs.cool:0` → `dispatching request to udp:reverse:0`).
- **НО payload по-прежнему НЕ проходит**: тест curl через `xray-reverse-portal:12345` → `Empty 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 docker` → `active`, диск `/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-23 — ГРАНИЦА ВОЗМОЖНОСТЕЙ: reverse НЕ работает как «вход в чужую приватную сеть»
>
> **Попытка:** завернуть клиентов `192.168.1.0/24` (за ASUS) на адреса `192.168.2.x` **через этот reverse-туннель** — то есть использовать его как «вход в сеть TrueNAS».
>
> **Результат: невозможно по дизайну.** План и полный разбор — [[personal/plans/lan-access-via-reverse-tunnel]].
>
> **Механизм отказа (воспроизведён вживую):**
> ```
> портал: for safety reasons, user a81c3179-… is not allowed to use forward proxy
> ```
> **Официальная дока Xray (freedom outbound):**
> > Traffic from **VLESS reverse proxy** blocks **all targets** by default. Traffic from VLESS/VMess/Trojan/Shadowsocks/Hysteria/WireGuard inbounds blocks **private and reserved IP ranges** by default. To allow clients access to internal services, explicitly configure `allow` rules.
>
> То есть reverse **намеренно** не даёт ходить в приватные сети — защита от превращения сервера в открытый прокси. Это **не баг конфига** и не лечится версией Xray.
>
> **Единственная рабочая конфигурация reverse (Use Case 2, «Remote Return Home»):**
> ```
> клиент → PUBLIC SERVER (портал) → reverse-out → туннель
> ↓
> INTERNAL DEVICE (бридж)
> ↓
> freedom + finalRules[allow ip <локальная сеть>]
> ↓
> <сеть «внутренней» стороны>
> ```
> Целевая сеть — **локалка «внутренней» стороны** (здесь — Кра́кен, `192.168.1.0/24`), **не** сеть публичной стороны. Направление «пойти в сеть TrueNAS снаружи» reverse-каналом не решается.
>
> **Что это НЕ задевает:** существующие сценарии работают как раньше —
> `kraken-user` (egress через Кра́кен) использует `reverse-in → direct` и не затронут;
> `user1` / `vless-space` — вообще другой механизм (direct / подписка).
>
> ### ✅ Побочный факт: канал впервые проверен end-to-end после починки 2026-09-20
> через SOCKS портала: `92.62.77.233` ≠ напрямую с TrueNAS `90.189.160.148`.
> ⚠️ **WAN-IP Кра́кена изменился: `92.62.70.41` → `92.62.77.233`.** Везде в этом доке и в `kraken-access.md` фигурирует старый — при следующей правке актуализировать.
> ## ✅ Верифицированный фикс 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`
```yaml
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:12345` → `92.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, поэтому делать только для диагностики/отката.
## ✅ Subscription-канал (auto-обновление клиентов) — 2026-09-15
> Проверено живьём: клиенты панели отдаются **ссылкой подписки**, а не только одиночным `vless://`.
>
> | Клиент | Ссылка подписки | Egress |
> |---|---|---|
> | `user1` | `https://vpn-panel.mallexxx.duckdns.org/sub/68c5cy5n5ui138yh` | `direct` → TrueNAS `90.189.160.148` |
> | `kraken-user` | `https://vpn-panel.mallexxx.duckdns.org/sub/f43074a029dc656e` | `via-kraken` → Kraken `92.62.70.41` |
>
> Ответ — **base64-список `vless://`** (стандартная подписка: `type=ws`, `security=tls`, `path=/vless`, `host=vpn.mallexxx.duckdns.org`). В клиенте: удалить ручной профиль → «Add subscription» с ПОЛНЫМ путём `…/sub/<subId>` → включить auto-update (6–12 ч).
> **Питфолл:** вбитый руками `vless://` авто-обновляться не будет — только ссылка подписки. Ссылка открыта без авторизации (кто знает `subId` — имеет ключ) — открытый вопрос к Alex.
> Полный разбор + команды проверки + что панель 3.7.0 умеет по подпискам: [[family/how-to/truenas-infrastructure]] → раздел `xray-admin` → «SUBSCRIPTION-КАНАЛ».
## ✅ 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:
```json
{
"protocol": "socks",
"tag": "via-kraken",
"settings": {
"address": "xray-reverse-portal",
"port": 12345
}
}
```
После глобальных `geoip:private -> blocked` и `bittorrent -> blocked` добавлено правило:
```json
{
"type": "field",
"user": ["kraken-user"],
"outboundTag": "via-kraken",
"ruleTag": "kraken-user-via-reverse"
}
```
Проверка одним и тем же локальным Docker-клиентом `xray-test-client`, менялся только client ID:
- `user1` → HTTPS `api.ipify.org` → `90.189.160.148` (TrueNAS direct).
- `kraken-user` → HTTP и HTTPS `api.ipify.org` → `92.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`.
### ⚠️ СОСТОЯНИЕ КЛИЕНТА 2026-09-02 (после замеров скорости туннеля)
Контейнер `xray-test-client` **переключён с `kraken-user` на `user1-direct`** для замеров скорости direct-пути, и НЕ возвращён обратно. Активная конфигурация = **`user1` (direct, REALITY)**.
- Контейнер: `xray-test-client` (image `teddysun/xray:latest`; лог старта показал «Xray 26.7.28 started»), bind-mount `/Users/admin/xray-test/config.json:/etc/xray/config.json:ro`, SOCKS `127.0.0.1:1080→1080`.
- **Как переключать:** в `/Users/admin/xray-test/`:
- `user1-direct` = `config.json.bak-user1-direct-20260902-1227` (id `ce320965-6956-4759-84bb-7cb71cfc6252`) — выход TrueNAS `90.189.160.148`.
- kraken-user = прежний активный, сохранён в `config.json.current-kraken-user` (id `93a5dc4b-1b8d-4af5-9363-eb0091734293`) — выход Kraken `92.62.70.41`.
- Смена: `cp <файл> /Users/admin/xray-test/config.json && docker restart xray-test-client`.
- Размер обоих конфигов одинаковый (831 байт), inbound общий (SOCKS :1080 noauth), различие только в VLESS-outbound (client id / egress).
### 📊 Замеры скорости туннелей (2026-09-02, с Mac через `xray-test-client` :1080)
> 🔗 **2026-09-21 — важное дополнение:** вопрос «поднять ещё VLESS-туннелей и распараллелить, чтобы Jellyfin залетал» разобран в `[[inter-site-throughput-taiga-to-mac]]` → раздел «2026-09-21 — РАЗБОР». Кратко: speedtest 120 Мбит = 8 параллельных TCP-сессий; один поток всё равно 28–45 Мбит, и N туннелей по **одному физическому пути** (ТТК→Ростелеком) этого не меняют. Документ также содержит сравнение webOS-клиентов (Moonfin/Breezyfin) и инструменты prefetch-proxy.
Замер пропускной способности каждого egress-режима (скачивание файлов по SOCKS-прокси контейнера; источник http cachefly + ovh; Cloudflare с этого egress режется = 0 B/s → не показатель):
| Режим | egress IP | Средний down | Разброс | Комментарий |
|---|---|---|---|---|
| `kraken-user` (reverse) | `92.62.70.41` (Kraken) | ~5.7 МБ/с (~45 Мбит) | 2.0–6.98 МБ/с | убывающий по ходу замера |
| `user1` (direct/REALITY) | `90.189.160.148` (TrueNAS) | ~4.6 МБ/с (~37 Мбит) | 3.67–5.63 МБ/с | cachefly 4×10MB |
Вывод: оба egress-режима туннеля дают ~35–45 Мбит/с с нестабильностью — **не кратно быстрее** прямого межоператорского пути (~28 Мбит single-flow), туннель не даёт надёжного запаса под stрим пиковых битрейтов BluRay (~20+ Мбит). Для jellyfin-стрима на ТВ туннель не решает проблему дёрганья.
Контроль (не туннель, Mac напрямую до Cloudflare): ~55 МБ/с. Туннель ~в 10× медленнее прямого локального интернета.
Бэкапы 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` осталась пустой.
## Связанные заметки
- [[family/how-to/vps-qentra]] — VPS на 2026-09-01 УДАЛЁН
- [[family/how-to/truenas-infrastructure]] — TrueNAS Caddy/контейнеры
- [[family/how-to/kraken-access]] — Docker Kraken
- [[family/how-to/rasputin-router]] — прежний VLESS-туннель на VPS (тоже требует пересмотра, VPS нет)
- [[family/how-to/wireguard-vpn]] — WG Eagle↔VPS↔Kraken (VPS-звено теперь мёртво)