From 5d8ba5d61b8b72b2e2de9a922a5e505c3a43470d Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Wed, 2 Sep 2026 12:35:46 +0600 Subject: [PATCH] [2026-09-02] eagle: family/how-to/truenas-infrastructure.md family/how-to/truenas-infrastructure.md.bak-per-user-20260902-1229 personal/tech/xray-reverse-tunnel-kraken-truenas.md personal/tech/xray-reverse-tunnel-kraken-truenas.md.bak-per-user-20260902-1229 --- family/how-to/truenas-infrastructure.md | 15 +- ...frastructure.md.bak-per-user-20260902-1229 | 511 ++++++++++++++++++ .../xray-reverse-tunnel-kraken-truenas.md | 42 ++ ...aken-truenas.md.bak-per-user-20260902-1229 | 388 +++++++++++++ 4 files changed, 953 insertions(+), 3 deletions(-) create mode 100644 family/how-to/truenas-infrastructure.md.bak-per-user-20260902-1229 create mode 100644 personal/tech/xray-reverse-tunnel-kraken-truenas.md.bak-per-user-20260902-1229 diff --git a/family/how-to/truenas-infrastructure.md b/family/how-to/truenas-infrastructure.md index 3e2ea34c..9d65f9ed 100644 --- a/family/how-to/truenas-infrastructure.md +++ b/family/how-to/truenas-infrastructure.md @@ -208,12 +208,12 @@ arr, caddy, cups, filebrowser, gitea, hermes, immich, inpx-web, inpxer, library, | Volume | `/mnt/RED_2TB/docker/xray-admin:/etc/x-ui` (там `x-ui.db`) | | Сеть | `caddy_default` (внешняя) | | Панель | `https://vpn-panel.mallexxx.duckdns.org/` (Caddy → xray-admin:2053) | -| Inbound | `vless-ws` port `10095`, tag `in-10095-tcp`, path `/vless`, host `vpn.mallexxx.duckdns.org`, client id `ce320965-6956-4759-84bb-7cb71cfc6252` (user1) | +| Inbound | `vless-ws` port `10095`, tag `in-10095-tcp`, path `/vless`, host `vpn.mallexxx.duckdns.org`; clients: `user1` (direct TrueNAS), `kraken-user` (reverse via Kraken) | | Sub-сервер | `[::]:443` (path /sub), панель `[::]:2053` | | Env | `TZ=Asia/Novosibirsk`, `PUID=950`, `PGID=950` | | Ports (host) | `54321:54321` (не используется панелью — внутри панель на 2053, можно убрать) | -**Статус (2026-09-01):** контейнер **Up**, панель HTTP 200. Reverse **портал** развёрнут отдельным контейнером `xray-reverse-portal` (см. ниже). 3x-ui поддерживает reverse (`clientReverseTags`). +**Статус (2026-09-02):** контейнер **Up**, панель HTTP 200. Reverse portal развёрнут отдельным контейнером `xray-reverse-portal`; per-user egress работает end-to-end. **✅ ПРОВЕРЕНО РАБОТАЕТ (2026-09-02): `vpn.mallexxx.duckdns.org:443` — это ФУНКЦИОНАЛЬНЫЙ Xray-СЕРВЕР, НЕ только reverse-frontend.** Проверено end-to-end юзером с Mac. Ключевые факты с живой машины: - Контейнеры `xray-admin` (Up 21h) и `caddy` (Up 20h) оба живы. Панель `vpn-panel` → HTTP 200. TCP `vpn.mallexxx.duckdns.org:443` снаружи открыт. @@ -224,6 +224,15 @@ arr, caddy, cups, filebrowser, gitea, hermes, immich, inpx-web, inpxer, library, - **⚠️ Так и твой клиент должен подключаться:** TLS терминирует Caddy на 443, inbound `security: none` → в конфиге КЛИЕНТА `network: ws`, TLS поверх на `vpn.mallexxx.duckdns.org` (**НЕ включать двойной TLS внутрь WS**). - **⚠️ Xray 26.7.28 удалил `allowInsecure`** в клиентских tlsSettings (мигрировано на `pinnedPeerCertSha256`/`verifyPeerCertByName`). Если в клиентском конфиге был `allowInsecure: true` — клиент падает. Это частая причина «не подключается». +**Per-user egress (2026-09-02):** + +- `user1`, ID `ce320965-6956-4759-84bb-7cb71cfc6252` → default outbound `direct` → TrueNAS IP `90.189.160.148`. +- `kraken-user`, ID `93a5dc4b-1b8d-4af5-9363-eb0091734293` → routing rule `user: ["kraken-user"]` → SOCKS outbound `via-kraken` at `xray-reverse-portal:12345` → Kraken IP `92.62.70.41`. +- Private destinations and BitTorrent remain blocked before the per-user rule. +- Persistent global template is stored in `settings.key=xrayTemplateConfig`; do not edit `/app/bin/config.json` manually because it is generated. +- Verified with the local `xray-test-client`: unchanged `user1` returned TrueNAS IP; changing only the client UUID to `kraken-user` returned Kraken IP over both HTTP and HTTPS. +- Pre/post backups: `/mnt/RED_2TB/docker/backups/xray-per-user-20260902-1200/`. + > ⚠️ База `x-ui.db` была **уже настроена** под эту Caddy-интеграцию (inbound vless-ws:10095, subDomain vpn-panel), поэтому панель заработала «из коробки». Бэкап базы/Caddyfile до изменений: `/mnt/RED_2TB/docker/backups/reverse-xray-3xui-20260901-113625/`. ### `xray-reverse-portal` — Xray reverse portal (TrueNAS, добавлен 2026-09-01) @@ -241,7 +250,7 @@ arr, caddy, cups, filebrowser, gitea, hermes, immich, inpx-web, inpxer, library, | local | `:12345` SOCKS (точка входа для клиентов сети TrueNAS), проброс `12345:12345` | | Env | `LOGLEVEL` | -**✅ Reverse внедрён на TCP+REALITY (2026-09-01 выполнен) + ИСТИННЫЙ КОРЕНЬ НАЙДЕН 2026-09-02.** Portal пересоздан на TCP+REALITY (`12346:12346`), OpenWrt DNAT `внешний:12346 → 192.168.2.197:12346` добавлен, bridge на Kraken пересоздан. REALITY-ключи: server PrivateKey `0JTjeirfviDqCr63wSnisvU7DV6SpR9_9V2l_EUHmkk`, PublicKey `GhsphQLT_0fwOvK45MHeAgG3sBQsFtw7lQfUIbrLMQU`, shortId `1451ef281caf5905`, SNI `www.cloudflare.com`. **НЕ ВНЕДРЕНО (ждёт команды):** payload по-прежнему не проходит даже с фиксом #6612 → истинный корень [issue #6242](https://github.com/XTLS/Xray-core/issues/6242) (регрессия bridge в v26.5+, у нас 26.7.28). Решение: сдаунгрейд bridge до `teddysun/xray:26.4.25`. Детали: [[personal/tech/xray-reverse-tunnel-kraken-truenas]]. +**✅ Reverse работает end-to-end (2026-09-02).** Portal работает на Xray `26.4.25`, TCP+REALITY+Vision (`12346:12346`); OpenWrt DNAT `внешний:12346 → 192.168.2.197:12346`. Bridge на Kraken также закреплён на `26.4.25` и обязательно использует `network_mode: host`; Docker bridge/NAT сбрасывал reverse mux. HTTP/HTTPS egress проверен как `92.62.70.41` (Kraken). Детали и rollback: [[personal/tech/xray-reverse-tunnel-kraken-truenas]]. ### Home Assistant — детали diff --git a/family/how-to/truenas-infrastructure.md.bak-per-user-20260902-1229 b/family/how-to/truenas-infrastructure.md.bak-per-user-20260902-1229 new file mode 100644 index 00000000..3e2ea34c --- /dev/null +++ b/family/how-to/truenas-infrastructure.md.bak-per-user-20260902-1229 @@ -0,0 +1,511 @@ +# TrueNAS — инфраструктура + +> Обновлено: 2026-09-02 (vpn.mallexxx:443 = РАБОЧИЙ Xray-сервер, проверено end-to-end; vless-proxy outbound мёртв) + +> ## ⚠️ ПРИОРИТЕТ 2026-09-01: VPS qentra.top УДАЛЁН → vless-proxy и сетевые туннели сломаны +> - **VPS `91.207.28.205` больше НЕ существует** (вся его Xray/OpenVPN/WG-инфраструктура утрачена). Подробно: [[family/how-to/vps-qentra]]. +> - **Контейнер `vless-proxy`** (teddysun/xray): inbound SOCKS `0.0.0.0:1080` + HTTP `0.0.0.0:1081`, но **outbound ⇒ мёртвый `v.qentra.top:443`** (VLESS+WS+TLS, path `/qentra`, id `2D9F24C4-21FE-4784-9843-F11C384DA67A`). ⇒ Hermes-Taiga (ходит через `vless-proxy:1080`) **сейчас БЕЗ рабочего прокси**. **Уточнено 2026-09-02:** `v.qentra.top` по-прежнему ресолвится, но в **Cloudflare IP** (`104.21.54.239`, `2606:4700:...`) — DNS-запись на qentra.top осталась в Cloudflare, хотя VPS сам удалён; origin'а за ней нет, поэтому трафик через прокси не идёт. Контейнер `vless-proxy` сам ЖИВ (Up 8 days), путь через его SOCKS наружу не проходит. +> - **⚠️ На корневом `mallexxx.duckdns.org:443` НЕ Xray**, а обычный **Caddy/nginx с валидным Let's Encrypt сертификатом** (проверено `openssl s_client` 2026-09-01). **НО на поддомене `vpn.mallexxx.duckdns.org:443` — РАБОЧИЙ Xray-сервер** (см. раздел `xray-admin` ниже, проверено end-to-end 2026-09-02). +> - **Наружу открыты только 22 (SSH) и 443 (HTTPS/TLS)** с Kraken; `8443/8964/8080/9000` closed. +> - **План замены** (выход клиентов сети TrueNAS через Kraken, Xray reverse — НЕ внедрён): [[personal/tech/xray-reverse-tunnel-kraken-truenas]]. + +> ## ✅ СТАТУС на 2026-08-25: пул ONLINE, docker поднят, почти все контейнеры Up +> **Пул RED_2TB пересоздан (2026-08-21) и работает:** `zpool status` ONLINE, rsync возврата данных завершён, `/mnt/RED_2TB/` смонтирован. +> **Docker: ПОДНЯТ на 2026-08-25.** Почти все контейнеры Up (zigbee2mqtt, webdav, vless-proxy, homeassistant, caddy, transmission, syncthing, mosquitto, nodered, immich*, gitea, filebrowser, portainer*, hermes-taiga и др.). ✅ **cups-splix поднят 2026-08-26** — образ собран заново (`docker build -t cups-splix .`), контейнер запущен `docker compose up -d`, порт 631 открыт, принтер `Samsung_CLX-216x_Series` активен (USB `04e8:3425`). Причина былого падения: образ локальный, потерян при восстановлении пула (`.ix-apps` не переносился), вручную не пересобирали. Рецепт — ниже, раздел «Печать / cups-splix». Ещё не подняты (проверить при надобности): inpxer/inpx-web/arr/ser2net. +> **⚠️ Известная проблема modbus-bridge/mbusd — гонка с udev при рестарте TrueNAS:** +> - После перезагрузки docker стартует раньше udev, поэтому `/dev/ttyZONT` и `/dev/ttyVent` на момент старта контейнеров ещё не существуют. +> - Контейнеры с `devices: /dev/ttyZONT:...` падают на `start` с `error gathering device information while adding custom device "/dev/ttyZONT": no such file or directory` (ExitCode 128/255, RestartCount=0). +> - `restart: unless-stopped` НЕ перезапускает такой контейнер (отказ до старта процесса). +> - Следствие: modbus-bridge не отвечает на шине → 485-датчики в ZONT отображаются **«недоступные»**. +> - Ручной фикс: `docker start modbus-bridge mbusd` (после готовности tty-симлинков). +> - Защита от рецидива (план, НЕ внедрён — ждёт OK Alex): `family/plans/zont-modbus-bridge-udev-race-protection.md` — POSTINIT init script с ожиданием симлинков + `docker start`. +> **⚠️ ДРУГОЕ (открытое):** пул `DEST` (IronWolf) на 2026-08-24 `DEGRADED` — разобраться, почему (отвалился mirror-член). TimeMachine (~277G) не возвращён (бэкапы macOS, вероятно не нужен — решение Alex не подтверждено). SSH с Mac по 192.168.2.197 нестабилен — использовать `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/`. +> **Контейнеры запускались через `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-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`). +> **ПЛАН (следующий шаг):** пересоздать пул RED_2TB с новой топологией `mirror {sdc,sdf}` + `mirror {sde,sdd}` (включаем WD2TB#2 зеркалом к WD2TB#1). Команды `zpool labelclear` + `zpool create` — в `family/how-to/truenas-sata-ports-and-zfs-pools.md` (раздел «Пересоздание пула 2026-08-21»). Затем вернуть данные rsync с IronWolf и восстановить инфраструктуру. +> **ПРОТОКОЛ ПОВРЕЖДЕНИЯ (история):** пул паниковал на rw-импорте (`adding existent segment to range tree`, повреждённая space map). Работал только `zpool import -o readonly=on`. In-place починки нет (mav/iXsystems) — только спасать данные и пересоздавать. Полный рецепт — в `family/how-to/truenas-sata-ports-and-zfs-pools.md`. + +## Доступ + +- **Host (external):** `mallexxx.duckdns.org` (DuckDNS) — **единственный способ** SSH/API из 192.168.1.x +- **SSH:** `truenas_admin@mallexxx.duckdns.org -i ~/.ssh/id_rsa` +- **Web UI:** http://truenas.mallexxx.duckdns.org +- **Portainer:** https://portainer.mallexxx.duckdns.org +- **Host (local network):** `192.168.2.197` — ⚠️ ИСПОЛЬЗОВАТЬ `ssh truenas_admin@mallexxx.duckdns.org`. НЕ ИСПОЛЬЗОВАТЬ локальный IP для SSH доступа! + - ⚠️ Eagle (Mac, 192.168.1.x) и Kraken (192.168.1.15) находятся в **другой подсети** + - ⚠️ Кра́кен и TrueNAS — **разные сети** (192.168.1.x vs 192.168.2.x). Доступ с Кракена на TrueNAS по локальному IP **не работает** + +## Пользователи и группы (ключевые) + +| uid | Имя | gid | Назначение | +|-----|-----|-----|------------| +| 950 | truenas_admin | 950 | SSH-пользователь, управление docker | +| 911 | transdamon | 911 | Процесс Transmission внутри контейнера | +| 921 | transmission | 921 | Старый пользователь (не используется контейнером) | +| 3000 | nas_users | 3000 | Общая группа доступа к NAS | + +## Структура папок + +``` +/mnt/RED_2TB/ +├── docker/ ← конфиги docker-контейнеров (бэкапятся → mailru-crypt:) +│ ├── caddy/ +│ ├── filebrowser/ +│ ├── ha/ ← Home Assistant +│ ├── hermes/ ← Hermes-Taiga +│ ├── homeassistant/ +│ ├── immich/ +│ ├── inpx-web/ +│ ├── inpxer/ +│ ├── mbusd/ +│ ├── modbus-bridge/ +│ ├── mosquitto/ +│ ├── nodered/ +│ ├── portainer/ +│ ├── python/ +│ ├── rclone/ +│ ├── ser2net/ +│ ├── transmission/ ← конфиг Transmission (settings.json, torrents, resume...) +│ ├── vless-proxy/ +│ ├── watchtower/ +│ ├── webdav/ +│ └── zigbee2mqtt/ +├── storage/ +│ ├── Downloads/ ← данные торрентов (монтируется в контейнер как /mnt/storage) +│ │ ├── transmission/ ← старый путь конфига (больше не используется) +│ │ └── [медиафайлы] +│ └── obsidian/ ← vault (read-only для hermes-taiga) +├── backup/ ← ручные бэкапы (бэкапятся → mailru-crypt:) +│ └── transmission-config/ ← снапшот конфига от 2026-04-30 +├── Photos/ ← фото (бэкапятся → mailru:Photos/Photos) +├── old-bu/ ← старый архив (бэкапятся → mailru:Photos/old-bu) +└── immich-photos-upload/ ← библиотека Immich (бэкапятся → mailru:Photos/immich) +``` + +## NFSv4 ACL — важно + +TrueNAS использует **NFSv4 ACL**, а не стандартный POSIX chmod/chown. +- `ls -la` показывает `----------` даже если ACL есть → всегда проверять через `midclt call filesystem.getacl ` +- Добавить запись: `midclt call filesystem.setacl '{...}'` +- `truenas_admin` не имеет passwordless sudo → root-операции только через midclt или TrueNAS UI + +## Docker-контейнеры + +| Контейнер | Image | Порт | Домен | +|-----------|-------|------|-------| +| transmission | linuxserver/transmission:latest | 9091, 51413 | transmission.mallexxx.duckdns.org | +| hermes-taiga | hermes-taiga:latest | — | — | +| vless-proxy | teddysun/xray:latest | — | — | +| filebrowser | filebrowser/filebrowser:latest | — | — | +| webdav | hacdias/webdav:latest | — | webdav.mallexxx.duckdns.org | +| homeassistant | home-assistant:stable | 8123 | mallexxx.duckdns.org | +| immich-server | immich-app/immich-server:release | 2283 | immich.mallexxx.duckdns.org | +| immich-postgres | tensorchord/pgvecto-rs:pg14-v0.2.0 | — | — | +| immich-redis | redis:7 | — | — | +| nodered | nodered/node-red:latest | 1880 | nodered.mallexxx.duckdns.org | +| mosquitto | eclipse-mosquitto:latest | — | — | +| caddy | caddy:latest | 80, 443 | reverse proxy для всего | +| rclone | rclone/rclone:latest | — | бэкап по cron | +| portainer | portainer/portainer-ce:latest | 9000 | portainer.mallexxx.duckdns.org | +| watchtower | containrrr/watchtower:latest | — | авто-обновление образов | +| inpxer | ghcr.io/hedger/inpxer:latest | 18080 | books.mallexxx.duckdns.org | +| nodered | node-red:latest | 1880 | nodered.mallexxx.duckdns.org | +| zigbee2mqtt | koenkk/zigbee2mqtt:latest | — | — | +| mbusd | 3cky/mbusd:latest | — | Modbus | +| modbus-bridge | modbus-bridge | — | — | +| cups-splix | cups-splix | — | принтер | +| xray-admin | ghcr.io/mhsanaei/3x-ui:latest | 2053 (панель), 10095 (vless-ws), 443 (sub) | vpn-panel.mallexxx.duckdns.org, vpn.mallexxx.duckdns.org | +| xray-reverse-portal | teddysun/xray:latest | 12345 (SOCKS), 12346 (VLESS-TCP REALITY interconn) | — (см. `personal/tech/xray-reverse-tunnel-kraken-truenas.md`) | + +### cups-splix — принтер Samsung CLX-216x (✅ поднят 2026-08-26; ✅ mDNS-фикс 2026-08-31 завершён) + +**Статус:** контейнер работает, принтер `Samsung_CLX-216x_Series` **idle / enabled / accepting**. CUPS слушает `0.0.0.0:631` (host-сеть). mDNS-анонс **включён** — штатная Android print service теперь видит принтер по mDNS (подробно: [[mac-print-shared-services]]). См. ниже раздел «✅ mDNS/AirPrint анонс принтера». + +Папка: `/mnt/RED_2TB/docker/cups/` → `Dockerfile`, `entrypoint.sh`, `docker-compose.yml`, `data/`→`/etc/cups`, `cache/`→`/var/cache/cups`, `spool/`→`/var/spool/cups`, `uld/`, бэкап `backup_20260831-003619.tar.gz`. + +- **Image:** `cups-splix` (локальная сборка из Dockerfile; старый образ сохранён как `cups-splix-old` для отката) +- **Dockerfile** (debian:12-slim): `cups-daemon cups-client cups-common printer-driver-splix avahi-daemon avahi-utils dbus usbutils nano procps`; `cupsadmin:admin` (группа lpadmin); `COPY entrypoint.sh`; `EXPOSE 631`; `ENTRYPOINT ["/entrypoint.sh"]` +- **entrypoint.sh:** `dbus-daemon --system --fork` → `avahi-daemon --no-drop-root --syslog` (фон) → `exec cupsd -f` +- **compose:** `image: cups-splix`, `network_mode: host`, `privileged: true`, volume `/dev/bus/usb:/dev/bus/usb`, restart `unless-stopped` (содержит устаревший `command: [cupsd -f]`, но ENTRYPOINT переопределяет — правится только через root/UI, файл 600 root) +- **Сборка/поднятие (⚠️ полное пересоздание, НЕ `docker restart`):** +```bash +cd /mnt/RED_2TB/docker/cups/ +docker build -t cups-splix-new . +docker stop cups-splix && docker rm cups-splix +docker tag cups-splix-new cups-splix && docker tag cups-splix cups-splix-old 2>/dev/null +docker compose up -d +``` + +> Полный разбор и симптом «телефон не видит принтер»: [[mac-print-shared-services]] + +### Инвентарь compose-файлов по папкам (проверено 2026-08-24) + +Каждый контейнер = своя папка `/mnt/RED_2TB/docker//`. Модель — **не один общий compose, а per-service compose** (контейнеры поднимались `docker compose up -d` из своей папки / `docker run`). + +**✅ Есть `docker-compose.yml` (поднимаются `docker compose -f ... up -d`)** — 22 шт: +arr, caddy, cups, filebrowser, gitea, hermes, immich, inpx-web, inpxer, library, mbusd, mosquitto, nodered, portainer-mcp, portainer, rclone, ser2net, syncthing, transmission, vless-proxy, watchtower, **xray-admin (3x-ui, добавлен 2026-09-01)** + +**⚠️ НЕТ compose-файла — только конфиг (восстанавливать вручную, параметры из доки ниже):** +- **ha** — Home Assistant: `/mnt/RED_2TB/docker/ha/` (automations.yaml). Образ `ghcr.io/home-assistant/home-assistant:stable`, порт `8123`, volume `/mnt/RED_2TB/docker/ha` → `/config`. +- **webdav** — `/mnt/RED_2TB/docker/webdav/` (config.yml). Образ `hacdias/webdav:latest`, домен webdav.mallexxx.duckdns.org. +- **modbus-bridge** — `/mnt/RED_2TB/docker/modbus-bridge/` (config.yml + modbus_ha_bridge.py). Образ `modbus-bridge` (локальная сборка из репо `HA-ZONT-Modbus`). Volumes: config.yml → `/app/config.yml` (ro), modbus_ha_bridge.py → `/app/modbus_ha_bridge.py` (ro). +- **zigbee2mqtt** — `/mnt/RED_2TB/docker/zigbee2mqtt/` (configuration.yaml). Образ `koenkk/zigbee2mqtt:latest`, работает через mosquitto. +- **homeassistant** — в доке упомянут как отдельный контейнер (порт 8123, volume → /config); папка `docker/homeassistant/` есть, но название контейнера в таблице `homeassistant`, а папка конфига HA фактически `ha/`. При восстановлении сверить, какой реально используется. + +### Порядок восстановления docker-стека (зависимости) + +1. **docker engine:** `systemctl enable --now docker` (после создания data-root, см. шапку). Проверка: `docker info | grep -iE "Server Version|Docker Root Dir"`. +2. **Инфраструктура/сеть:** mosquitto (MQTT) → zigbee2mqtt (нужен mosquitto) → nodered (MQTT) → caddy (прокси, тянет все домены) → vless-proxy (SOCKS5 для hermes). +3. **Умный дом:** mbusd (Modbus TCP:502) → modbus-bridge (через mbusd) → ha (homeassistant, нужен caddy для домена). +4. **Медиа/хранилище:** transmission (нужен caddy) → arr (radarr/sonarr/prowlarr) → inpxer (books), inpx-web, library → rclone, syncthing, filebrowser, webdav, gitea. +5. **Сервисы/свои:** hermes-taiga (нужен vless-proxy), portainer, portainer-mcp, watchtower, cups, ser2net. +6. **Проверка:** `docker ps`. HA: `docker exec homeassistant python -m homeassistant --script check_config --config /config`. + +### Transmission — детали +- **Config:** `/mnt/RED_2TB/docker/transmission/` (монтируется как `/config`; внутри `/config/docker-compose.yml`) +- **Данные:** `/mnt/RED_2TB/storage` (монтируется как `/mnt/storage`) +- **Download dir:** `/mnt/storage/Downloads` +- **UID/GID:** ⚠️ **по факту работает как ROOT (uid 0)**, НЕ 911/911. Причина: в `/mnt/RED_2TB/docker/transmission/docker-compose.yml` **НЕ задан `PUID`/`PGID`** → linuxserver `/init` (s6-overlay) оставляет контейнер root (подтверждено `docker exec transmission id` → root). Пользователь `transdamon`/911 (док) — это владелец конфига на хосте (`drwx------ 911 911`), но НЕ процесс внутри контейнера. + - **Зачем важно:** root-трансмишен пишет файлы как root и переживает права 0000 медиа → это причина, почему он "работает" на сломанных после restore папках. Но для pipeline с jellyfin/radarr (не-root) root-создаваемые файлы барьер. + - **План фикса (Вариант A, одобрен 2026-09-02):** добавить `PUID=950 PGID=950` и пересоздать контейнер → работает под `truenas_admin`. План: `family/documents/vault-sync/2026-09-02-restore-privilege-scope.md` §5. +- **RPC whitelist:** `172.16.6.*` +- **Web:** https://transmission.mallexxx.duckdns.org +- **Порты:** 9091 (RPC/web), 51413 (TCP/UDP peers) + +### Caddy — домены +| Домен | → | +|-------|---| +| mallexxx.duckdns.org | Home Assistant :8123 | +| transmission.mallexxx.duckdns.org | Transmission :9091 | +| immich.mallexxx.duckdns.org | Immich :2283 | +| nodered.mallexxx.duckdns.org | Node-RED :1880 | +| webdav.mallexxx.duckdns.org | WebDAV | +| books.mallexxx.duckdns.org | Inpxer :18080 🔒 basicauth (user: books-admin) | +| library.mallexxx.duckdns.org | library-app :8080 🔒 basicauth (user: books-admin) | +| portainer.mallexxx.duckdns.org | Portainer :9000 | +| truenas.mallexxx.duckdns.org | TrueNAS UI :80 | +| cam.mallexxx.duckdns.org | Камера :8090 | +| docs.mallexxx.duckdns.org | Docs :8000 | +| **vpn-panel.mallexxx.duckdns.org** | **3x-ui панель :2053** (добавлен 2026-09-01) | +| **vpn.mallexxx.duckdns.org** | **Xray VLESS-WS (путь /vless) → xray-admin:10095** (добавлен 2026-09-01) | + +### `xray-admin` — 3x-ui панель (Xray server, добавлена 2026-09-01) + +**Цель:** 3x-ui frontend для Xray-reverse туннеля Kraken↔TrueNAS (выход клиентов сети TrueNAS через Kraken). Подробно: [[personal/tech/xray-reverse-tunnel-kraken-truenas]]. + +| Параметр | Значение | +|----------|----------| +| Папка | `/mnt/RED_2TB/docker/xray-admin/` | +| Контейнер | `xray-admin` (имя важно — Caddyfile резолвит по нему) | +| Образ | `ghcr.io/mhsanaei/3x-ui:latest` (3.7.0, Xray 26.7.28) | +| Volume | `/mnt/RED_2TB/docker/xray-admin:/etc/x-ui` (там `x-ui.db`) | +| Сеть | `caddy_default` (внешняя) | +| Панель | `https://vpn-panel.mallexxx.duckdns.org/` (Caddy → xray-admin:2053) | +| Inbound | `vless-ws` port `10095`, tag `in-10095-tcp`, path `/vless`, host `vpn.mallexxx.duckdns.org`, client id `ce320965-6956-4759-84bb-7cb71cfc6252` (user1) | +| Sub-сервер | `[::]:443` (path /sub), панель `[::]:2053` | +| Env | `TZ=Asia/Novosibirsk`, `PUID=950`, `PGID=950` | +| Ports (host) | `54321:54321` (не используется панелью — внутри панель на 2053, можно убрать) | + +**Статус (2026-09-01):** контейнер **Up**, панель HTTP 200. Reverse **портал** развёрнут отдельным контейнером `xray-reverse-portal` (см. ниже). 3x-ui поддерживает reverse (`clientReverseTags`). + +**✅ ПРОВЕРЕНО РАБОТАЕТ (2026-09-02): `vpn.mallexxx.duckdns.org:443` — это ФУНКЦИОНАЛЬНЫЙ Xray-СЕРВЕР, НЕ только reverse-frontend.** Проверено end-to-end юзером с Mac. Ключевые факты с живой машины: +- Контейнеры `xray-admin` (Up 21h) и `caddy` (Up 20h) оба живы. Панель `vpn-panel` → HTTP 200. TCP `vpn.mallexxx.duckdns.org:443` снаружи открыт. +- **Inbound `in-10095-tcp`** (реальный конфиг из `bin/config.json`, Xray 26.7.28): VLESS-WS, `security: none`, WS path `/vless`, host `vpn.mallexxx.duckdns.org`. + - **client id:** `ce320965-6956-4759-84bb-7cb71cfc6252` (email `user1`) +- **Outbound:** `freedom`/`direct` — сервер имеет **СОБСТВЕННЫЙ выход в интернет** через TrueNAS (не через Kraken!). routing: geoip:private + bittorrent → blocked. +- **Тест с Mac** (временный xray-клиент в docker): VLESS+WS через `vpn.mallexxx.duckdns.org:443` → HTTP 200, выходной IP `90.189.160.148` (TrueNAS). Сервер полностью рабочий. +- **⚠️ Так и твой клиент должен подключаться:** TLS терминирует Caddy на 443, inbound `security: none` → в конфиге КЛИЕНТА `network: ws`, TLS поверх на `vpn.mallexxx.duckdns.org` (**НЕ включать двойной TLS внутрь WS**). +- **⚠️ Xray 26.7.28 удалил `allowInsecure`** в клиентских tlsSettings (мигрировано на `pinnedPeerCertSha256`/`verifyPeerCertByName`). Если в клиентском конфиге был `allowInsecure: true` — клиент падает. Это частая причина «не подключается». + +> ⚠️ База `x-ui.db` была **уже настроена** под эту Caddy-интеграцию (inbound vless-ws:10095, subDomain vpn-panel), поэтому панель заработала «из коробки». Бэкап базы/Caddyfile до изменений: `/mnt/RED_2TB/docker/backups/reverse-xray-3xui-20260901-113625/`. + +### `xray-reverse-portal` — Xray reverse portal (TrueNAS, добавлен 2026-09-01) + +**Цель:** portal-часть Xray-reverse туннеля: принимает исходящий трафик локальных клиентов сети TrueNAS (через SOCKS `:12345`) и пересылает по reverse-каналу на Kraken (bridge) → интернет через Kraken. Подробно: [[personal/tech/xray-reverse-tunnel-kraken-truenas]]. + +| Параметр | Значение | +|----------|----------| +| Папка | `/mnt/RED_2TB/docker/reverse-portal/` | +| Контейнер | `xray-reverse-portal` | +| Образ | `teddysun/xray:latest` (Xray 26.7.28) | +| Volume | `config.json:/etc/xray/config.json:ro` | +| Сеть | `caddy_default` | +| interconn | `:12346` VLESS (принимает reverse-канал от Kraken) — **сейчас на TCP+REALITY** (внутр. порт 12346, проброс `12346:12346`) | +| local | `:12345` SOCKS (точка входа для клиентов сети TrueNAS), проброс `12345:12345` | +| Env | `LOGLEVEL` | + +**✅ Reverse внедрён на TCP+REALITY (2026-09-01 выполнен) + ИСТИННЫЙ КОРЕНЬ НАЙДЕН 2026-09-02.** Portal пересоздан на TCP+REALITY (`12346:12346`), OpenWrt DNAT `внешний:12346 → 192.168.2.197:12346` добавлен, bridge на Kraken пересоздан. REALITY-ключи: server PrivateKey `0JTjeirfviDqCr63wSnisvU7DV6SpR9_9V2l_EUHmkk`, PublicKey `GhsphQLT_0fwOvK45MHeAgG3sBQsFtw7lQfUIbrLMQU`, shortId `1451ef281caf5905`, SNI `www.cloudflare.com`. **НЕ ВНЕДРЕНО (ждёт команды):** payload по-прежнему не проходит даже с фиксом #6612 → истинный корень [issue #6242](https://github.com/XTLS/Xray-core/issues/6242) (регрессия bridge в v26.5+, у нас 26.7.28). Решение: сдаунгрейд bridge до `teddysun/xray:26.4.25`. Детали: [[personal/tech/xray-reverse-tunnel-kraken-truenas]]. + +### Home Assistant — детали + +- **Image:** `ghcr.io/home-assistant/home-assistant:stable` +- **Порт:** `8123:8123` +- **Volume:** `/mnt/RED_2TB/docker/ha` → `/config` +- Конфиги редактируются **напрямую на NAS** — `docker cp` не нужен, изменения применяются после reload/restart HA. + +**Ключевые файлы конфига:** + +| Файл | Назначение | +|------|------------| +| `configuration.yaml` | Главный конфиг: интеграции, template sensors, http trusted_proxies | +| `automations.yaml` | Все автоматизации (подключён через `!include`) | +| `scripts.yaml` | Скрипты | +| `.storage/lovelace.home_plan` | Dashboard с планом этажей (JSON, управляется HA UI) | +| `www/floorplan/floor1_ha.svg` | SVG фон первого этажа | +| `www/floorplan/floor2_ha.svg` | SVG фон второго этажа | + +**Перезапуск после редактирования конфига:** +```bash +ssh truenas_admin@mallexxx.duckdns.org "docker restart homeassistant" +``` + +**Проверка конфига перед перезапуском:** +```bash +ssh truenas_admin@mallexxx.duckdns.org "docker exec homeassistant python -m homeassistant --script check_config --config /config" +``` + +### mbusd — Modbus RTU → TCP gateway + +Мост Modbus RTU → TCP: пробрасывает серийный порт в TCP 502. Используется и для вентиляции (AT2), и для ZONT-шины. + +- **Image:** `3cky/mbusd`, compose в `/mnt/RED_2TB/docker/mbusd/` +- **Порт:** `502:502` (TCP) +- **Config:** `/mnt/RED_2TB/docker/mbusd/mbusd.conf` → `/etc/mbusd.conf` (`device=/dev/ttyUSB0 speed=9600 mode=8n1`, `port=502`) +- **Device:** `devices: - /dev/ttyVent:/dev/ttyUSB0` +- **Entrypoint:** `["/usr/bin/mbusd","-d","-L","-","-c","/etc/mbusd.conf"]` +- **Pitfall udev-race:** см. ниже «Проблема modbus-bridge/mbusd после рестарта». + +### modbus-bridge — 485-датчики + виртуальные slaves для ZONT + +Кастомный Python-мост (`modbus_ha_bridge.py`, репо `HA-ZONT-Modbus`), контейнер `/mnt/RED_2TB/docker/modbus-bridge/`. + +- **Image:** `modbus-bridge` (локальная сборка, `--no-cache`). **НЕ имеет compose-файла** — создавался через `docker-compose`-подобный run; для восстановления использовать параметры ниже. +- **Device:** `devices: - /dev/ttyZONT:/dev/ttyUSB0` (внутри контейнера слушает `/dev/ttyUSB0`) +- **Volumes:** `config.yml` → `/app/config.yml` (ro), `modbus_ha_bridge.py` → `/app/modbus_ha_bridge.py` (ro) +- **Env (из compose):** `HA_TOKEN`, `MQTT_USER=zont`, `MQTT_PASS=...` +- **`network_mode: host`**; MQTT broker `localhost:1883` (mosquitto), HA `http://localhost:8123`. + +**Роль (важно — два режима работы):** +1. **Sniff (чтение)** — сниффит реальные 485-датчики на шине ZONT: **Dining=slave 1, Kids=slave 2, Bedroom=slave 3** (CO₂/температура/влажность, регистры 2 и 100) и публикует в MQTT (`modbus/sensors//...`), а также пишет в HA. +2. **Mappings (виртуальные slaves для ZONT)** — подставляет на **slave 101/102/103** (регистр 100) значения temperature от 485-датчиков: Dining→101, Kids→102, Bedroom→103. **ZONT (Modbus master) опрашивает 101/102/103 как свои внешние датчики температуры.** Есть также wifi-термостат как slave 100 (`sensor.0xa4c13862d39377e6_temperature`) и Socket 1 = slave 101 через switch (обратим внимание: 101 занят и Dining temp — переиспользуется на одном slave с разными функциями; сверить в config.yml). +3. Также через mbusd может работать с AT2 вентиляции. + +**Если modbus-bridge не слушает `ttyZONT`** (упал/не запущен) → ZONT не получает ответ на запросы slave 101/102/103 → в интерфейсе ZONT 485-датчики отображаются **«недоступные»**. + +### Проблема modbus-bridge/mbusd после рестарта TrueNAS (гонка с udev) + +**Симптом:** после перезагрузки TrueNAS `/dev/ttyZONT` и `/dev/ttyVent` присутствуют (`ttyZONT`→ttyUSB1, `ttyVent`→ttyUSB0, создаются init script id=1), НО контейнеры `modbus-bridge`/`mbusd` упали на старте и не перезапустились; 485-датчики в ZONT «недоступные». + +**Причина:** docker стартует раньше udev → при `start` контейнера устройство ещё не существует → падение ДО запуска процесса: +``` +docker inspect --format '{{.State.Error}}' +error gathering device information while adding custom device "/dev/ttyZONT": no such file or directory +# ExitCode 128 / 255, RestartCount=0 +``` +`restart: unless-stopped` такой отказ **не подхватывает** (RestartCount=0), и задержка внутри entrypoint не поможет (device mount происходит до старта процесса). + +**Ручной фикс:** `docker start modbus-bridge mbusd` (после того как симлинки созданы). + +**Защита от рецидива (план, НЕ внедрён, ждёт OK Alex):** `family/plans/zont-modbus-bridge-udev-race-protection.md` — POSTINIT init script `/mnt/RED_2TB/system/start-modbus.sh`, который ждёт появления `ttyZONT`/`ttyVent` (≤25с) и делает `docker start modbus-bridge mbusd`. + +### USB device aliases + +Файл правил: `/mnt/RED_2TB/system/99-tty-alias.rules` + +``` +SUBSYSTEM=="tty", KERNEL=="ttyUSB*", KERNELS=="?-1.6:1.0", SYMLINK+="ttyZONT" +SUBSYSTEM=="tty", KERNEL=="ttyUSB*", KERNELS=="?-1.5:1.0", SYMLINK+="ttyVent" +``` + +`?` — wildcard на префикс USB-шины (`2`, `3` и т.д.): правила работают даже если хаб переопределяется под другой контроллер (например, после подключения USB3-устройства к тому же хабу). + +Применить после изменений: +```bash +cp /mnt/RED_2TB/system/99-tty-alias.rules /etc/udev/rules.d/ && udevadm control --reload-rules && udevadm trigger +``` + +> `/etc/udev/rules.d/` на TrueNAS — tmpfs, не переживает перезагрузку. Правила применяются автоматически через **TrueNAS Init/Shutdown Scripts** (POSTINIT). + +**Просмотреть/изменить:** TrueNAS UI → System → Advanced → Init/Shutdown Scripts, или: +```bash +midclt call initshutdownscript.query +``` + +Текущая запись (id 1, POSTINIT, comment: "Map ttyUSB"): +```bash +cp /mnt/RED_2TB/system/99-tty-alias.rules /etc/udev/rules.d/ && udevadm control --reload-rules && udevadm trigger +``` + +## Hermes-Taiga агент + +| Параметр | Значение | +|----------|----------| +| Контейнер | `hermes-taiga` | +| Telegram | через общий токен, SOCKS5 прокси `vless-proxy:1080` | +| Модель | **DeepSeek Chat** (`deepseek/deepseek-chat`) | +| Auxiliary | OpenRouter (`openrouter/auto`) | +| Vault (хост) | `/mnt/RED_2TB/storage/obsidian` | +| Vault (контейнер) | `/vault:rw` | +| obsidian-mcp | `/opt/data/.local/bin/mcpvault /vault` | +| Scope | sparse: `personal/ + family/` | +| Toolsets | hermes-cli, file, web, browser | +| web_search | Tavily (`TAVILY_API_KEY` в .env) | +| web_extract | ✅ HTTP-парсинг | +| browser | ✅ Playwright/Chromium (headless, JS-heavy сайты) | +| Прокси | SOCKS5 `vless-proxy:1080` (HTTP/HTTPS/Telegram — все через прокси) | + +### SOUL.md — identity & persona (обновлено 2026-05-13) + +Файл: `/opt/data/SOUL.md` (монтируется в контейнер, читается Hermes на каждый тёрн). + +**Ключевые изменения 2026-05-13:** +- Добавлен блок `## Identity` — Тайга не ассистент, а лес: не извиняется, не суетится, говорит прямо +- Добавлен uncertainty posture: при отсутствии данных говорит "не знаю" / "нет данных в vault", не строит истории +- Тон исправлен: убрано "тёплая" (активировало female-helper архетип), оставлено "спокойная, уверенная, немногословная" +- Добавлена обязанность читать и писать в Obsidian (RULE 2, Vault Access с правильными MCP-командами) +- `display.personality` в config.yaml изменён с `helpful` на `neutral` — убирает Hermes-level "helpful" прайминг поверх soul + +**Почему важно:** `display: personality: helpful` в config.yaml инжектировался поверх soul.md и был основным источником извинений и гиперкомпенсации. + +### Починка root-проблемы (2026-05-13) +Hermes обновился — появилась проверка на root. Контейнер падал с `Refusing to run as root`. +Фикс: `HERMES_ALLOW_ROOT_GATEWAY=1` + `UV_CACHE_DIR=/tmp/uv-cache` в docker-compose.yml + пересборка с `--no-cache`. + +> ⚠️ При обновлении образа — всегда `docker build --no-cache`, иначе `.venv` остаётся от root-слоя и ломает permissions. + +## Obsidian Sync (Taiga) + +**Скрипт:** `~/sync-vault.sh` (запускается на **хосте**, не в контейнере) +**Крон:** Hermes cron job `0 * * * *` +**Bare repo:** `file:///mnt/RED_2TB/storage/git/obsidian-vault.git` +**Лог:** `/tmp/vault-sync.log` + +```bash +# Запустить sync вручную: +bash ~/sync-vault.sh + +# Посмотреть лог: +tail -20 /tmp/vault-sync.log + +# История коммитов: +git -C /mnt/RED_2TB/storage/git/obsidian-vault.git log --oneline -10 +``` + +> ⚠️ Скрипт запускается от `truenas_admin` — только этот пользователь имеет ZFS ACL доступ к bare repo и vault папке. + +Подробности: [[obsidian-sync]] + +## Home Assistant — что настроено + +### `configuration.yaml` + +- `http:` раздел: `use_x_forwarded_for: true`, `trusted_proxies: 172.16.0.0/12` — обязательно для работы через reverse proxy (Caddy) +- Modbus интеграция для вентиляторов AT2 и заслонок +- Template sensors (в блоке `template: - sensor:`): + +| Сенсор | Пример | Описание | +|--------|--------|----------| +| `dining_summary` | "24° 450ppm" | Темп и CO₂ в столовой | +| `dining_air_summary` | "65tvoc 3pm" | TVOC и частицы в столовой | +| `kids_summary` | "22° 600ppm" | Темп и CO₂ в детской | +| `bedroom_summary` | "21° 500ppm" | Темп и CO₂ в спальне | +| `at2_1_summary` | "Off" / "45%" | AT2-1: объединённые on/off + скорость | +| `at2_2_summary` | "Off" / "45%" | AT2-2: объединённые on/off + скорость | + +### `automations.yaml` + +- ГВС циркуляция: вкл (09:30) / выкл (23:00) +- Вентиляционный вентилятор вкл в 05:00 +- Проходной выключатель кабинета → toggle света в кабинете (`not_from: [unavailable, unknown]` — защита от ложных срабатываний при запуске HA) +- Подсветка лестницы: вкл/выкл по датчику освещённости +- Диммер спальни: toggle и цикл яркости +- Ночной свет в душе: присутствие + освещённость +- Уведомление: датчик протечки (котельная) +- Уведомления: низкий заряд батареи (несколько устройств) + +### Floor Plan Dashboard (`lovelace.home_plan`) + +Два вида — Ground Floor (`floor1`) и Second Floor (`floor2`) — `picture-elements` поверх SVG фона. + +**Первый этаж (`floor1`):** +- Приточные заслонки: столовая (левая/правая), кабинет +- Вытяжные заслонки: кухня, туалет 1F +- Вентилятор 3 (кухонная вытяжка) +- Метки AT2-1 / AT2-2 (`sensor.at2_1_summary` / `sensor.at2_2_summary`) +- Сауна, обогревательный кабель +- Свет кабинет (левый/правый) +- Метка столовой (`sensor.dining_summary`) и качество воздуха (`sensor.dining_air_summary`) + +**Второй этаж (`floor2`):** +- Приточные заслонки: детская, спальня, север +- Вытяжные заслонки: ванная, душ 2F +- Свет спальни (диммер) +- Метки: `sensor.kids_summary`, `sensor.bedroom_summary` + +**SVG dark mode** — встроенный CSS в SVG-файлах: +```svg + +``` + +> ЖJSON Lovelace зафиксирован в git по пути `floorplan/lovelace.home_plan.json` (справочный снимок, HA **не** подгружает его автоматически). + +--- + +## Печать / cups-splix (2026-08-26, починено) + +**Принтер Samsung CLX-216x подключён по USB к TrueNAS** (не в сети!). Единственный путь печати — контейнер `cups-splix`, который раздаёт CUPS на `192.168.2.197:631`. + +**Почему телефон не видел принтер (2026-08-26):** после пересоздания пула контейнер `cups-splix` **не был поднят** — образ локальный (не registry), стёрлся вместе с `.ix-apps`; при восстановлении его не пересобирали (пометка «проверить при надобности»). Конфиг `/mnt/RED_2TB/docker/cups/data` (это `/etc/cups`) цел → принтер прописан и подцепился после рестарта сам. + +**Рецепт подъёма (при «не вижу принтер»):** +```bash +cd /mnt/RED_2TB/docker/cups +docker build -t cups-splix . # образ локальный, собрать заново (~3.5 мин) +docker compose up -d # поднять (privileged + /dev/bus/usb) +docker exec cups-splix lpstat -p -d # проверить принтер +nc -z 192.168.2.197 631 # проверить порт наружу +``` +- Принтер: `usb://Samsung/CLX-216x%20Series?serial=9566BAGQ213134Z.&interface=1` (USB ID `04e8:3425` Samsung CLX-216x). +- Порт 631: открыт наружу после подъёма. + +### ✅ mDNS/AirPrint анонс принтера — включён 2026-08-31 (Android print service видит принтер) + +Проблема: Android **штатная служба печати** (в отличие от Samsung Mobile Print, который ходит прямо по IP) ищет принтер **только через mDNS/Bonjour** (`_ipp._tcp.local`). CUPS не анонсировал: в контейнере не было `avahi-daemon`, а `printer-dns-sd-name` в IPP был `no-value` → Android помечал принтер «недоступен», даже добавленный вручную по IP. + +**Решение (выполнено):** пересобрали cups-splix — теперь запускает `dbus-daemon` + `avahi-daemon` рядом с cupsd через `entrypoint.sh`, и в `cupsd.conf` включено `Browsing On` + `BrowseLocalProtocols dnssd`. После этого CUPS регистрирует принтер в avahi → mDNS-анонс с **`mopria-certified=1.3`** на IPv4 `192.168.2.197` физического интерфейса `enp3s0`. Android (Mopria) теперь находит принтер сам в локальной сети. + +**Что изменилось в конфиге** (папка `/mnt/RED_2TB/docker/cups/`): +- `Dockerfile`: добавлен `avahi-daemon` в apt, написан `entrypoint.sh`, `ENTRYPOINT` вместо `CMD` (`.old` образ сохранён как `cups-splix-old`). +- `entrypoint.sh`: стартует `dbus-daemon --system`, затем `avahi-daemon --no-drop-root`, затем `exec cupsd -f`. +- `data/cupsd.conf`: `Browsing Off` → `Browsing On` + добавлена строка `BrowseLocalProtocols dnssd` (бэкап `cupsd.conf.pre-avahi`). + +**⚠️ Важный питфолл:** после правки конфига НЕ использовать `docker restart cups-splix` — он убивает avahi-daemon (defunct), перед новым подъёмом обязателен **`docker stop cups-splix && docker rm cups-splix && docker compose up -d`** (полный пересоздание, чтобы entrypoint перевыполнился с нуля). + +**Проверка анонса:** +```bash +docker exec cups-splix sh -c "timeout 6 avahi-browse -rt -p _ipp._tcp | grep ';enp3s0;IPv4;'" +# должно показать: ... Samsung\032CLX-216x... truenas.local;192.168.2.197;631; "mopria-certified=1.3" ... +``` + +**Бэкап конфига (2026-08-31):** `/mnt/RED_2TB/docker/cups/backup_20260831-003619.tar.gz` (md5 `0e303a6a57ae767d1e14cd72c8039fe4`) — tar из /etc/cups, /var/spool/cups, /var/cache/cups. + +> Диагностика и полное объяснение: [[mac-print-shared-services]] + +> ⚠️ **2026-08-31: топология изменена.** TrueNAS больше НЕ в локальной сети (только публичный DNS `mallexxx.duckdns.org`) — из других подсетей/внешки `192.168.2.197` недостижим, и **снаружи `mallexxx.duckdns.org:631` закрыт**. НО **из самой подсети `192.168.2.x` TrueNAS достижима** (телефон `192.168.2.141` успешно печатал по `192.168.2.197:631` — CUPS access_log это подтверждает). → Samsung Mobile Print (app) печатает (висит на локальном IPP внутри подсети), а штатная Android print service с `ipp://192.168.2.197:631/...` показывала «недоступен» из-за **отсутствия mDNS/AirPrint-анонса** (avahi-daemon не запущен; `printer-dns-sd-name = no-value`). ✅ **Исправлено** (см. раздел «✅ mDNS/AirPrint анонс принтера»): cups-splix пересобран с avahi-daemon, cupsd.conf получил `Browsing On` + `BrowseLocalProtocols dnssd` → принтер анонсируется по mDNS (`mopria-certified=1.3`, IPv4 `192.168.2.197`); Android-служба теперь находит принтер сама. Детали и откат: [[mac-print-shared-services]]. + +## Связанные заметки +- [[truenas-access]] — SSH-доступ +- [[truenas-rclone-backup]] — система бэкапов +- [[obsidian-sync]] — Obsidian sync Eagle ↔ Taiga ↔ Kraken +- [[openmediavault-rpi5]] — Kraken NAS (Hermes агент, sync) diff --git a/personal/tech/xray-reverse-tunnel-kraken-truenas.md b/personal/tech/xray-reverse-tunnel-kraken-truenas.md index 53cbd362..6f386939 100644 --- a/personal/tech/xray-reverse-tunnel-kraken-truenas.md +++ b/personal/tech/xray-reverse-tunnel-kraken-truenas.md @@ -380,6 +380,48 @@ TrueNAS: Rollback network fix: вернуть compose-бэкап на Kraken и выполнить `docker compose up -d`. Это вернёт нерабочий Docker bridge mode, поэтому делать только для диагностики/отката. +## ✅ Per-user egress на `vpn.mallexxx.duckdns.org` (2026-09-02) + +В существующий VLESS-WS inbound `in-10095-tcp` добавлен второй клиент. Маршрутизация теперь различает клиентов по `email`: + +| Client email | Client ID | Egress | +|---|---|---| +| `user1` | `ce320965-6956-4759-84bb-7cb71cfc6252` | `direct` → TrueNAS `90.189.160.148` | +| `kraken-user` | `93a5dc4b-1b8d-4af5-9363-eb0091734293` | `via-kraken` → portal SOCKS `xray-reverse-portal:12345` → Kraken `92.62.70.41` | + +В persistent 3x-ui Xray template (`settings.key = xrayTemplateConfig`) добавлен SOCKS outbound: + +```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`. + +Бэкапы 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/контейнеры diff --git a/personal/tech/xray-reverse-tunnel-kraken-truenas.md.bak-per-user-20260902-1229 b/personal/tech/xray-reverse-tunnel-kraken-truenas.md.bak-per-user-20260902-1229 new file mode 100644 index 00000000..53cbd362 --- /dev/null +++ b/personal/tech/xray-reverse-tunnel-kraken-truenas.md.bak-per-user-20260902-1229 @@ -0,0 +1,388 @@ +--- +title: Xray Reverse Tunnel — Kraken ↔ TrueNAS +created: '2026-09-01' +updated: '2026-09-02' +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]]' +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 + +> **Статус: ✅ ВНЕДРЕНО И ПРОВЕРЕНО END-TO-END (2026-09-02).** TrueNAS SOCKS `:12345` → VLESS Reverse TCP+REALITY+Vision → Kraken → internet работает. HTTP и HTTPS тесты оба вернули выходной IP Kraken `92.62.70.41`. **Истинная причина:** Docker bridge/NAT на Kraken сбрасывал reverse mux; bridge должен работать с `network_mode: host`. Более ранние секции со статусом «не работает» и гипотезами #6612/#6242 сохранены ниже как история диагностики и суперсидированы секцией «Верифицированный фикс». +> Архитектурное решение: проксировать исходящий трафик локальных клиентов сети TrueNAS через **TrueNAS → Kraken → интернет**. + +> ## ✅ ВАЖНО (2026-09-02): `xray-admin` (3x-ui) на TrueNAS — это ОДНОВРЕМЕННО РАБОЧИЙ САМОСТОЯТЕЛЬНЫЙ Xray-VPN-сервер +> Путаница в вопросе юзера выявила: `vpn.mallexxx.duckdns.org:443` — это **не только reverse-frontend**, а полноценный Xray-сервер со **своим собственным выходом в интернет** (outbound `freedom`/`direct` → сразу через TrueNAS), НЕ зависящий от reverse-канала к Kraken. Это **отдельная фича**, параллельная reverse-туннелю. +> - **Проверено end-to-end 2026-09-02** (временный xray-клиент с Mac): VLESS+WS через `vpn.mallexxx.duckdns.org:443` → HTTP 200, выход IP `90.189.160.148` = TrueNAS. Контейнеры `xray-admin` (Up 21h) + `caddy` (Up 20h) живы. +> - Inbound `in-10095-tcp` (VLESS-WS): client id `ce320965-6956-4759-84bb-7cb71cfc6252` (user1), `security: none`, path `/vless`, host `vpn.mallexxx.duckdns.org`. TLS терминирует Caddy → в клиенте `network: ws` + TLS на домен, **без** двойного TLS внутрь. +> - Полные параметры и pitfalls (вкл. удаление `allowInsecure` в Xray 26.7.28) — в `family/how-to/truenas-infrastructure.md`, раздел `xray-admin`. +> - Reverse к Kraken — это ОТДЕЛЬНЫЙ механизм (для проксирования локальных клиентов сети TrueNAS через Kraken-egress). Он теперь также внедрён и проверен; см. «Верифицированный фикс». 3x-ui-сервер остаётся независимым рабочим VPN-выходом через TrueNAS. + +## Контекст / Почему + +- **VPS qentra.top (91.207.28.205) УДАЛЁН** — вся прежняя Xray-инфраструктура на нём (VLESS+REALITY, OpenVPN, WebSocket v.qentra.top) больше не существует. +- Нужен новый путь для выхода локальных клиентов сети TrueNAS в интернет через другую точку выхода (Kraken). +- Белый IP есть только у **TrueNAS** (`mallexxx.duckdns.org` = `90.189.160.148`). +- **Kraken за NAT**, входящие не принимает — только исходящие соединения. + +## Принятая схема + +``` +Локальные клиенты (сеть TrueNAS, 192.168.2.x) + │ шлют трафик на локальный прокси TrueNAS (SOCKS 1080 / HTTP 1081) + ▼ +TrueNAS ←── контроллер / bridge (белый IP, mallexxx.duckdns.org), принимает + │ TrueNAS заворачивает трафик в reverse-канал + ▼ ▲ +Kraken ──┘ держит ИСХОДЯЩИЙ reverse-канал к TrueNAS, отпускает трафик → интернет + ▼ +интернет +``` + +**Тип решения: Xray `reverse`.** Роли по Xray: + +| Узел | Роль | Держит канал? | Выход в интернет? | +|------|------|---------------|-------------------| +| **TrueNAS** | bridge/контроллер (inbound `reverse`) | ❌ слушает | ❌ | +| **Kraken** | outbound reverse-нода + exit | ✅ **исходящий** к TrueNAS | ✅ **да** | +| **Локальные клиенты** | используют TrueNAS как локальный прокси-шлюз | — | через Kraken | + +**Ключевое физическое ограничение:** Kraken за NAT не может принимать входящих. Поэтому канал держит **Kraken исходящим** к TrueNAS. Для передачи клиентского трафика TrueNAS → Kraken используются конструкции `dokodemo-door` + `reverse` + policy-маршрутизация (routing rules). Это чуть сложнее "поставить reverse и всё", конфиг нужен аккуратный. + +## ⚠️ Факты, проверенные 2026-09-01 (важно, ломают прежние допущения) + +1. **На 443 у TrueNAS НЕ Xray.** Проверено `openssl s_client`: на `mallexxx.duckdns.org:443` отвечает **обычный TLS 1.3 с валидным Let's Encrypt сертификатом для `mallexxx.duckdns.org`** (`issuer=Let's Encrypt/CN=YE2`). Это **Caddy/nginx reverse-proxy**, НЕ Xray REALITY (у REALITY сертификат был бы чужой/поддельный). → Твоя память «на 443 висел xray server» не подтверждается. +2. **`vless-proxy` на TrueNAS** (контейнер `teddysun/xray:latest`, Up 7 дней): + - inbound: SOCKS `0.0.0.0:1080`, HTTP `0.0.0.0:1081` (локально в LAN TrueNAS) + - outbound: VLESS+WS+TLS на `v.qentra.top:443`, path `/qentra`, id `2D9F24C4-21FE-4784-9843-F11C384DA67A` — **указывает на УДАЛЁННЫЙ VPS → сейчас мёртвый**. + - ⚠️ Используется Hermes-Taiga как SOCKS5-прокси (`vless-proxy:1080`) → **Hermes-Taiga сейчас без рабочего прокси**. +3. **Kraken→TrueNAS по `mallexxx.duckdns.org`:** открыты **только 22 (SSH) и 443 (HTTPS/TLS)**. `8443/8964/8080/9000` — closed. Порт 443 — TLS (Caddy), не сырой. +4. **Kraken:** Docker установлен (`/usr/bin/docker`), но демон отвечает медленно/рвёт SSH (проверка `docker ps` не завершилась за 40s). Xray на Kraken **отсутствует** (`which xray` пусто) — нужен Docker-контейнер. +5. **Связанность Kraken↔TrueNAS по 22/443 — подтверждена** (оба OPEN с Kraken). + +## ✅ ВНЕДРЕНО 2026-09-01: 3x-ui на TrueNAS (фронтенд + Docker Compose) + +**Решение Alex:** использовать **3x-ui frontend** + **Docker Compose** (управление клиентами через панель), а не ручной Caddy-pass-through с сырым Xray. Это изменило исходный план реализации (Шаг 1 ниже устарел по способу). + +### Развёрнут контейнер `xray-admin` (TrueNAS) +- **Имя контейнера:** `xray-admin` (строго, т.к. Caddyfile резолвит `xray-admin` по имени в docker-сети). +- **Образ:** `ghcr.io/mhsanaei/3x-ui:latest` (**3.7.0**, Xray **26.7.28**). +- **Сеть:** `caddy_default` (external) — там же Caddy, чтобы резолвить имя. +- **Volume:** `/mnt/RED_2TB/docker/xray-admin:/etc/x-ui` (туда лёг существующий `x-ui.db`). +- **Порт панели:** хостовый `54321 → 54321` (внутри панель реально слушает **2053** — Caddy проксирует `vpn-panel.mallexxx.duckdns.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-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//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-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, поэтому делать только для диагностики/отката. + +## Связанные заметки +- [[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-звено теперь мёртво)