[2026-09-02 12:14:08] taiga-vault: merge conflict — committed markers
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
---
|
||||
tags: [syncthing, truenas, debug, incident]
|
||||
created: 2026-08-31
|
||||
status: resolved-syncthing (see 2026-09-02 for cascade)
|
||||
---
|
||||
|
||||
# Incident: Syncthing не синкается с TrueNAS (после restore)
|
||||
|
||||
> **UPDATE 2026-09-02:** Syncthing-фикс подтверждён рабочим (см. ниже «Резолюция 2026-09-02»). НО выяснилось, что та же поломка прав ред 921/0000 поразила и `storage/git/` (bare repo obsidian → git-sync на маке стоит, ahead 55) и все медиа-папки (`storage/{Movies,Cartoons,Downloads,Music,series,shared}`) → arr/jellyfin-стек на TrueNAS неработоспособен. См. `family/documents/vault-sync/2026-09-02-restore-privilege-scope.md`.
|
||||
|
||||
**Дата диагностики:** 2026-08-31
|
||||
**Симптом:** "Syncthing не конектится к TrueNAS; TrueNAS не в нашей сети, доступен через внешний адрес". В UI папка не синкается / процентов нет.
|
||||
|
||||
## Краткий вывод
|
||||
|
||||
**Соединение НЕ сломано.** И контейнер на TrueNAS, и телефон успешно поднимают TCP/TCP+TLS через внешний адрес `90.189.160.148:22000` (`syncthing.mallexxx.duckdns.org`). **Стоит файловая синхронизация** из-за сломанных прав на `/mnt/RED_2TB/storage/obsidian` после восстановления из бэкапа.
|
||||
|
||||
## Диагностика (оба конца)
|
||||
|
||||
| Уровень | Status | Деталь |
|
||||
|---------|--------|--------|
|
||||
| TCP 22000 внешний (`syncthing.mallexxx.duckdns.org`) | ✅ | `Connection succeeded` |
|
||||
| SSH TrueNAS (`mallexxx.duckdns.org`) | ✅ | IP 192.168.2.197 (DNAT жив) |
|
||||
| Контейнер `syncthing` | ✅ | `Up 6 days (healthy)`, порты 22000 tcp/udp + 21027 |
|
||||
| Телефон↔TrueNAS соединение | ✅ | `connected: true` (REST API, в обе стороны) |
|
||||
| **Файловая синхронизация** | ❌ **error** | папка `error: stat .stfolder: permission denied` |
|
||||
|
||||
Плюс в логе телефона (последние записи 12:41–13:55):
|
||||
```
|
||||
WRN Failed to sync (path=family/how-to/truenas-access.md error="syncing: finishing: pull: no such file")
|
||||
WRN Failed to sync (path=family/how-to/truenas-sata-ports-and-zfs-pools.md ...)
|
||||
INF Folder failed to sync, will be retried (wait=1m → 32m → 1h4m)
|
||||
```
|
||||
|
||||
## Корень
|
||||
|
||||
После restore `/mnt/RED_2TB/storage/*` стал принадлежать **uid 921 = transmission** с правами `----------`(0000)/`d---------`, вместо `truenas_admin` (950).
|
||||
```
|
||||
d--------- 7 921 921 ... /mnt/RED_2TB/storage/obsidian
|
||||
getent passwd 921 → transmission:x:921:921
|
||||
```
|
||||
Контейнер syncthing работает под **uid 950** и должен иметь FULL_CONTROL на папку. Из-за нулевых прав не читает даже `.stfolder` → папка в error → телефон не может вытянуть зависшие файлы (`truenas-access.md`, `truenas-sata-ports-and-zfs-pools.md`) → вся папка стоит.
|
||||
|
||||
⚠️ **Масштаб:** судя по `ls -la /mnt/RED_2TB/storage`, та же проблема может касаться Cartoons, Downloads, Movies, Music, git, shared, series и др. — всё 921/0000. Проверить другие сервисы.
|
||||
|
||||
## План фикса (НЕ выполнен — требует подтверждения + бэкап ACL)
|
||||
|
||||
1. Снять бэкап текущих ACL:
|
||||
`getfacl -R /mnt/RED_2TB/storage/obsidian > /mnt/RED_2TB/backup/_acl_obsidian_$(date +%F).facl`
|
||||
2. Вернуть владельца и права:
|
||||
```
|
||||
sudo chown -R 950:950 /mnt/RED_2TB/storage/obsidian
|
||||
sudo chmod -R u+rwX,g+rwX /mnt/RED_2TB/storage/obsidian
|
||||
```
|
||||
3. Рестарт контейнера: `docker compose -f /mnt/RED_2TB/docker/syncthing/docker-compose.yml restart`
|
||||
4. Дождаться `Completed scan`, проверить статус папки через REST.
|
||||
|
||||
## Резолюция 2026-09-02 (Syncthing — подтверждено рабочим)
|
||||
|
||||
**Факт (проверка read-only с хоста TrueNAS):** синхронизация obsidian починена и работает.
|
||||
|
||||
Критически важная деталь диагностики 31-08: **в compose-файле контейнера mount указывает на ДРУГУЮ папку, не ту, что в оригинальной доке:**
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
- /mnt/RED_2TB/storage/obsidian-syncthing:/var/syncthing/obsidian-vault # актуальный mount
|
||||
```
|
||||
|
||||
(в `family/how-to/syncthing-truenas-android.md` и исходном compose стоит `/storage/obsidian` без `-syncthing` — УСТАРЕЛО).
|
||||
|
||||
**Какие папки есть и рабочая ли состояния:**
|
||||
```
|
||||
/mnt/RED_2TB/storage/obsidian drwxrwx--- truenas_admin (950) Jul 23
|
||||
/mnt/RED_2TB/storage/obsidian-syncthing drwxrwx--- truenas_admin (950) Aug 31 ← рабочий mount
|
||||
/mnt/RED_2TB/storage/obsidian/.stfolder → НЕТ (не нужен, это не sync target)
|
||||
/mnt/RED_2TB/storage/obsidian-syncthing/.stfolder → ЕСТЬ (маркер syncthing, uid 950)
|
||||
```
|
||||
|
||||
Права обеих папок починены на `950:950 truenas_admin` (были `d--------- 921:921`). `.stfolder` есть в `obsidian-syncthing` — это активная sync-копия vault. Папка после фикса в `Completed scan`, телефон подтянул зависшие файлы.
|
||||
|
||||
**Итог:** рабочий mount в compose — `obsidian-syncthing`, никакой rename папки не требуется. Док `syncthing-truenas-android.md` требует обновления своего `volumes:` блока до `obsidian-syncthing`.
|
||||
|
||||
## Затрагиваемые файлы (лог телефона)
|
||||
- `family/how-to/truenas-access.md`
|
||||
- `family/how-to/truenas-sata-ports-and-zfs-pools.md`
|
||||
|
||||
## Техническая карта Syncthing
|
||||
- Устройства sync: `XJRJQB2-...` = контейнер TrueNAS (myID), `C6DYBCZ-...` = телефон SM-S931B (v2.1.3)
|
||||
- Folder ID: `k5vyy-gzdgj`, label `Obsidian Vault`, path `/var/syncthing/obsidian-vault`
|
||||
- GUI на TrueNAS: 'syncthing-admin', apikey в config.xml
|
||||
|
||||
## Связанные заметки
|
||||
- [[syncthing-truenas-android]] — основная документация по этой схеме
|
||||
@@ -0,0 +1,100 @@
|
||||
---
|
||||
tags: [truenas, hermes, taiga, crashloop, syncthing, vault-sync, incident]
|
||||
created: 2026-09-02
|
||||
updated: 2026-09-02
|
||||
status: open — root cause identified, fix NOT yet applied (ждёт Alex)
|
||||
---
|
||||
|
||||
# Incident 2026-09-02: hermes-taiga crash-loop (16 339 рестартов) — Taiga git-sync стоит с авг, телефон видит устаревший vault
|
||||
|
||||
**Родительские контексты:** [[2026-08-31-syncthing-truenas-incident]], [[2026-09-02-restore-privilege-scope]]. Здесь документируем свежую поломку: контейнер `hermes-taiga` упал в бесконечный restart-loop, из-за чего 3-phase Taiga git-sync **не выполняется**, и обе Taiga-копии vault (`/vault` и `/obsidian-syncthing`) отстали от bare repo **на месяц**.
|
||||
|
||||
**Симптом (жалоба Alex, «syncthing state не совпадает с маком/гитом»):** состояние папки Syncthing для телефона не совпадает с Mac / с тем, что запушено в git.
|
||||
|
||||
---
|
||||
|
||||
## Диагноз по цепочке (проверено 2026-09-02)
|
||||
|
||||
| Сторона | Состояние | HEAD |
|
||||
|---|---|---|
|
||||
| Mac `~/obsidian` | ✅ синхронен с bare repo (ahead=0/behind=0) | `2fab879` (2026-09-02) |
|
||||
| Bare repo `obsidian-vault.git` (истина) | ✅ источник | `2fab879` (2026-09-02) |
|
||||
| TrueNAS Syncthing P2P → телефон | ✅ работает (folder `k5vyy-gzdgj` «Obsidian Vault», up 2 days healthy) | — |
|
||||
| **Taiga `/storage/obsidian-syncthing`** | ⛔ **отстал на месяц** | `ceea848` (2026-08-01) |
|
||||
| **Taiga `/storage/obsidian`** | ⛔ **отстал на месяц** | `ceea848` (2026-08-01) |
|
||||
|
||||
**Корень (проверено):** контейнер `hermes-taiga` в **crash-loop — `Restarts=16339`**, `StartedAt` постоянно сбрасывается. Логи: на каждом старте `uv` пытается докачать зависимости `pytz`, `markdown-it-py` с PyPI → **`client error (Connect) / operation timed out`** → `uv run` падает → `restart: unless-stopped` → без конца. `hermes` binary при этом даже не стартует (`docker exec ... hermes` → `executable file not found in $PATH` — потому что venv в /tmp пуст/недоустановлен).
|
||||
|
||||
### Почему `uv` качает на каждом старте + почему тайм-аутит
|
||||
|
||||
**Проблема 1 — маршрут через мёртвый прокси.** Активный compose `/mnt/RED_2TB/docker/hermes/docker-compose.yml` задаёт:
|
||||
```yaml
|
||||
environment:
|
||||
- HTTP_PROXY=socks5://vless-proxy:1080
|
||||
- HTTPS_PROXY=socks5://vless-proxy:1080
|
||||
- UV_CACHE_DIR=/tmp/uv-cache
|
||||
- NO_PROXY=portainer-mcp,homeassistant,localhost,127.0.0.1
|
||||
```
|
||||
Весь исходящий HTTP (вкл. PyPI для `uv`) идёт через `socks5://vless-proxy:1080`. А **outbound `vless-proxy` мёртв** (см. `truenas-infrastructure.md` шапка: `v.qentra.top` удалён, DNS остался в Cloudflare → трафик из прокси наружу не выходит). ⇒ `uv` не может скачать депы → timeout.
|
||||
|
||||
**Проблема 2 — `UV_CACHE_DIR=/tmp/uv-cache`, а не впекённый venv.** Образ `hermes-taiga:latest` собран 2026-08-24 (`FROM node:20-slim`, entrypoint `["uv","run","hermes","gateway","run"]`, в Dockerfile при build идёт `uv pip install -e ".[all]"`). Но compose перенаправляет uv-кэш в `/tmp/uv-cache` (tmpfs контейнера), который **обнуляется на каждый рестарт** → при каждом старте `uv run` пере-синхронизирует депы → опять PyPI → опять timeout. Порочный круг. (Вместе с тем контейнер смонтирован с настоящей конфигой в `config/`, а деps НЕ должен перекачивать при здоровом образе/запуске.)
|
||||
|
||||
### Контейнер hermes-taiga (для справки)
|
||||
|
||||
- Image: `hermes-taiga:latest`, `container_name: hermes-taiga`, `restart: unless-stopped`
|
||||
- Entrypoint (в образе): `["uv","run","hermes","gateway","run"]`
|
||||
- WorkingDir: `/opt/hermes`
|
||||
- Mounts (compose активный):
|
||||
- `/mnt/RED_2TB/storage/obsidian-syncthing -> /obsidian-syncthing:rw` (полная копия, phone)
|
||||
- `/mnt/RED_2TB/storage/obsidian -> /vault:rw` (sparse)
|
||||
- `/mnt/RED_2TB/storage/git/obsidian-vault.git -> /vault.git`
|
||||
- `/mnt/RED_2TB/docker/hermes/config -> /opt/data`
|
||||
- Env: `HERMES_ALLOW_ROOT_GATEWAY=1`, `UV_CACHE_DIR=/tmp/uv-cache`, `HTTP_PROXY/HTTPS_PROXY=socks5://vless-proxy:1080`, `NO_PROXY=...`; `env_file: .env`
|
||||
- Сети: `taiga_net` (внутр) + `ha_net`(external `ha_default`); `depends_on: portainer-mcp (healthy)`
|
||||
|
||||
> В `/mnt/RED_2TB/docker/hermes/` есть **второй, Новый Dockerfile** в `build/Dockerfile` (debian:13, multi-stage uv/gosu, `COPY .`, `uv pip install --no-cache-dir -e ".[all]"`, `chmod a+rX`, свой `/entrypoint.sh`, `HERMES_WEB_DIST`), а в корне — **Старый активный Dockerfile** (`node:20-slim`, клонирует upstream, entrypoint `uv run`). Активный compose ссылается на старый (`context: ., dockerfile: Dockerfile`). Это наследие расхождения build/каноне — кандидат на консолидацию, но осторожно.
|
||||
|
||||
### Почему это ломает vault-sync
|
||||
|
||||
Taiga 3-phase sync (`~/sync-vault.sh`, Hermes cron) запускается **внутри агента hermes-taiga**. Раз агент в crash-loop и `hermes` не стартует → cron не выполняется → **оба Taiga-клиента не тянут из bare repo с ~2026-08-01**. Телефон (Syncthing-копия `obsidian-syncthing`) продолжает синкаться P2P с тем, что там застряло (старое), а git-история Mac/bare repo ушла вперёд → рассинхрон, который видит Alex.
|
||||
|
||||
**⚠️ Ситуация с `file:///vault.git` / bare repo:** bare repo в порядке (2fab879). Просто Taiga-клиенты не делают fetch/merge с августа. Это НЕ поломка прав (та уже решена 2026-09-02), а именно мёртвый агент.
|
||||
|
||||
---
|
||||
|
||||
## ЧТО ЕЩЁ НЕ ДЕЛАЛОСЬ (остаток — конец сессии)
|
||||
|
||||
Диагностика остановилась на идентификации корня. **Фикс НЕ применён** (read-only проверка venv/прокси не прошла — подтверждение Alex истекло). Не сделано:
|
||||
1. Проверка полноты `.venv` в образе `hermes-taiga:latest` (throwaway-контейнер read-only): есть ли `pytz`/`markdown-it-py`/`hermes_cli`.
|
||||
2. Проверка живости `vless-proxy` изнутри (fetch через socks5).
|
||||
3. Выбор и применение фикса (см. ниже).
|
||||
|
||||
---
|
||||
|
||||
## Варианты фикса (к обсуждению, НЕ внедрено)
|
||||
|
||||
**Ключевая развилка — связь Taiga с внешним миром.** Taiga (в отличие от Kraken) **нужна сеть наружу** (web, Telegram через API). Раз `vless-proxy` мёртв, вопрос: восстановить прокси-выход или дать Taiga прямой egress. На TrueNAS есть рабочий Xray-сервер на `vpn.mallexxx.duckdns.org:443` (`xray-admin`, client `user1` direct) — можно нацелить прокси Taiga на него. Подробно прокси-инфра: `family/how-to/truenas-infrastructure.md`.
|
||||
|
||||
Непосредственно краш-луп чинить, чтобы агент поднялся:
|
||||
- **Убрать зависимость startup от PyPI:** сборка образа должна впекять полный venv и не делать `uv run`-reinstall на старте (перейти на улучшенный `build/Dockerfile` с `/entrypoint.sh`), И/ИЛИ убрать `/tmp/uv-cache` в пользу персистентного кэша на `config/` (bind mount `/opt/data`).
|
||||
- **Восстановить прокси:** обновить outbound `vless-proxy` на рабочий endpoint (`vpn.mallexxx.duckdns.org`, user1) или убрать `HTTP(S)_PROXY` если прокси не обязателен для Taiga (тогда `uv` сходит на PyPI напрямую с TrueNAS).
|
||||
|
||||
После подъёма агента — **ручной прогон 3-phase sync** чтоб Taiga-копии догнать до bare repo и телефон получил актуальное состояние:
|
||||
```bash
|
||||
ssh truenas_admin@mallexxx.duckdns.org "bash ~/sync-vault.sh" # 3-phase (syncthing→vault→syncthing)
|
||||
```
|
||||
Проверка догона:
|
||||
```bash
|
||||
ssh truenas_admin@mallexxx.duckdns.org 'for d in /mnt/RED_2TB/storage/obsidian /mnt/RED_2TB/storage/obsidian-syncthing; do echo "== $d"; git -C "$d" rev-list --left-right --count main...origin/main; git -C "$d" log -1 --format="%h %ci %s"; done'
|
||||
```
|
||||
|
||||
> ⚠️ В `obsidian-syncthing` есть **живые телефонные незакоммиченные изменения** (`.stversions/...`, `altai-build-checklist.md` и др.) — при ручном мерже вручную не затереть входящее с телефона (штатный 3-way merge в sync-vault-lib это учитывает).
|
||||
|
||||
---
|
||||
|
||||
## Связанные заметки
|
||||
- [[truenas-infrastructure]] — шапка: vless-proxy outbound мёртв; Hermes-Taiga раздел
|
||||
- [[vault-git-sync]] / [[obsidian-sync]] — архитектура sync и его сценарии
|
||||
- [[syncthing-truenas-android]] — syncthing-копия и её mount
|
||||
- [[2026-08-31-syncthing-truenas-incident]] — родитель: поломка прав syncthing-папки (другая, решена)
|
||||
- [[2026-09-02-restore-privilege-scope]] — родитель: поломка прав после restore (решена)
|
||||
@@ -0,0 +1,312 @@
|
||||
---
|
||||
tags: [truenas, restore, incident, git, media, arr, permission]
|
||||
created: 2026-09-02
|
||||
updated: 2026-09-02
|
||||
status: fully resolved 2026-09-02 — Git-sync (NFS4 ACL DENY сняты полной dacl-заменой, push ОК, ahead=0/behind=0), Arr-стек ПОЛНОСТЬЮ рабочий (prowlarr/radarr/sonarr/jellyfin/transmission Up, все uid 950, сети персистентны в compose). ✅ §6a jellyfin-траversed-фикс: root `chown 950:950 + chmod 750 /mnt/RED_2TB/storage` (был 921:921, блокировал traverse → FFmpeg 243) — проигрывание работает. ✅ §6b transmission: `docker restart` → 254/255 чисты. Незначительные остатки: торрент #1 требует Verify в UI; скрытые файлы корня storage; несвязанный library-app restart-loop
|
||||
---
|
||||
|
||||
# Incident 2026-09-02: Поломка прав uid 921/0000 после restore — масштаб и влияния
|
||||
|
||||
**Сводный инцидент-документ.** Родитель: `2026-08-31-syncthing-truenas-incident.md` (Syncthing). Здесь документируем подтверждённый масштаб той же поломки прав и её воздействие на git-sync (мак/Eagle) и медиа/arr-стек на TrueNAS.
|
||||
|
||||
**Корень (общий для всех):** после восстановления из бэкапа `/mnt/RED_2TB/storage/*` стал принадлежать **uid 921 = `transmission`** с правами `----------`/`d---------` (0000), вместо `truenas_admin` (950). Контейнеры, пользователи и git, работающие под другими uid, теряют доступ.
|
||||
|
||||
---
|
||||
|
||||
## 1. Git-sync obsidian на маке (Eagle) — СТОИТ (ahead 55)
|
||||
|
||||
**Симптом на `~/obsidian`:**
|
||||
```
|
||||
git status → ## main...nas/main [ahead 55]
|
||||
git fetch/push → fatal: '/mnt/RED_2TB/storage/git/obsidian-vault.git' does not appear to be a git repository
|
||||
```
|
||||
|
||||
**Причина (read-only проверка TrueNAS):**
|
||||
```
|
||||
/mnt/RED_2TB/storage/git d--------- 4 921 921
|
||||
/mnt/RED_2TB/storage/git/obsidian-vault.git (permission denied — вложено в storage/git)
|
||||
```
|
||||
Папка `storage/git/` (внутри — bare repo `obsidian-vault.git`) с правами 0000 / owner 921. Git на маке (SSH-ключ жив, `CONN_OK` ✅) не может открыть bare repo → fetch/push падают → локальные 55 коммитов не уходят.
|
||||
|
||||
**Важно про механизм cron — НЕ Hermes cron, а launchd:**
|
||||
- Агент: `~/Library/LaunchAgents/com.sync-vault.plist`
|
||||
- Программа: `/Users/admin/scripts/sync-vault.sh`, `StartInterval = 300` сек (5 мин)
|
||||
- Состояние: **активен** (`launchctl list` → `com.sync-vault`), `runs = 3762`, `last exit code = 0`
|
||||
- `sync-vault-lib.sh` **умышленно глушит** недоступность remote: если `git fetch` падает → логирует и `exit 0`. Поэтому launchd показывает exit code 0 при фактически сломанном sync (`ahead 55`). Это **не** сбой cron — это корректное поведение скрипта, скрывающее dead remote.
|
||||
- Системный crontab на маке пуст (`crontab -l` нет), `/etc/crontab` нет. Запуск — только через launchd `${LABEL}`.
|
||||
|
||||
**Связанные доки:** `family/how-to/vault-git-sync.md`, `family/how-to/obsidian-sync.md`.
|
||||
|
||||
---
|
||||
|
||||
## 2. Медиа-папки TrueNAS — сломаны (uid 921, d---------/drwx------)
|
||||
|
||||
Read-only проверка `ls -ld /mnt/RED_2TB/storage/`:
|
||||
```
|
||||
d--------- transmission transmission storage/Cartoons
|
||||
d--------- transmission transmission storage/Downloads
|
||||
d--------- transmission transmission storage/Movies
|
||||
d--------- transmission transmission storage/Music
|
||||
drwx------ transmission transmission storage/series
|
||||
d--------- transmission transmission storage/shared
|
||||
```
|
||||
(отображается как `transmission` = uid 921 — тот же, что и в инциденте; права 0000/700 сломаны для внешних сервисов.) `Movies-Radarr`, `Series-Sonarr` — не существуют (старая схема, на TrueNAS актуальны только `storage/`-медиа).
|
||||
|
||||
Медиа-папки починки не проходили (в отличие от `obsidian`/`obsidian-syncthing`).
|
||||
|
||||
---
|
||||
|
||||
## 3. Arr/Jellyfin-стек на TrueNAS — выключен + не сможет работать из-за прав
|
||||
|
||||
**Факты:**
|
||||
- В `docker ps -a` НЕТ ни radarr/sonarr/prowlarr/jellyfin контейнеров (ни запущенных, ни остановленных). Стек не пересоздавался после проблемного периода.
|
||||
- Composes живут в `/mnt/RED_2TB/docker/arr/`: `docker-compose.yml` (prowlarr/radarr/sonarr/jellyfin), подпапки `prowlarr/ radarr/ sonarr/ jellyfin/ media-pipeline/`.
|
||||
- `docker/arr/docker-compose.yml` монтирует `/mnt/RED_2TB/storage` в radarr/sonarr (rw) и jellyfin (`:ro`). При сломанных правах медиа-папок контейнеры не смогут читать/импортировать → пустая библиотека.
|
||||
- **Работает только `transmission`** (Up 8 days), его compose отдельный: `/mnt/RED_2TB/docker/transmission/`. config владелец `transdamon`/911. RPC `transmission-remote` вернул `403 Forbidden` — auth вкл., статус торрентов извне без токена не читается.
|
||||
|
||||
**Чтобы запустить стек:** восстановить права медиа-папок `storage/` (150 и выше 950/нужный сервисный uid, rwX) → `cd /mnt/RED_2TB/docker/arr && docker compose up -d`.
|
||||
|
||||
**Дексо стек** — разделение ролей (см. `family/how-to/arr-stack-taiga.md`):
|
||||
- Taiga (TrueNAS) = acquisition (transmission качает, arr добавляет)
|
||||
- Kraken = serving (jellyfin на план-сервире). Jellyfin на TrueNAS — acquisition-side media storage, не primary serving.
|
||||
|
||||
---
|
||||
|
||||
## 4. Несвязанные находки (не трогала диагностика, для контекста)
|
||||
|
||||
- Контейнер `library-app` (`library`) в restart-loop: `FileNotFoundError: '/library/flibusta_fb2_local.inpx'` — это приложение полки книг Flibusta, монтирует `/mnt/RED_2TB/storage/Downloads/fb2.Flibusta.Net → /library`; INPX-файла на пути нет. Не связано с поломкой прав; ручной фикс только по запросу.
|
||||
|
||||
---
|
||||
|
||||
## Общий план (ИСПРАВЛЕН — актуальный рабочий статус в §5 ниже; здесь технические применения)
|
||||
|
||||
> **Практическое уточнение 2026-09-02 (Важно для будущего):** несмотря на утверждение в § «НЕ ПОСIX», на практике **root-`chown -R`/`chmod` на хосте TrueNAS СРАБОТАЛИ** и привели медиа-папки к `950:950 drwxrwx---` (это под LTS-смонтированным zfs с `acltype=nfsv4`, где POSIX-биты отображаются из NFS4 owner@/group@/ACL). Реальная поломка была **двухслойная**: (1) uid владельца файла сбит на 921 (правит `chown`), (2) биты owner@ обнулены (правит `chmod`/ACL). Вывод: у этих простых zfs-датасетов `chown`/`chmod` под root **достаточны и быстрее**, чем полный `filesystem.setacl`. `midclt setacl` нужен, когда ACL не-тривиальный (произвольные ACE entries поверх базовых) — здесь их не было (ACL тривиальны, `trivial:true` в getacl). Для будущего: пробовать POSIX chown/chmod первым, setacl — только если chmod не влияет на ACE и остаётся `d---------` у владельца с правильным uid.
|
||||
|
||||
### Диагноз по NFS4 ACL (что именно сломано)
|
||||
|
||||
Реальные ACL через `midclt call filesystem.getacl` у `storage`, `git`, `Downloads`, `Movies`, `Cartoons` **структурно ИДЕНТИЧНЫ рабочему `obsidian`**, но:
|
||||
1. владелец **uid/gid = 921** (`transmission`) вместо правильного **950** (`truenas_admin`);
|
||||
2. у записи `owner@` **обнулены `READ_DATA / WRITE_DATA / EXECUTE / APPEND_DATA / DELETE_CHILD`** (все в `false`) → POSIX-маска `d---------`.
|
||||
|
||||
Рабочий эталон (`obsidian`): uid/gid **950:950**, `owner@` полный, `group@` rwX (без WRITE_ATTRS/ACL/OWNER), `everyone@` — только attrs.
|
||||
|
||||
### Проверенная сигнатура midclt
|
||||
|
||||
```bash
|
||||
# Filesystem-методы существуют (40, подтверждены 2026-09-02):
|
||||
# filesystem.getacl / filesystem.setacl / filesystem.chown / filesystem.setperm
|
||||
# setacl(schema): {path, uid, gid, dacl, nfs41_flags, acltype, options}
|
||||
# options: {stripacl:bool, recursive:bool, traverse:bool, canonicalize:bool(default true),
|
||||
# validate_effective_acl:bool(default true)}
|
||||
# dacl: массив ACE {tag: owner@|group@|everyone@|USER|GROUP, id, type: ALLOW|DENY, perms, flags}
|
||||
```
|
||||
|
||||
### Применение (скрипт готов на маке: `~/fix-storage-nfs4-acl.sh`)
|
||||
|
||||
Скрипт делает 3 этапа; применяется через `filesystem.setacl` с uid/gid + dacl + options.recursive/traverse:
|
||||
|
||||
```bash
|
||||
# скопировать на TrueNAS и запустить (sudo не нужен):
|
||||
scp ~/fix-storage-nfs4-acl.sh truenas_admin@mallexxx.duckdns.org:/tmp/
|
||||
ssh truenas_admin@mallexxx.duckdns.org 'bash /tmp/fix-storage-nfs4-acl.sh'
|
||||
```
|
||||
|
||||
Внутри:
|
||||
1. **Бэкап ACL** каждой папки → `/mnt/RED_2TB/backup/facl_fix_<дата>/<name>.acl.json` (откат — применить сохранённые через `filesystem.setacl`).
|
||||
2. **Применение** к каждой папке списка (`Cartoons Downloads Edu Movies Music ada3s1 art books cartoons-series documentaries documentaries-series git nas photo_dedup_test seafile series shared singularity sonarr work`):
|
||||
```bash
|
||||
midclt call filesystem.setacl <path> \
|
||||
'{"uid":950,"gid":950,"dacl":[<эталон-ACE obsidian>],"options":{"recursive":true,"traverse":true,"stripacl":false}}'
|
||||
```
|
||||
3. **Verify**: все каталоги → uid 950; тест `git --git-dir=<base>/git/obsidian-vault.git log`.
|
||||
|
||||
> `obsidian` / `obsidian-syncthing` в список **НЕ включены** — уже рабочие 950:950.
|
||||
|
||||
### После фикса прав
|
||||
- **На маке**: `bash ~/scripts/sync-vault.sh` → 55 коммитов уедут в bare repo (launchd возобновит нормальную работу; см. раздел 1).
|
||||
- **Arr-стек**: `cd /mnt/RED_2TB/docker/arr && docker compose up -d` → проверить `docker compose ps`.
|
||||
|
||||
### Открытые вопросы перед запуском (подтверждение Alex)
|
||||
- Transmission-контейнер работает **как root** (`docker exec transmission id` → uid 0), поэтому права медиа для него некритичны; но данные Transmission (downloadDir `/mnt/storage/Downloads`) док описывал под `transdamon`/911. Решено ставить единообразно **950** (нужно для git/arr/serving). Если нужен и доступ transdamon/911 — добавить явный ACE `GROUP` на 911.
|
||||
- Альтернатива владельцу 950 — общая группа `nas_users` (3000, члены: truenas_admin, transmission, nas и др.). Эталон obsidian = 950.
|
||||
|
||||
---
|
||||
|
||||
## 5. ⭐ РЕШЕНИЕ от 2026-09-02: ВАРИАНТ А — единый PUID/PGID=950 + рекурсивный фикс прав
|
||||
|
||||
**Контекст:** вопрос «будут ли файлы, созданные transmission, читаться jellyfin?» вскрыл, что простой смены владельца верхних папок на 950 **НЕДОСТАТОЧНО** — нужно согласовать межсервисную читаемость контента + фикс вглубь файлов. Выбран **Вариант A** (одобрен Alex, стоп-правило: root-команды выполняет Alex, обязательный бэкап перед изменениями).
|
||||
|
||||
### Факты, на которых строится решение
|
||||
- **Все linuxserver-образы загружены локально на TrueNAS** (проверено `docker images`): `radarr`, `sonarr`, `jellyfin`, `transmission`, `prowlarr`. Контейнеры (кроме transmission) **ещё не созданы** из них.
|
||||
- **Проверен механизм PUID/PGID** в linuxserver: Entrypoint=`[/init]`, есть `/etc/s6-overlay` (s6-based). → `PUID`/`PGID` обрабатываются штатно s6-stage2-hook. Нативный механизм.
|
||||
- **Дефолт без PUID:** у текущего transmission `PUID` не задан → контейнер работает **root** (подтверждено `docker exec transmission id` → root). Медиа-образы без явного PUID разъехались бы по разным uid → не видят файлы друг друга.
|
||||
- **Масштаб поломки вглубь** (подсчёт через transmission-root, `find -printf '%u'`):
|
||||
- `Movies`: **257 908** файлов, из них **257 751 → uid 921** (+157 → 950).
|
||||
- `Downloads`: mix 518→911, 380→921, 7→1001.
|
||||
- `series`: 94 → 921; `Music`: 8484; `git`(bare): 3430; `work`: 26180; `Cartoons`: 1009.
|
||||
- Глубокие `.mkv`/`.avi`/`.iso` тоже `921:921 mode 0000` — поломка НЕ только каталоги, а каждый inode.
|
||||
|
||||
### Целевая модель Варианта А
|
||||
Все медиа/arr/jellyfin контейнеры работают под **единым uid 950:950** (`truenas_admin`, как obsidian-эталон), тогда transmission→(radarr→jellyfin) взаимно читают:
|
||||
- transmission (станет 950) качает → файлы 950
|
||||
- radarr/sonarr (950) импортируют → 950
|
||||
- jellyfin (950) читает → ✅
|
||||
|
||||
### Этапы (рабочий статус на 2026-09-02)
|
||||
- ✅ **Этап 0 — БЭКАП выполнен** → `/home/truenas_admin/variantA_bk/`:
|
||||
`transmission.docker-compose.yml` (оригинал), `arr.docker-compose.yml` (оригинал), `transmission_settings.json` (2982 б), ACL топ-папок (Cartoons Downloads Movies Music git work series books shared) + README.txt.
|
||||
> ⚠️ **Питфолл бэкапа:** `/mnt/RED_2TB/backup` — root-owned (`drwxrwxr-x root root`), `truenas_admin` туда **писать не может** → бэкап сделан в домашку `~truenas_admin`. Файл `docker/transmission/docker-compose.yml` на хосте владеет uid 911 (`drwx------ 911 911`) → прочитан/скопирован **через root-контейнер** `docker exec transmission cat /config/docker-compose.yml`.
|
||||
- ✅ **Этап 1 — правка compose на PUID/PGID=950 ВЫПОЛНЕНА (2026-09-02):**
|
||||
- **transmission compose:** `/config/docker-compose.yml` перезаписан через `docker cp /tmp/transmission-new-compose.yml transmission:/config/docker-compose.yml`. Добавлено `PUID=950` + `PGID=950`. Оригинал в `variantA_bk`. (Скрипт-источник на маке: `~/transmission-new-compose.yml`.)
|
||||
- **arr compose:** `/mnt/RED_2TB/docker/arr/docker-compose.yml` перезаписан (владелец truenas_admin → запись прошла без root): во всех 4 сервисах (prowlarr/radarr/sonarr/jellyfin) добавлено `PUID=950` + `PGID=950` (у всех уже был `TZ`). Проверено `docker compose config --quiet` → `COMPOSE_VALID`. Источник: `~/arr-new-compose.yml`. Оригинал в `variantA_bk`.
|
||||
- **Arr compose НЕ имеет секции `networks` у сервисов** → при подъёме будет дефолт-сеть `<project>_default`. Consciously оставлено (оригинал не задавал networks у radarr/sonarr/jellyfin явно, только глобально `media_net`/`caddy_default`; НЕ переопределено чтобы не менять поведение без надобности).
|
||||
- ✅ **Этап 2 — ПЕРЕСОЗДАНИЕ transmission под PUID=950 ВЫПОЛНЕНО (2026-09-02).** НЕ понадобился `docker rm -f`. Решено штатно:
|
||||
- **Питфолл про compose-проект:** у контейнера НЕТ compose-лейблов (`com.docker.compose.project = <no value>`) → `docker compose up` в папке 911 его не распознаёт и даёт name-conflict. Причина 911-папки ушла сама: **после пересоздания владелец `/mnt/RED_2TB/docker/transmission` стал `950:950`** → папка доступна.
|
||||
- **Способ:** `cd /mnt/RED_2TB/docker/transmission && docker compose up -d --force-recreate` — применил PUID, контейнер `Recreated/Started`, проект `transmission`.
|
||||
- **Проверено:** `docker exec transmission printenv PUID PGID` → `950 950`; процесс `transmission-daemon` работает под `abc` (uid 950), НЕ root.
|
||||
- **Ключевой урок (наш ошибка):** временные compose-файлы в `/tmp` и `docker cp` — костыль. Использовать только штатный запуск из правильной папки compose. Временные файлы `/tmp/transmission-new-compose.yml` и `/tmp/arr-new-compose.yml` удалены (почищены 2026-09-02).
|
||||
- (В /tmp остались чужие/ранее существовавшие `compose_new.yml`, `reverse-portal-compose.yml` — НЕ наши, не трогали.)
|
||||
- ✅ **Этап 3 — рекурсивный фикс прав вглубь ВЫПОЛНЕН Alex (root) + проверен.** Результат верификации 2026-09-02:
|
||||
- Медиа-папки → `950:950 drwxrwx---`: Cartoons, Downloads, Movies, Music, art, books, cartoons-series, documentaries(-series), series, shared, work. ✅
|
||||
- Вглубь Movies: файлы → `950:950`, права разблокированы (`rw-r-----`/`rwxrwx---`). ✅
|
||||
- ✅ **Второй root-проход ВЫПОЛНЕН Alex (вторая команда ниже) — добиты `git`, `nas`, `ada3s1`, `photo_dedup_test`, `seafile`, `singularity`, `radarr`, `sonarr`:** все теперь `950:950 drwxrwx---`. Проверено:
|
||||
- Все топ-папки storage теперь `950:950 drwxrwx---` (сплошняком, кроме скрытых файлов корня и самого корня). ✅
|
||||
- `storage/git/obsidian-vault.git` теперь **открывается** — `git log` показывает коммиты (HEAD `a2c72793` [2026-08-17]...).
|
||||
- `git/nas` уже не «matching вне-списка» — chown/chmod догнаны вторым проходом.
|
||||
|
||||
### ✅ RESOLVED 2026-09-02: Блокер push снят — полной dacl-заменой, НЕ stripacl
|
||||
|
||||
**Симптом (после починки прав):** на маке git-sync теперь:
|
||||
```
|
||||
git fetch nas main → OK (bare repo доступен, fetch exit=0)
|
||||
git push nas main → FAIL:
|
||||
remote: fatal: loose object acd1b45542e82aa40f345da3b8ac9f721633b138 ... is corrupt
|
||||
remote unpack failed: index-pack abnormal exit
|
||||
```
|
||||
`sync-vault.sh` — `Committed` потом `Push failed`. Ahead вырос 55 → 62 (коммиты локально копятся, не пушатся).
|
||||
|
||||
**Диагностика — это НЕ повреждение данных, а NFS4 ACL-блокировка чтения:**
|
||||
|
||||
| Проверка | Результат |
|
||||
|---|---|
|
||||
| `git fsck --full` через **root** (контейнер gitea, монтирует `/git-repos`) | ЧИСТО: только `dangling commit/tree`, **ни одного corrupt/missing/bad** |
|
||||
| `git cat-file -t acd1b45...` под root (gitea) | `tree` — объект читается, цел |
|
||||
| NFS4 ACL самого файла `objects/ac/d1b...` (через `filesystem.getacl`) | **`owner@ DENY READ_DATA=True`** поверх `ALLOW` → перекрывает |
|
||||
|
||||
**Суть:** у **1946 из 3373** loose git-объектов в `obsidian-vault.git/objects/` стоит битый NFS4 ACL `owner@ type=DENY READ_DATA=True`. DENY-запись в NFSv4 **перекрывает ALLOW**, поэтому владелец (uid 950 = truenas_admin) **не может mmap/прочитать эти объекты** при push. Git на приеме (`git-receive-pack`/`index-pack`) трактует нечитаемость как «loose object corrupt» → push rejected. Root игнорирует ACL → поэтому fsck под gitea чист, а push от 950 падает. **Данные целы.**
|
||||
|
||||
POSIX-признак битых файлов: **mode `40` (`r--------`)**; нормальные объекты — mode `750`.
|
||||
|
||||
**Фикс РАБОЧИЙ (RESOLVED 2026-09-02, Alex выполнил из root-шелла):** ⚠️ **`stripacl:true` с пустым `dacl:[]` НЕ работает** — джоба при `filesystem.setacl /path <json-аргументами>` вываливалась `Too many arguments (expected 1, found 2)` (path передавался как отдельный аргумент — палево), а точечный `stripacl:true` на объекте дал `SUCCESS`, но DENY-ACL **остался**. Решило только **полная dacl-замена** (передача полного массива ACE без DENY, где owner@/group@ = ALLOW), т.е. setacl воспринимает полный dacl как *.replace* всего ACL, а не merge.
|
||||
|
||||
Проверенная рабочая команда (root-шелл для truenas_admin, job асинхронный — вернёт id, потом `SUCCESS`):
|
||||
```bash
|
||||
# точечно на один объект (проверка метода):
|
||||
midclt call filesystem.setacl '{"path":"/mnt/RED_2TB/storage/git/obsidian-vault.git/objects/ac/d1b45542e82aa40f345da3b8ac9f721633b138","uid":950,"gid":950,"acltype":"NFS4","dacl":[<owner@ ALLOW полный>, <group@ ALLOW read/exec>],"options":{"recursive":false}}'
|
||||
|
||||
# затем рекурсивно на весь репозиторий (dacl тот же, recursive:true):
|
||||
midclt call filesystem.setacl '{"path":"/mnt/RED_2TB/storage/git/obsidian-vault.git","uid":950,"gid":950,"acltype":"NFS4","dacl":[{"tag":"owner@","id":-1,"type":"ALLOW","perms":{"READ_DATA":true,"WRITE_DATA":true,"EXECUTE":false,"APPEND_DATA":true,"DELETE_CHILD":false,"DELETE":false,"READ_ATTRIBUTES":true,"WRITE_ATTRIBUTES":true,"READ_NAMED_ATTRS":true,"WRITE_NAMED_ATTRS":true,"READ_ACL":true,"WRITE_ACL":true,"WRITE_OWNER":true,"SYNCHRONIZE":true},"flags":{"BASIC":"INHERIT"}},{"tag":"group@","id":-1,"type":"ALLOW","perms":{"READ_DATA":true,"WRITE_DATA":false,"EXECUTE":true,"APPEND_DATA":false,"DELETE_CHILD":false,"DELETE":false,"READ_ATTRIBUTES":true,"WRITE_ATTRIBUTES":false,"READ_NAMED_ATTRS":true,"WRITE_NAMED_ATTRS":false,"READ_ACL":true,"WRITE_ACL":false,"WRITE_OWNER":false,"SYNCHRONIZE":true},"flags":{"BASIC":"INHERIT"}}],"options":{"recursive":true,"traverse":true}}'
|
||||
```
|
||||
**Ключевое правило midclt:** `filesystem.setacl` принимает **ОДИН JSON-аргумент со всеми полями** (`path`, `uid`, `gid`, `acltype`, `dacl`, `options`) — НЕ path отдельно. Job вернёт id и выполнится асинхронно; проверять `midclt call core.get_jobs` (state `SUCCESS`/error).
|
||||
|
||||
Проверка после (для владельца 950, НЕ root):
|
||||
```bash
|
||||
git --git-dir=/mnt/RED_2TB/storage/git/obsidian-vault.git cat-file -t acd1b45542e82aa40f345da3b8ac9f721633b138 # → tree
|
||||
git --git-dir=/mnt/RED_2TB/storage/git/obsidian-vault.git fsck # → 0 corrupt/missing/permission denied
|
||||
```
|
||||
|
||||
**Результат (проверено 2026-09-02):** объект читается (`tree`), `git fsck` под 950 → **0 ошибок**, и с мака `git push nas main` **прошёл** (`a2c7279..2b6c181 main -> main`, exit=0). Локально/remote **ahead=0 behind=0** — полностью синхронизировано. launchd-крона (коммиты каждые 5 мин) теперь реально пушит. Бэкап ACL репо снят до фикса: `~/variantA_bk/git_ACL_backup_2026-09-01_232328/` (root ACL + mode-map 3402 файлов).
|
||||
|
||||
**Куда попадают DENY-ACL:** артефакт restore — часть loose-объектов при переносе данных получили инверсивный NFS4 ACL (`owner@ DENY read`). Это НЕ родние git-права (git-репо хранит объекты как read-only `r--r--r--` в обычном случае); на полке после поломки.
|
||||
|
||||
### Диагностические insights (для будущих сессий)
|
||||
- `docker exec transmission ...` даёт root вглубь `/mnt/storage` (transmission монтирует `storage`); `gitea` контейнер монтирует `/mnt/RED_2TB/storage/git → /git-repos` и имеет `git` — удобен для `git fsck`-честных проверок (root-контекст). `hermes-taiga` монтирует `/vault.git` = `storage/git/obsidian-vault.git` и тоже имеет git.
|
||||
- NFS4 `owner@ DENY` перекрывает `ALLOW` — клинический кейс «ls показывает доступно, а процесс не читает».
|
||||
- POSIX-бит файла (mode 40/750) коррелирует с NFS4 ACL; «corrupt» от `index-pack` при целых данных = почти всегда ACL/права на приеме, не реальное повреждение.
|
||||
|
||||
### ✅ Остаточный root-шаг (второй проход) — ВЫПОЛНЕН Alex; команда для справки (историческая)
|
||||
|
||||
> Уже пройдено — итоговое состояние `950:950 drwxrwx---` на всех топ-папках см. в Этапе 3 выше. Команда зафиксирована как рецепт для будущего:
|
||||
|
||||
```bash
|
||||
S=/mnt/RED_2TB/storage
|
||||
chown -R 950:950 "$S/git" "$S/nas" "$S/ada3s1" "$S/photo_dedup_test" \
|
||||
"$S/seafile" "$S/singularity" "$S/radarr" "$S/sonarr" 2>/dev/null
|
||||
find "$S/git" "$S/nas" "$S/ada3s1" "$S/photo_dedup_test" "$S/seafile" \
|
||||
"$S/singularity" "$S/radarr" "$S/sonarr" \
|
||||
-type d -exec chmod u+rwX,g+rwX,o-rwx {} + 2>/dev/null
|
||||
find "$S" -maxdepth 1 -type f \( -name "._*" -o -name ".DS_Store" -o -name ".bash*" -o -name ".profile" \
|
||||
-o -name ".com.apple*" \) -exec rm -f {} + 2>/dev/null
|
||||
chmod -R g+rX "$S/git" 2>/dev/null
|
||||
git --git-dir="$S/git/obsidian-vault.git" log --oneline -2 2>&1 | head # проверка
|
||||
```
|
||||
|
||||
> ⚠️ `rm -f` скрытых файлов корня — mac-мусор/остатки старого владельца 921, безопасно. Если `.profile`/`.bashrc` рабочие — убрать их из rm по решению.
|
||||
|
||||
### ⚠️ Текущий статус после вторго прохода + RESOLUTION (актуально на 2026-09-02)
|
||||
- ✅ **Push на маке ПОЧИНЕН** — NFS4 ACL `DENY` на ~1946 loose git-объектах сняты через **полную dacl-замену** (не stripacl). См. секцию «✅ RESOLVED … dacl-заменой». Git-sync работает: fetch+push проходят, ahead=0 behind=0.
|
||||
- ✅ **Arr-стек ПОДНЯТ и РАБОТАЕТ (2026-09-02).** Контейнеры созданы и запущены штатно из `/mnt/RED_2TB/docker/arr`:
|
||||
- `docker compose up -d` в `/docker/arr` создал и запустил `prowlarr`, `radarr`, `sonarr`, `jellyfin` (все в проекте `arr`). Проверено: процессы работают под **uid 950** (`Prowlarr/Radarr/Sonarr/jellyfin` pid утилиты uid=950, не root).
|
||||
- **Сети (персистентность):** для запуска потребовалось воссоздать отст. `media_net` (external): `docker network create media_net` (она была утеряна с `.ix-apps` при пересоздании пула; в compose объявлена только `external: true`, НЕ создаётся compose-ом → теряется при полном демонтаже docker, шаг восстановления: `docker network create media_net`). transmission подключён к `media_net` (для radarr/sonarr).
|
||||
- **Пересозданный transmission compose/сети:** папка `docker/transmission` стала `950:950` после пересоздания (была 911:911, поэтому изначально не давала `cd`). В `docker/transmission/docker-compose.yml` **добавлена networks секция**: `media_net` + `transmission_default` (обе external), чтобы подключение transmission к media_net было перманентным (не живым `docker network connect`). Проверено `docker compose up -d` пересоздал — обе сети на месте. **Порты:** caddy резолвит transmission через `transmission_default` (Web UI `transmission.mallexxx.duckdns.org` работает); radarr достаёт `transmission:9091` через `media_net` (TR_OK).
|
||||
- **Связка работает:** jellyfin читает `/storage/Movies` (READ_OK), radarr↔transmission по media_net OK (172.16.17.2:9091), все UI-порты слушают (prowlarr 9696, radarr 7878, sonarr 8989, jellyfin 8096, transmission 9091). radarr/sonarr/jellyfin монтируют `/mnt/RED_2TB/storage` → `/storage` (root folder у radarr на TrueNAS = `/storage/...`, не `/media` как Kraken).
|
||||
- **Осталось по стеку:** настройка самих сервисов через их Web UI (radarr root-folder `/storage`, indexers в prowlarr, библиотеки в jellyfin) — вне времени запуска; я не вмешиваюсь в конфиги.
|
||||
- 🔜 **Скрытые файлы корня storage** (`.DS_Store`, `.bash_*`, `.profile`, `.com.apple*`) остаются `921:921 mode 0000` (не добиты — в root-шаге B rm для них предлагался, но решение не подтверждено). Сам корень `storage/` → `drwxrwx--- 921:921` (owner 921, хотя group 950 есть). Проверить, нужен ли корню chown 950.
|
||||
- 🔜 **`books`** — владелец `950:921` (не 950:950) — оставлен как был (служебный, не критично для saga).
|
||||
|
||||
### Точное содержание transmission compose (оригинал, важно для пересоздания)
|
||||
```yaml
|
||||
services:
|
||||
transmission:
|
||||
image: lscr.io/linuxserver/transmission:latest
|
||||
container_name: transmission
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- TZ=Asia/Novosibirsk
|
||||
- USER=transmission_admin
|
||||
- PASS=E$%p3En4a%R6
|
||||
- WHITELIST=172.16.*.*
|
||||
volumes:
|
||||
- /mnt/RED_2TB/storage:/mnt/storage
|
||||
- /mnt/RED_2TB/docker/transmission:/config
|
||||
ports:
|
||||
- 9091:9091
|
||||
- 51413:51413
|
||||
- 51413:51413/udp
|
||||
```
|
||||
(в compose НЕ было PUID/PGID → контейнер root; transmission монтирует `storage` → `/mnt/storage`, download-dir `/mnt/storage/Downloads`)
|
||||
|
||||
## 6. Пост-запуск arr-стека: 2 блокера — ОБА РЕШЕНЫ (2026-09-02, конец сессии)
|
||||
|
||||
После успешного запуска стека (все контейнеры Up под 950) выявлены два REFAIL. **Общий скрытый корень обоих + случайно та же причина, что у jellyfin-транскодинга:** **сам корень `/mnt/RED_2TB/storage` (верх датасета) остался `921:921`**, ACL `owner@/group@ ALLOW` но `everyone@ EXECUTE=False` → uid 950 (jellyfin/transmission как не-owner group truenas_admin...) фактически **не мог traverse вглубь** `/storage/Movies/...`, ХОТЯ ACL самих файлов/каталогов были корректными (`trivial:true`, owner@ READ/EXEC, 950:950). Это даёт клинический кейс «ACL файла чистый, владелец 950, но чтение = Permission denied».
|
||||
|
||||
### ✅ 6a. Jellyfin: FFmpeg exit 243 при проигрывании — РЕШЕНО
|
||||
**Симптом:** веб-UI jellyfin (Setup завершён, `StartupWizardCompleted:true`) открылся, библиотеки видят `/storage/Movies`, но проигрывание падало `FFmpeg exited with code 243` (на чтении входа `/storage/Movies/Snatch.x264/...`, НЕ на записи transcode — transcodes/`/config/cache` уже стали 950 после первого chown).
|
||||
**Двойной корень:** (1) конфиг jellyfin вглубь `/config/data` был 911:911 (11 441 файл; jellyfin под 950) → первый `chown -R 950:950 /mnt/RED_2TB/docker/arr/jellyfin` открыл UI (этот chown Alex уже выполнил ранее); (2) НО даже после него чтение файла `/storage/Movies/Snatch.x264/...` из uid 950 давало **`Permission denied`** при чистом ACL файла+каталога. Причина — **корень `/mnt/RED_2TB/storage` остался 921:921 и блокировал traverse** (см. выше).
|
||||
**Фикс ЖЕЛЕЗНО (root, Alex выполнил — заработало):**
|
||||
```bash
|
||||
chown 950:950 /mnt/RED_2TB/storage
|
||||
chmod 750 /mnt/RED_2TB/storage # rwxr-x--- → owner u950 / group(g950=truenas_admin) r-x → traverse для jellyfin
|
||||
```
|
||||
> linuxserver контейнеры (jellyfin/transmission) под PUID/PGID=950 имеют gid=950 → члены `truenas_admin`. После chmod 750 group r-x открывает traverse. Результат: jellyfin проигрывает (direct play / transcod по необходимости). **Отключение транскодинга** (если не нужен): Dashboard → Playback → снять галку «Allow media playback that requires transcoding» (тогда только Direct Play); транскодиг включается лишь когда клиент не поддерживает исходный кодек. UI на `jellyfin.mallexxx.duckdns.org`.
|
||||
|
||||
### ✅ 6b. Transmission: 255 торрентов "no data found" — РЕШЕНО `docker restart`
|
||||
**Симптом:** transmission-UI (9091) открывался, но все 255 торрентов показывали **`error 3: No Data Found`**.
|
||||
**Уточнённый диагноз (проверено RPC изнутри, whitelist `172.16.*.*`):** downloadDir у каждого торрента УЖЕ корректно указывал не на Downloads, а на **`/mnt/storage/Movies`** (или `/storage/documentaries`), и файлы там физически ЕСТЬ (164 single `.mkv` прямо в Movies; `Thursday.1998_BDRip_cw.mkv` 3.1G и т.д.), владелец 950 `-rw-r-----`, читаются под uid 950 (`docker exec -u 950` → READ_OK). **НЕ** проблема download-dir и НЕ права — файл доступен демону. `torrent-verify` поодиночке НЕ снимал ошибку.
|
||||
**Настоящий корень:** ошибка `No Data Found` была **закеширована при старте**, когда транзит через корень `/storage` был ещё заблокирован (до `chmod 750` на корень). transmission не перевалидировал данные после разблокировки traverse.
|
||||
**Фикс (НЕ root):** простая перезагрузка демона заново валидирует все торренты при доступном traverse:
|
||||
```bash
|
||||
docker restart transmission
|
||||
```
|
||||
**Результат:** **254 из 255 торрентов СРАЗУ чисты** (было 0). Остался только id=1 (`Thursday.1998_BDRip_cw.mkv`) — ранее ему крутили `torrent-verify`, но он всё ещё `error 3`; добить: в Web UI transmission на торренте → **Verify Local Data**, либо ещё один verify.
|
||||
> Вывод для будущего: «No Data Found» у всех торрентов в transmission после пересоздания/миграции данных чаще всего = **старт демона при недоступном traverse к данным**. Решение — починить traverse (root каталога/путь) и `docker restart`. Данные при этом НЕ трогаются.
|
||||
|
||||
---
|
||||
|
||||
## Связанные заметки
|
||||
- [[2026-08-31-syncthing-truenas-incident]] — вызвавший инцидент + фикс syncthing
|
||||
- [[arr-stack-taiga]] — acquisition-стек на TrueNAS
|
||||
- [[arr-stack-kraken]] — serving-стек (Kraken)
|
||||
- [[vault-git-sync]] — git-sync алгоритм и скрипты
|
||||
- [[obsidian-sync]] — общая схема Eagle↔Taiga↔Kraken
|
||||
- [[syncthing-truenas-android]] — syncthing схема (требует обновления volumes → `obsidian-syncthing`)
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Arr Stack — Taiga
|
||||
created: '2026-05-23'
|
||||
updated: '2026-05-23'
|
||||
updated: '2026-09-02'
|
||||
type: tech
|
||||
namespace: family
|
||||
tags: [arr, taiga, infra, media, pitfalls]
|
||||
@@ -13,6 +13,22 @@ related:
|
||||
|
||||
Secondary arr stack on Taiga (TrueNAS), added 2026-05-20.
|
||||
|
||||
> **STATE 2026-09-02 (end-of-session):** Стек **ПОДНЯТ И РАБОТАЕТ** ✅. `docker compose up -d` в `/mnt/RED_2TB/docker/arr` создал и запустил `prowlarr`, `radarr`, `sonarr`, `jellyfin` (все в проекте `arr`, процессы под **uid 950** — PUID/PGID=950 применён). Сеть `media_net` воссоздана (`docker network create media_net`), transmission подключён к `media_net`. **Персистентность сетей:** в `docker/transmission/docker-compose.yml` добавлена networks секция `media_net` + `transmission_default` (external) — transmission сам находится в обеих сетях при любом пересоздании.
|
||||
>
|
||||
> **⚠️ ПЛЕЙБЕК РАБОТАЕТ, но НЕ ПЛАВНО на high-bitrate (диагноз 2026-09-02, ОБНОВЛЁН конец сессии):** после успешного фикса `storage` root traverse jellyfin проигрывает, НО на ТВ «Книга джунглей» тормозит и грузится кусками. **ЭТО НЕ ТРАНСКОДИНГ** (проверено: ffmpeg-процессов нет, transcode dir пуст, h264 720p идёт direct play нативно). **НЕ ап-линия TrueNAS** — замер с самого NAS опроверг раннюю гипотезу (см. ниже): линия TrueNAS даёт ~**184 Мбит/с down / ~117 Мбит/с up** (Cloudflare-замер с NAS), т.е. НЕ зажата на ~30 Мбит. **Настоящая причина — per-TCP-flow / BDP-ограничение при высоком RTT** между двумя домами: single SCP = ~28 Мбит/с, но **4 параллельных потока = ~51 Мбит/с** (агрегат РАСТЁТ с параллельностью → это ограничение конгeст-окна одного TCP, а НЕ жёсткий лимит линии/транзита). RTT ~104 мс, ~50 мс теряются на **одном физическом межоператорском прыжке** (мой провайдер TTK 3–6 мс → хоп `194.186.168.65` до 54 мс). Пер-хоп loss-анализ: грань моего ISP чиста (0%, 3 мс), дальние хопы дают спорадические LOSS-кластеры (ICMP-деприоритизация, НЕ устойчивые потери), re-route 104 мс **полностью не уберёт** (это география/пиринг, не дефектная петля). Мак-download НЕ виноват (CDN ~78 Мбит/с ✅). Файл 720p BR 7.1 GB (средний ~12 Мбит/с, пики >20) в пределах одного TCP-потока ~28–51 Мбит с малым запасом + 104 мс рвёт HLS-буфер → динамичные сцены подтормаживают. **Jellyfin НЕ умеет мультистримить один плейбек** (последовательный HLS на одном TCP; штатной настройки «в N потоков» нет). **Реальные пути:** (в 1) if TrueNAS в одном здании/роутере — дать локальный маршрут к `192.168.2.197` (убьёт 104 мс, LAN-скорость); (2) поднять ап-линию TrueNAS ТОЛЬКО если она реально мала — но замер 117 Мбит up говорит, что скорее нужен не тариф, а (3) снижение эффективной латентности/битрейт-запаса: ограничить jellyfin-транскод < ~20 Мбит ИЛИ прокси, тянущий файл с NAS в 4+ TCP-потоков (подтянет агрегат к 51+), ИЛИ WireGuard-туннель через VPS (меньше jitter/пер-потоковой деградации; минус не убирает 104 мс). Жирный отказ от варианта (б) «поднять ап-линию» как первичного — он основывался на ОШИБОЧНОМ замере 28 Мбит от Мака как потолка TrueNAS. Полный пересмотренный разбор: секция «Плейбек по сети → …» ниже.
|
||||
>
|
||||
> **✅ Два пост-запуска блокатора — ОБА РЕШЕНЫ (2026-09-02 конец):**
|
||||
> 1. **Jellyfin не проигрывал (FFmpeg 243)** — переход решён двумя фиксами: (а) `chown -R 950:950 /mnt/RED_2TB/docker/arr/jellyfin` (конфиг вглубь был 911:911) открыл UI; (б) главный скрытый корень — корень `/mnt/RED_2TB/storage` остался `921:921`, ACL `everyone@ EXECUTE=False` → uid 950 не мог traverse в `/storage/Movies/...`. Фикс (root): `chown 950:950 /mnt/RED_2TB/storage && chmod 750 /mnt/RED_2TB/storage`. После этого jellyfin проигрывает. Транскодинг откл.: Dashboard→Playback→убрать «Allow …transcoding».
|
||||
> 2. **Transmission 255 торрентов "no data found"** — downloadDir УЖЕ корректно указывал на `/storage/Movies`, файлы были и читались под 950; ошибка была закеширована от старта при блокированном traverse. Фикс (НЕ root): `docker restart transmission` → **254/255 чисты** сразу. Остался торрент #1 — Verify в UI.
|
||||
>
|
||||
> **Почему стек изначально не запускался — медиа-права были сломаны** (тот же restore-инцидент uid 921/0000): `/mnt/RED_2TB/storage/{Movies,Cartoons,Downloads,Music,series,shared}` были `d---------`/`drwx------`, owner `transmission` (uid 921). radarr/sonarr монтируют `/storage` (rw), jellyfin `:ro` — со сломанными правами не прочитали бы библиотеку. ✅ **Права медиа ИСПРАВЛЕНЫ** (2026-09-02) до `950:950 drwxrwx---`; контейнеры arr/jellyfin затем подняты и запущены. Полный контекст и команды: `family/documents/vault-sync/2026-09-02-restore-privilege-scope.md`.
|
||||
|
||||
> **Docker-image facts (2026-09-02):** All 5 media images **loaded locally** on TrueNAS (`docker images`): `lscr.io/linuxserver/{radarr,sonarr,jellyfin,transmission,prowlarr}:latest`. All containers now exist and run under **uid 950**. Was: transmission container existed (now running as uid 950); jellyfin/radarr/sonarr/prowlarr containers were NOT yet created — now they are (PUID/PGID=950).
|
||||
> **Transmission originally ran as ROOT** (not 911/950): its compose had no `PUID`/`PGID`, so linuxserver `/init` (s6-overlay) left it root. ✅ **Fixed 2026-09-02:** `PUID=950 PGID=950` added and container force-recreated → now daemon under uid 950. It mounts `storage` → `/mnt/storage`, download-dir = `/mnt/storage/Downloads`.
|
||||
> **Fix direction (approved Variant A):** set `PUID=950 PGID=950` on transmission + all arr/jellyfin compose services so every service shares uid `950` and mutually reads files; then recursively fix perms in depth. Plan + commands: `2026-09-02-restore-privilege-scope.md` §5.
|
||||
>
|
||||
> **PROGRESS 2026-09-02 (updated end-of-session):** Both compose files edited for PUID/PGID=950 (transmission at `/mnt/RED_2TB/docker/transmission/docker-compose.yml`, arr at `/mnt/RED_2TB/docker/arr/docker-compose.yml` incl. all 4 services). **transmission container force-recreated** from its proper folder (`cd /mnt/RED_2TB/docker/transmission && docker compose up -d --force-recreate`) and now runs its daemon as **uid 950** (was root) — env `PUID=950 PGID=950` confirmed, process under `abc`/950. Media perms in depth recursively fixed to `950:950 drwxrwx---` on all top storage folders (incl. git/nas 2nd root pass). **Git-sync on Mac now RESOLVED** — the broken NFS4 `DENY READ_DATA` ACL on ~1946 loose git objects in `obsidian-vault.git` was stripped via full **dacl replacement** (not stripacl), so `git push` from Mac works again (push `a2c7279..2b6c181`, ahead=0 behind=0). **Arr stack is UP (2026-09-02 end):** `cd /mnt/RED_2TB/docker/arr && docker compose up -d` created/started prowlarr/radarr/sonarr/jellyfin. All daemons under **uid 950**. jellyfin reads `/storage/Movies`; radarr↔transmission via `media_net` (`transmission:9091`) OK; caddy resolves transmission via `transmission_default` (Web UI). UI ports: prowlarr 9696, radarr 7878, sonarr 8989, jellyfin 8096, transmission 9091. NOTE: radarr/sonarr/jellyfin mount `/mnt/RED_2TB/storage` as `/storage` (NOT `/media` like Kraken) — radarr root-folder on Taiga differs.
|
||||
|
||||
## Notes from Setup (2026-05-20)
|
||||
|
||||
- Config and pitfalls recorded during initial Taiga arr stack deployment
|
||||
@@ -29,3 +45,71 @@ Secondary arr stack on Taiga (TrueNAS), added 2026-05-20.
|
||||
|
||||
(Details were referenced but not captured. Update this page after next
|
||||
Taiga arr maintenance session.)
|
||||
|
||||
## Плейбек по сети → per-TCP-flow/BDP-ограничение при хай-РТТ (диагноз 2026-09-02, ПЕРЕСМОТРЕН конец сессии)
|
||||
|
||||
**Симптом:** jellyfin на TrueNAS работает, файлы проигрываются, но на ТВ high-bitrate (720p BluRay и выше) *тормозят / грузятся кусками*, потом подтормаживают на динамике.
|
||||
|
||||
**Вердикт — НЕ транскодинг и НЕ ап-линия TrueNAS.** Live-проверка во время плейбека через `docker exec jellyfin sh -c 'ps ... | grep ffmpeg'` и `ls /config/cache/transcodes/`:
|
||||
- нет ни одного дочернего ffmpeg, transcode dir пуст;
|
||||
- jellyfin-процесс `ps` — это сам сервер, не транс-ребёнок.
|
||||
- Файл `The.Jungle.Book.1967.720p.BluRay.5xRus.Eng.HDCLUB.mkv` — h264 **High@L4.1, 1256×720** → приложение ТВ (Jellyfin app) тянет нативно (direct play), транскодинг не нужен.
|
||||
- Lог показывает, что jellyfin даже при direct-play может ремуксовать в **HLS-сегменты по 6 сек** (`-codec:v:0 copy ... -f hls` — копия, не перекодирование). «Грузка кусками» = HLS-сегменты добираются по сети одним TCP-потоком.
|
||||
|
||||
**Сетевая топология (два дома, доступ только через внешку):**
|
||||
|
||||
| | Сеть | Шлюз | Внешний IP | Провайдер |
|
||||
|---|---|---|---|---|
|
||||
| Мак / ТВ | `192.168.1.57` | `192.168.1.1` | динамика | ТТК (92.62.x / 185.20.x) |
|
||||
| TrueNAS | `192.168.2.197` | `192.168.2.2` | `90.189.160.148` | Ростелеком (217.107.x) |
|
||||
|
||||
TrueNAS **физически/логически НЕ в локальной сети Мак/ТВ**. ТВ→Jellyfin идёт целиком по интернету между двумя домами через межоператорский транзит.
|
||||
|
||||
**Замеры (воспроизводимы) — САМОЕ ВАЖНОЕ: замер с самого NAS, а не от Мака.**
|
||||
> Ранняя гипотеза «~28 Мбит = ап-линия TrueNAS ~30 Мбит» была ОШИБОЧНОЙ: 28 Мбит — это потолок ОДНОГО TCP-потока от Мака по пути с 104мс RTT, а НЕ лимит линии TrueNAS. Проверено замером С TrueNAS до Cloudflare:
|
||||
```bash
|
||||
# На самом TrueNAS — интернет-линия НЕ зажата:
|
||||
ssh truenas_admin@mallexxx.duckdns.org \
|
||||
'curl -o /dev/null -s -w "DOWN %{speed_download} B/s\n" "https://speed.cloudflare.com/__down?bytes=50000000"'
|
||||
# DOWN ~23 MB/s ≈ 184 Мбит/с
|
||||
ssh truenas_admin@mallexxx.duckdns.org \
|
||||
'truncate -s 30M /tmp/up.bin && curl -o /dev/null -s -w "UP %{speed_upload} B/s\n" -X POST "https://speed.cloudflare.com/__up" --data-binary @/tmp/up.bin; rm -f /tmp/up.bin'
|
||||
# UP ~14.7 MB/s ≈ 117 Мбит/с
|
||||
# ovh/tele2 speedtest ХОСТЫ ЗАБЛОКИРОВАНЫ из RU (curl 000/timeout) — юзать Cloudflare __down/__up.
|
||||
```
|
||||
|
||||
**Где реальная пропускная просадка — per-TCP-flow/BDP при высоком RTT** (не жёсткий лимит). Ключевой тест — агрегат растёт с параллельностью:
|
||||
```bash
|
||||
# 1 поток: ~28 Мбит/с
|
||||
scp -q truenas_admin@mallexxx.duckdns.org:/tmp/dis.bin /tmp/dis.bin
|
||||
|
||||
# 4 параллельных потока: ~51 Мбит/с ← агрегат РАСТЁТ → BDP-штраф одного TCP при 104мс, не лимит линии/транзита
|
||||
for f in a b c d; do scp -q truenas_admin@mallexxx.duckdns.org:/tmp/$f.bin /tmp/par_$f.bin & done; wait
|
||||
```
|
||||
(8-потоковый тест не дозамерен — апрув на запуск истёк; экстраполированное число НЕ фигурирует.)
|
||||
|
||||
**Латентность и loss по хопам (per-hop):**
|
||||
```bash
|
||||
ping -c 5 mallexxx.duckdns.org # ~104 мс avg
|
||||
traceroute -m 10 -n 90.189.160.148
|
||||
# х1-7 мой провайдер: 3–6 мс
|
||||
# х8 194.186.168.65 → прыжок ~54 мс (переход ТТК→Ростелеком-регион)
|
||||
|
||||
# per-hop loss probe (через отдельные ping каждые ~0.25с к 92.62.74.1 / 194.186.x / 217.107.x / 8.8.8.8):
|
||||
# моя ISP-грань 92.62.74.1: ~3 мс, 0% loss (61/61) ← сегмент чистый
|
||||
# дальние хопы (194.186.x,8.8.8.8): спорадич. LOSS-кластерами синхронно → ICMP-деприоритизация, НЕ устойчивые потери данных
|
||||
# mtr на macOS по умолчанию нет — ставить tofu (brew install mtr). 8.8.8.8 тоже ~53мс → ВСЕ дальние сети идут через тот же 50мс переход.
|
||||
```
|
||||
|
||||
**Вывод (пересмотренный):** ограничитель = **per-TCP-flow / BDP-штраф за 104мс RTT**, а не ап-линия TrueNAS (117 Мбит up — отдаёт, но один поток из-за латентности получает лишь ~28–51). Файл 7.1GB/78 мин → средний ~12 Мбит/с, пики >20 — впритык к achievable single-flow ~28–51 с малым запасом; 104мс рвёт HLS-буфер → стоп-кары. Re-route 104мс полностью НЕ уберёт (пиринг/география, но у Мак/ТВ-все дальние сети идут через тот же 50мс переход — намек, что частичный выигрыш смены исхода возможен, но не гарантирован).
|
||||
|
||||
**Что реально чинит (по убыванию надёжности):**
|
||||
1. **Если TrueNAS в одном здании/роутере** → дать ТВ/Маку локальный маршрут к `192.168.2.197`, не через внешку `90.189.160.148` — убьёт 104мс, станет LAN. Топология в `truenas-infrastructure.md` (Доступ) говорит про разные подсети — обязательно сверить, один ли это физический роутер/здание (вопрос открыт).
|
||||
2. **Jellyfin НЕ умеет мультистримить один плейбек** (последовательный HLS на одном TCP; штатной настройки «в N потоков» нет). Параллельность можно применить только на уровне доставки файла, НЕ внутри jellyfin-потока:
|
||||
- прокси-«качель»: локально отдаёт клиенту один поток, а файл тянет с NAS в 4+ TCP (aria2/hget) → подтянет агрегат к ~51+;
|
||||
- **WireGuard-туннель дом↔NAS через VPS** (`91.207.28.205`, см. `truenas-remote-access-reverse-proxy.md`) — меньше jitter/пер-потоковой деградации, но 104мс физику не уберёт. **⚠ XRAY-ТУННЕЛЬ УЖЕ ИЗМЕРЕН и НЕ ПОМОГАЕТ** (2026-09-02): оба egress-режима локального `xray-test-client` (`kraken-user` reverse → Kraken ~45 Мбит; `user1` direct/REALITY → TrueNAS ~37 Мбит) дают ~35–45 Мбит с нестабильностью — тот же уровень, НЕ кратно выше single-flow прямого пути (28–51 Мбит). Детали и способ переключения клиента: `personal/tech/xray-reverse-tunnel-kraken-truenas.md` § «СОСТОЯНИЕ КЛИЕНТА/Замеры».
|
||||
3. **Прагматичный фикс под ТВ-стрим сейчас:** ограничить jellyfin-транскод битрейтом < ~20 Мбит (заведомо ниже single-flow achievable ~28), чтобы один HLS-поток укладывался без дожевания. Включается сразу, без новой инфраструктуры.
|
||||
4. Поднять ап-линию TrueNAS — **только если** замер из п.º (117 Мбит up) реально маловат для нужного контента; как первичный вариант отвергнут.
|
||||
|
||||
> **Перекрёстно:** это исправление ранней ошибочной записи «потолок ~28 = ап-линия TrueNAS» (см. history этого файла до 2026-09-02). Если будущая сессия увидит противоречие — истина здесь: NAS-линк 184/117 Мбит, проблема per-flow/BDP при высоком RTT.
|
||||
|
||||
|
||||
@@ -85,6 +85,59 @@ docker compose up -d
|
||||
| `hermes/config/` | `/opt/data` | `HERMES_HOME` — config, sessions, skills, memory |
|
||||
| `/home/kraken/obsidian` | `/vault` | Obsidian vault read/write access |
|
||||
|
||||
## SSH из контейнера → хост (диагностика и фиксы)
|
||||
|
||||
> Перенесено из удалённого скилла `kraken-omv-maintenance` / `kraken-docker-ssh`. Актуальные пути и фиксы для случая, когда `ssh kraken-host` изнутри контейнера `hermes-kraken` не работает.
|
||||
|
||||
**Архитектура**
|
||||
|
||||
```
|
||||
Container (hermes-kraken)
|
||||
uid=10000 (dropped from root by entrypoint)
|
||||
HOME=/opt/data
|
||||
~/.ssh/config = /opt/data/.ssh/config (bind mount from host)
|
||||
/etc/ssh/ssh_config — bind mount (полный /etc/ssh/)
|
||||
|
||||
Host (Kraken RPi5)
|
||||
User kraken (uid=1000) owns /home/kraken/.ssh/
|
||||
/home/kraken/.ssh/id_ed25519 — закрытый ключ (обязательно 600)
|
||||
/home/kraken/.ssh/authorized_keys — должен содержать публичный ключ
|
||||
```
|
||||
|
||||
**Fixed points (НЕ менять)**
|
||||
|
||||
1. В compose **не задавать** `user:`, `entrypoint:`, `HERMES_UID/GID` — entrypoint сам сбрасывает uid (image defaults).
|
||||
2. Публичный ключ на хост один раз: `ssh-copy-id kraken@<host>`.
|
||||
3. Закрытый ключ на хосте **обязан быть 600**: `ssh kraken@<host> "chmod 600 /home/kraken/.ssh/id_ed25519"` — OpenSSH 10.x (Bookworm) отвергает 644.
|
||||
4. В `/etc/passwd` контейнера должен быть `kraken:x:1000` — не выставлять `user:` в compose.
|
||||
5. SSH config обязан лежать в `$HOME/.ssh/config` (`$HOME=/opt/data` → `/opt/data/.ssh/config`).
|
||||
|
||||
**Диагностика по порядку**
|
||||
|
||||
```bash
|
||||
ssh kraken@<host> "echo OK && hostname" # доступен ли хост
|
||||
ssh kraken@<host> "sudo docker ps --filter name=hermes-kraken --format '{{.Names}} {{.Status}}'"
|
||||
# изнутри контейнера на хост (loopback алиас kraken-host)
|
||||
ssh kraken@<host> "sudo docker exec hermes-kraken ssh -o ConnectTimeout=5 kraken-host 'echo HELLO'"
|
||||
# verbose — какие конфиги читает SSH
|
||||
ssh kraken@<host> "sudo docker exec hermes-kraken ssh -v kraken-host 'echo HELLO' 2>&1 | grep -E 'config|debug1.*/ssh|Host|connect|Permission|authenticate|bad|owner' | head -15"
|
||||
ssh kraken@<host> "sudo docker exec hermes-kraken getent passwd 1000" # uid 1000 в passwd?
|
||||
ssh kraken@<host> "sudo docker exec hermes-kraken ls -la /opt/data/.ssh/id_ed25519"
|
||||
ssh kraken@<host> "sudo docker exec hermes-kraken cat /opt/data/.ssh/config"
|
||||
ssh kraken@<host> "sudo docker exec hermes-kraken sh -c 'echo HOME=\$HOME; ls -la \"\$HOME/.ssh/config\"'"
|
||||
```
|
||||
|
||||
**Pitfalls**
|
||||
|
||||
- Не менять `user:` в compose — entrypoint должен стартовать как root, чтобы сделать chown.
|
||||
- Не chown'ить `/opt/data` на `1000:1000` — entrypoint делает `chown -R hermes:hermes` (uid 10000).
|
||||
- Не ставить 644 на закрытый ключ.
|
||||
- НЕ использовать `Include ~/.ssh/config` в системном `/etc/ssh/ssh_config` — OpenSSH не резолвит `~` в системных Include.
|
||||
- Если `$HOME=/opt/data`, а конфиг живёт в `/opt/data/home/.ssh/` — SSH его не прочитает (путь не совпадает).
|
||||
- Может быть несколько пар ключей: bind mount приносит хост-ключ, а агент может иметь свой в `/opt/data/home/.ssh/`.
|
||||
- passwd сбрасывается при пересоздании контейнера.
|
||||
- Полный mount `/etc/ssh/` перезаписывает и host keys тоже.
|
||||
|
||||
## Notes
|
||||
|
||||
- `network_mode: host` — port 8642 is directly on the Kraken host, no port mapping needed
|
||||
|
||||
@@ -194,6 +194,10 @@ ZONT relays
|
||||
[8: Конвектор котельная - н.п.]
|
||||
```
|
||||
|
||||
> **ℹ️ Про «виртуальные sensor 101/102/103» и «недоступные датчики в ZONT»:**
|
||||
> 101/102/103 — это **виртуальные Modbus-slaves**, которые контейнер `modbus-bridge` на TrueNAS подставляет на шине `ttyZONT`: реальные 485-датчики **Гостиная=1, Детская=2, Спальня=3** сниффятся и их температуры выдаются ZONT'у как датчики 101/102/103 (регистр 100). ZONT (Modbus master) опрашивает их как внешние датчики.
|
||||
> Если `modbus-bridge` не запущен/не слушает `ttyZONT` → ZONT показывает эти датчики **«недоступные»**. Известная первопричина — гонка docker/udev после рестарта TrueNAS. Подробности и план защиты: `[[family/how-to/truenas-infrastructure.md#Проблема-modbus-bridge/mbusd-после-рестарта-TrueNAS-гонка-с-udev]]` и `[[family/plans/zont-modbus-bridge-udev-race-protection]]`. (Заметка обновлена 2026-08-25: добавлено пояснение про 101/102/103, ZONT relays не менялись.)
|
||||
|
||||
## Карта регистров контроллера вентиляторов
|
||||
|
||||
```
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
# Kraken — Внешний доступ
|
||||
|
||||
> Обновлено: 2026-06-24
|
||||
> Обновлено: 2026-09-01
|
||||
|
||||
> Updated: 2026-09-01 23:00 — диск/докер кракена восстановились после перезагрузки.
|
||||
|
||||
## Как зайти
|
||||
|
||||
Везде `ssh kraken`. Резолвится через `~/.ssh/config` на Eagle:
|
||||
|
||||
- **Дома** — напрямую по LAN (`192.168.1.15`)
|
||||
- **Снаружи** — через WireGuard (`10.99.1.2`, VPN поднимается автоматически `wg-auto.sh`)
|
||||
- **Снаружи** — ⚠️ через 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]]).
|
||||
|
||||
WireGuard split-tunnel: Eagle (10.99.0.2) ↔ VPS ↔ Kraken (10.99.1.2). Подробнее: [[wireguard-vpn]].
|
||||
> ⚠️ **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`.
|
||||
|
||||
> ⚠️ **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). При необходимости — пересоздать из образов.
|
||||
|
||||
## Portainer (локально)
|
||||
|
||||
@@ -26,26 +30,23 @@ EP=3 # endpoint ID на Кракене = 3, не 1!
|
||||
|
||||
`http://kraken:8642/v1/chat/completions` — OpenAI-compatible endpoint.
|
||||
|
||||
## Docker контейнеры (2026-06-24)
|
||||
## Reverse Xray bridge (развёрнут 2026-09-01)
|
||||
|
||||
- Контейнер **`xray-reverse-bridge`** в `/home/kraken/xray-reverse/` (compose + `config.json`, образ `teddysun/xray:latest`, Xray 26.7.28 ARM64).
|
||||
- Outbound VLESS+REALITY TCP → `mallexxx.duckdns.org:12346` (TrueNAS через OpenWrt DNAT), reverse tag `reverse-in`, egress freedom.
|
||||
- ⛔ **End-to-end payload НЕ работает** (bridge принимает reverse-канал, но данные от portal до bridge не доходят). Детали: [[tech/xray-reverse-tunnel-kraken-truenas]].
|
||||
|
||||
## Docker контейнеры (исторически было 2026-06-24; на 2026-09-01 НЕ восстановлены)
|
||||
|
||||
| Имя | Заметки |
|
||||
|-----|---------|
|
||||
| flaresolverr | |
|
||||
| hermes-kraken | |
|
||||
| homeassistant | |
|
||||
| jellyfin | |
|
||||
| portainer | |
|
||||
| prowlarr | |
|
||||
| radarr | |
|
||||
| rclone | |
|
||||
| sonarr | |
|
||||
| transmission | |
|
||||
| cloudflared | |
|
||||
| watchtower | |
|
||||
| xray-reverse-bridge | развёрнут 2026-09-01 (единственный активный) |
|
||||
| flaresolverr / hermes-kraken / homeassistant / jellyfin / portainer / prowlarr / radarr / rclone / sonarr / transmission / cloudflared / watchtower | образы есть, контейнеры потеряны — пересоздать при необходимости |
|
||||
|
||||
## Связанные заметки
|
||||
|
||||
- [[kraken-network]] — SSH, WG топология
|
||||
- [[wireguard-vpn]] — полное описание WG
|
||||
- [[wireguard-vpn]] — полное описание WG (⚠️ VPS-звено мёртво на 2026-09-01)
|
||||
- [[kraken-portainer-access]]
|
||||
- [[openmediavault-rpi5]]
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Kraken Network & Infra
|
||||
created: '2026-05-23'
|
||||
updated: '2026-05-23'
|
||||
updated: '2026-09-02'
|
||||
type: tech
|
||||
namespace: personal
|
||||
tags: [infra, kraken, ssh, wireguard, network]
|
||||
@@ -17,7 +17,20 @@ related:
|
||||
ssh kraken
|
||||
```
|
||||
|
||||
IP: `192.168.1.15` (wlan0, primary). SSH alias `kraken` resolves via `~/.ssh/config`.
|
||||
SSH alias `kraken` resolves via `~/.ssh/config`.
|
||||
|
||||
## Актуальная сеть (проверено 2026-09-02)
|
||||
|
||||
> Оба интерфейса живы. **eth0 — активный uplink** (default route metric 100), wlan0 — fallback (metric 600).
|
||||
|
||||
| Интерфейс | IP | MAC | Uplink role |
|
||||
|---|---|---|---|
|
||||
| **eth0** (Ethernet, Gigabit RPi5 rp1-gem/macb) | `192.168.1.14/24` (DHCP) | `2c:cf:67:64:03:f3` | **primary** — default via `192.168.1.1`, metric 100 |
|
||||
| **wlan0** (WiFi) | `192.168.1.15/24` (DHCP) | `2c:cf:67:64:03:f4` | fallback — metric 600 |
|
||||
|
||||
- Ethernet link: **1000 Mbit/s full duplex** (как и ожидалось для Gigabit-порта RPi5), carrier up, стабильно.
|
||||
- Router/gateway: `192.168.1.1` (`f0:79:59:77:9b:70`). eth0 MAC соответствует static lease в доке [[family/how-to/openmediavault-rpi5|openmediavault-rpi5]].
|
||||
- ⚠️ Ранее эта заметка утверждала «wlan0 = .15 primary» — устарело (см. таблицу выше).
|
||||
|
||||
## WireGuard Topology
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ mallexxx.duckdns.org:/mnt/RED_2TB/storage/git/obsidian-vault.git
|
||||
|
||||
| Узел | Vault путь | Scope | Скрипт | Крон |
|
||||
|------|-----------|-------|--------|------|
|
||||
| Eagle | `~/obsidian` | full vault | `~/scripts/sync-vault.sh` | `0 * * * *` (Hermes cron job) |
|
||||
| Eagle | `~/obsidian` | full vault | `~/scripts/sync-vault.sh` | **launchd `com.sync-vault`** (5 мин; ⚠️ НЕ Hermes cron — см. `vault-git-sync.md` §Scripts) |
|
||||
| Kraken | `~/obsidian` | sparse: `personal/ family/` | `~/scripts/sync-vault.sh` | `0 * * * *` (crontab) |
|
||||
| Taiga | `/mnt/RED_2TB/docker/hermes/vault` | sparse: `personal/ family/` | `~/sync-vault.sh` (на хосте!) | `0 * * * *` (Hermes cron job) |
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
# RED_2TB — карта датасетов и назначений (для решения о пересоздании пула)
|
||||
|
||||
> Собрано: 2026-08-20 (Ель — Кит). Источник: live-данные `zfs list` + `ls` с TrueNAS (readonly-импорт).
|
||||
> НАЗНАЧЕНИЕ: решить, воссоздавать ли карту датасетов как есть, или что-то поменять/добавить/убрать перед пересозданием пула RED_2TB.
|
||||
> Ничего не изменялось — только сбор информации.
|
||||
|
||||
## Статус спасения на 2026-08-21
|
||||
|
||||
- **Выгрузка ЗАВЕРШЕНА УСПЕШНО** (подтверждено Alex). Данные RED_2TB (4.56T) на IronWolf — `DEST`, `/mnt/IRONWOLF`.
|
||||
- **RED_2TB пул — OFFLINE** в БД TrueNAS (id=1), НЕ импортирован. `zpool export` → `no such pool`.
|
||||
- Проверочный rsync прогон завершён (rsync не запущен).
|
||||
- **РЕШЕНИЕ:** пересоздаём пул с новой топологией — ВКЛЮЧАЕМ WD2TB#2 (sdf) зеркалом к WD2TB#1 (sdc). Итог: `mirror {sdc,sdf}` + `mirror {sde,sdd}`.
|
||||
- Следующий шаг: `zpool labelclear` по разделам `*2` + `zpool create` (подробно в [[truenas-sata-ports-and-zfs-pools]] → «Пересоздание пула 2026-08-21»).
|
||||
|
||||
## Общая сводка
|
||||
|
||||
- Пул: RED_2TB, 5.44T (4.61T занято), компрессия lz4, рекордсайз 128K, acltype nfsv4, atime=on, exec=on.
|
||||
- Квот/резерваций НЕТ ни на одном датасете (все `none`).
|
||||
- Монтинг: датасеты в `/RED_2TB/*`, служебные `.system`/`ix-apps` в `legacy`/`/.ix-apps`.
|
||||
|
||||
## ✅ Датасеты (воссоздавать как ZFS datasets)
|
||||
|
||||
| Датасет | USED | REFER | Назначение | Примечание |
|
||||
|---------|------|-------|-----------|------------|
|
||||
| **storage** | 3.24T | 3.24T | Общее хранилище мультимедиа и файлов | Подкаталоги: Cartoons, Downloads, Edu, Movies, Music, ada3s1, art, books, cartoons-series, documentaries(-series), git, nas(пусто), obsidian, obsidian-syncthing, photo_dedup_test, radarr, seafile, series, shared, singularity, sonarr, work. `git/` = hermes-taiga.git, obsidian-vault.git |
|
||||
| **backup** | 287G | 287G | Резервные копии (личные доки, коды, VM, пароли, браузеры) | Много семейных документов (договоры, справки), Google Keep/Play, VPN, Virtual Machines, accessKeys.csv, lastpass_export.zip, коды восстановления. |
|
||||
| **TimeMachine/guest** | 277G | 267G | Бэкапы macOS (Time Machine) | Родитель TimeMachine 277G/96K; дочерний `guest` несёт данные. Много снимков `aapltm-*`. |
|
||||
| **Edu** | 214G | 214G | Учебные материалы | |
|
||||
| **Photos** | 146G | 146G | Фотографии | |
|
||||
| **old-bu** | 65.5G | 65.5G | Старый семейный архив фото/видео | Фото 2009–2010+, свадьбы, семейные события (папки вида `09-01-01 Новый 2009 год!`). |
|
||||
| **ix-apps** | 24.0G | - | Системный — TrueNAS Apps (docker 23.6G, truenas_catalog 385M) | Воссоздаётся самой TrueNAS, не вручную. |
|
||||
| **iocage** | 15.4G | 9.19M | Jail-ы TrueNAS | Jails: backuppc, emby, homeassistant, plex, transmission, worker + releases 11.2/12.2/12.3, images, download, templates. |
|
||||
| **openbsd** | 10.2G | 4.43M | ?? неясно — refer всего 4.43M при used 10.2G | Вероятно remnants после снимка/пробного пула. Решить: нужен ли вообще. |
|
||||
| **docker** | 2.98G | 2.98G | Живой docker-конфиг (текущие контейнеры) | |
|
||||
| **apps** | 192K | 96K | Точка для app-конфигов | Дочерний `apps/homeassistant-config` (96K). |
|
||||
| **.system/** | 568M | - | Служебное TrueNAS (configs, netdata, rrd, samba4, syslog...) | Воссоздаётся самой системой, не создавать руками. |
|
||||
|
||||
## ⚠️ Данные ВНЕ датасетов — лежат прямо в корне `RED_2TB` (REFER 362G)
|
||||
|
||||
Эти пути НЕ являются ZFS-datasets (их нет в `zfs list`) — при пересоздании пула их надо решать отдельно, иначе потеряются (или перепутаются с содержимым корневого датасета):
|
||||
|
||||
| Путь | Содержимое | Важность |
|
||||
|------|-----------|----------|
|
||||
| `/RED_2TB/system/` | SSH-туннель: `tunnel.sh`, `tunnel_key` (приватный!), `tunnel_key.pub`, `99-tty-alias.rules`. Владелец root, режим 600/644. | ⚠️ **КРИТИЧНО** — рабочий туннель TrueNAS. root-only. |
|
||||
| `/RED_2TB/docker.bak/` | Бэкап конфигов docker: caddy, cups, filebrowser, ha, hermes, homeassistant, immich, inpx-web, inpxer, mbusd, modbus-bridge, mosquitto, nodered, portainer, python, rclone, ser2net | Архив/бэкап контейнеров. `hermes/` = бэкап Hermes-агента. |
|
||||
| `/RED_2TB/immich-photos-upload/` | Конфиг Immich: backups, encoded-video, library, profile, thumbs, upload | Рабочий Immich (он же в docker). |
|
||||
| Корневые файлы | `.DS_Store`, `._.DS_Store` (мусор mac), `dedupe_rm.sh`, `files.txt.xz` (содержимое old-bu/somo?) | dedupe_rm.sh — скрипт дедупликации, файловый список. |
|
||||
|
||||
## 🤔 Метки для решения
|
||||
|
||||
Вопросы, которые надо решить ПЕРЕД пересозданием:
|
||||
|
||||
1. **openbsd (10.2G/4.43M)** — судя по refer почти пуст. Что это? Удалить из map?
|
||||
2. **Внутри storage/ есть `Edu`** — это ДУБЛЬ датасета `Edu`? Проверить: возможно медиа-папка Edu в storage vs отдельный датасет Edu для учебных.
|
||||
3. **`nas` внутри storage пуст**.
|
||||
4. **`TimeMachine`** (277G) — вернуть ли отдельным датасетом как было, с дочерним `guest`?
|
||||
5. **`docker` vs `docker.bak`** — оба сохранить? `docker` = живой, `docker.bak` = архив.
|
||||
6. **`immich-photos-upload`** — оставить в корне пула (вне датасета) или завести отдельный датасет?
|
||||
7. **Внедатасетные каталоги** (`system`, `docker.bak`, `immich-photos-upload`) — после пересоздания они окажутся в корневом dataset RED_2TB (REFER 362G). Решить, оставить их там или разнести по датасетам.
|
||||
|
||||
## Ключевые решения по подходу к пересозданию (из truenas-sata-ports-and-zfs-pools.md)
|
||||
|
||||
- In-place починки НЕТ (битая space map, паника на rw).
|
||||
- Рабочий путь: readonly-импорт → выгрузка rsync → `zpool destroy`+`create` → возврат данных rsync.
|
||||
- НЕ использовать `zfs send|recv` (падает на повреждённом пуле). Только rsync.
|
||||
- **РЕШЕНО (2026-08-21):** включить WD2TB#2 (sdf) зеркалом к WD2TB#1 (sdc) при пересоздании. Топология `mirror {sdc,sdf}` + `mirror {sde,sdd}` — оба зеркалированы.
|
||||
- `zpool import`/`mount`/destroy/create — ТОЛЬКО под root (truenas_admin не root).
|
||||
- **НИКОГДА не импортировать RED_2TB в rw** (kernel panic). Только `labelclear` + `create`.
|
||||
|
||||
## Ссылки
|
||||
|
||||
- Связанные: [[truenas-sata-ports-and-zfs-pools]] (план спасения/пересоздания), [[truenas-access]] (общие данные доступа).
|
||||
@@ -2,15 +2,35 @@
|
||||
title: "🖨 Samsung — настройки"
|
||||
aliases: ["Samsung CLX-2160", "Samsung TV", "samsung"]
|
||||
tags: ["family", "how-to", "devices"]
|
||||
updated: "2026-05-17"
|
||||
updated: "2026-08-26"
|
||||
---
|
||||
# 🖨 Samsung — настройки
|
||||
|
||||
## Принтер Samsung CLX-2160 (сетевой адрес)
|
||||
## Принтеры в системе (на Маке admin, macOS)
|
||||
|
||||
```
|
||||
ipps://192.168.2.197:631/printers/Samsung_CLX-216x_Series
|
||||
```
|
||||
Два принтера:
|
||||
- **Samsung CLX-216x** — сетевой: `ipps://192.168.2.197:631/printers/Samsung_CLX-216x_Series`. Драйвер Generic PostScript.
|
||||
- **Samsung M2020 Series** (SEC84251974A6B3) — AirPrint (dnssd), дефолтный. Подключается по Wi-Fi/AirPrint.
|
||||
|
||||
## Состояние печати / шеринга (диагностика 2026-08-26)
|
||||
|
||||
Симптом: с телефона не виден принтер.
|
||||
|
||||
### ✅ Корень проблемы (подтверждено SSH на TrueNAS)
|
||||
|
||||
**Samsung CLX-216x физически подключён к TrueNAS (USB) и обслуживается docker-контейнером `cups-splix` (драйвер splix). Контейнер НЕ запущен** — образ не собран, контейнер отсутствует после пересоздания пула. Поэтому принтер не виден по сети → телефон не печатает.
|
||||
|
||||
- На TrueNAS нет другой службы печати: `lpstat`/`cupsd` не установлены, порт 631 закрыт.
|
||||
- `192.168.2.197` — это адрес TrueNAS (не принтер); запись `ipps://192.168.2.197:631/...` = расшаренная печать TrueNAS.
|
||||
- **Фикс:** пересобрать `cups-splix` и поднять — см. `[[truenas-infrastructure]]` (раздел «cups-splix — принтер») и `[[mac-print-shared-services]]`.
|
||||
|
||||
### Факты из CUPS на этом Маке (вторичны для этой проблемы)
|
||||
- `Listen localhost:631` — служба печати CUPS слушает **только локально**, наружу не отдаёт.
|
||||
- `SharePrinters` в `/etc/cups/cupsd.conf` не активен — **шеринг печати выключен** (оба принтера `Shared: No`). Шеринг на Маc актуален только для принтера, висящего на Маcе (Samsung M2020).
|
||||
|
||||
Подсеть: Мак в этом сеансе был на `192.168.6.x`, инфраструктура живёт на `192.168.2.x` — расхождение из-за того, что Мак был вне основной сети, а не из-за принтера.
|
||||
|
||||
Примечание: `sudo -n cupsctl` не работает без пароля — шеринг удалённо через SSH проверить нельзя.
|
||||
|
||||
## Отключение Detecting Device
|
||||
|
||||
|
||||
@@ -9,12 +9,16 @@ Android (Syncthing app)
|
||||
│ P2P sync (QUIC/TCP :22000)
|
||||
▼
|
||||
TrueNAS (syncthing контейнер)
|
||||
/var/syncthing/obsidian-vault → /mnt/RED_2TB/storage/obsidian
|
||||
/var/syncthing/obsidian-vault → /mnt/RED_2TB/storage/obsidian-syncthing
|
||||
│
|
||||
├── Obsidian vault (полная копия на TrueNAS)
|
||||
└── Eagle (Mac) — продолжает через git, Syncthing не участвует
|
||||
```
|
||||
|
||||
> ⚠️ **2026-09-02 уточнение:** фактический mount в compose — `/mnt/RED_2TB/storage/obsidian-syncthing` (НЕ `/storage/obsidian`). Есть две отдельные папки:
|
||||
> - `/storage/obsidian` — архивная/рабочая копия vault (старый mount в доке; `.stfolder` отсутствует) — НЕ является sync target.
|
||||
> - `/storage/obsidian-syncthing` — **активная sync-копия** (`.stfolder` присутствует, uid 950) — это то, что реально монтируется контейнером. По ней и идёт телефонная синхронизация. В блоке `volumes:` ниже именно она.
|
||||
|
||||
## Доступ
|
||||
|
||||
- **Web UI:** https://syncthing.mallexxx.duckdns.org
|
||||
@@ -42,7 +46,7 @@ services:
|
||||
- TZ=Asia/Novosibirsk
|
||||
volumes:
|
||||
- /mnt/RED_2TB/docker/syncthing/config:/var/syncthing/config
|
||||
- /mnt/RED_2TB/storage/obsidian:/var/syncthing/obsidian-vault
|
||||
- /mnt/RED_2TB/storage/obsidian-syncthing:/var/syncthing/obsidian-vault
|
||||
ports:
|
||||
- "22000:22000/tcp"
|
||||
- "22000:22000/udp"
|
||||
@@ -55,7 +59,9 @@ networks:
|
||||
external: true
|
||||
```
|
||||
|
||||
**UID 950** = `truenas_admin` — имеет `FULL_CONTROL` ACL на `/mnt/RED_2TB/storage/obsidian`.
|
||||
**UID 950** = `truenas_admin` — имеет `FULL_CONTROL` ACL на `/mnt/RED_2TB/storage/obsidian-syncthing` (и на `/storage/obsidian`).
|
||||
|
||||
> **Питфол (после restore 2026-08-31):** после восстановления из бэкапа и syncthing-папка (`obsidian-syncthing`), и многие `/storage/*` стали `uid 921` (`transmission`) с правами 0000 → syncthing-папка уходит в `error: stat .stfolder: permission denied` → телефонная синхронизация стоит. Фикс: вернуть `950:950` + `u+rwX,g+rwX` (см. `family/documents/vault-sync/2026-08-31-syncthing-truenas-incident.md`). Эта же поломка затрагивает `git/` и медиа-папки (см. `2026-09-02-restore-privilege-scope.md`).
|
||||
|
||||
## Caddy
|
||||
|
||||
|
||||
@@ -42,6 +42,15 @@ docker run --rm alpine sh -c 'apk add -q openssh sshpass && sshpass -p 1316261 s
|
||||
|
||||
**Пароль root:** `1316261`
|
||||
|
||||
> 💡 **Бэкап firewall OpenWrt перед любой правкой redirect-правил** (вошло в практику 2026-09-01):
|
||||
> ```bash
|
||||
> # с TrueNAS: сохранить весь firewall-конфиг OpenWrt в backup-папку TrueNAS
|
||||
> docker run --rm alpine sh -c 'apk add -q openssh sshpass && sshpass -p 1316261 ssh -o StrictHostKeyChecking=no root@192.168.2.2 "uci show firewall"'
|
||||
> # → сохранить вывод в /mnt/RED_2TB/docker/backups/openwrt-firewall-YYYYMMDD-HHMMSS.txt
|
||||
> # Пример сделанного: /mnt/RED_2TB/docker/backups/openwrt-firewall-20260901-130558.txt
|
||||
> ```
|
||||
> Существующие redirect-правила OpenWrt → TrueNAS(192.168.2.197): MQTT 1883, SSH 22, caddy_http 80→8088, caddy_https 443→8443, HomeAssistant 8123 (disabled).
|
||||
|
||||
## Пул и датасеты
|
||||
|
||||
Пул: RED_2TB (ZFS)
|
||||
|
||||
@@ -1,6 +1,36 @@
|
||||
# TrueNAS — инфраструктура
|
||||
|
||||
> Обновлено: 2026-07-06
|
||||
> Обновлено: 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/<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-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`.
|
||||
|
||||
## Доступ
|
||||
|
||||
@@ -12,6 +42,14 @@
|
||||
- ⚠️ Eagle (Mac, 192.168.1.x) и Kraken (192.168.1.15) находятся в **другой подсети**
|
||||
- ⚠️ Кра́кен и TrueNAS — **разные сети** (192.168.1.x vs 192.168.2.x). Доступ с Кракена на TrueNAS по локальному IP **не работает**
|
||||
|
||||
**⚠️ Измеренный потолок канала Mac/ТВ (192.168.1.x) → TrueNAS (192.168.2.x) — 2026-09-02:**
|
||||
**⚠️ Измеренный потолок канала Mac/ТВ (192.168.1.x) → TrueNAS (192.168.2.x) — 2026-09-02, ПЕРЕСМОТРЕНО:**<br>Между этими двумя сетями нет LAN — только обход через внешку провайдеров (ТТК дом A ↔ Ростелеком дом B). Замерено:
|
||||
- **Single TCP flow ≈ 28 Мбит/с**, но **4 параллельных потока ≈ 51 Мбит/с** (агрегат РАСТЁТ с параллельностью) → это **per-TCP-flow / BDP-штраф за ~104 мс RTT**, а **НЕ лимит линии TrueNAS**.
|
||||
- ⚠️ **ПОЗДНЕЙШИЙ ЗАМЕР С САМОГО NAS ОПРОВЕРГ раннюю запись «ап-линия TrueNAS ~30 Мбит/с»**: NAS → Cloudflare даёт **~184 Мбит/с down / ~117 Мбит/с up** (`curl https://speed.cloudflare.com/__down?bytes=50000000` и POST `__up`). ovh/tele2 speedtest из RU заблокированы — юзать Cloudflare-эндпоинты.
|
||||
- **~104 мс RTT**, из них ~50 мс на **одном межоператорском хопе** `194.186.168.65` (TTK 3–6 мс → прыжок до ~54 мс). Per-hop loss: моя ISP-грань чиста (0%, 3 мс); дальние хопы дают спорадич. LOSS (ICMP-деприоритизация, не устойчивые потери). Re-route 104мс полностью не уберёт (пиринг/география).
|
||||
- Следствие: **высокобитрейтный медиа-плейбек (720p BluRay и выше) через jellyfin на этом пути тормозит/грузится кусками** (HLS одним TCP + 104мс RTT, single-flow ~28–51 Мбит впритык к пикам файла). НЕ транскодинг (direct-play). **Jellyfin не умеет мультистримить один плейбек.**
|
||||
- Пересмотренный разбор + команды: `family/how-to/arr-stack-taiga.md` → «Плейбек по сети → per-TCP-flow/BDP». Решения: дать локальный маршрут (если TrueNAS в одном здании/роутере), ограничить jellyfin-битрейт < ~20 Мбит, или прокси с мульти-TCP-загрузкой файла, или WireGuard-туннель через VPS.
|
||||
|
||||
## Пользователи и группы (ключевые)
|
||||
|
||||
| uid | Имя | gid | Назначение |
|
||||
@@ -91,12 +129,60 @@ TrueNAS использует **NFSv4 ACL**, а не стандартный POSIX
|
||||
| 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/<app>/`. Модель — **не один общий 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:** `/mnt/RED_2TB/docker/transmission/` (монтируется как `/config`; внутри `/config/docker-compose.yml`)
|
||||
- **Данные:** `/mnt/RED_2TB/storage` (монтируется как `/mnt/storage`)
|
||||
- **Download dir:** `/mnt/storage/Downloads`
|
||||
- **UID/GID:** 911/911 (пользователь `transdamon`)
|
||||
- **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)
|
||||
@@ -115,6 +201,64 @@ TrueNAS использует **NFSv4 ACL**, а не стандартный POSIX
|
||||
| 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`; 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-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` снаружи открыт.
|
||||
- **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` — клиент падает. Это частая причина «не подключается».
|
||||
|
||||
**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)
|
||||
|
||||
**Цель:** 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 работает 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 — детали
|
||||
|
||||
@@ -144,24 +288,49 @@ ssh truenas_admin@mallexxx.duckdns.org "docker restart homeassistant"
|
||||
ssh truenas_admin@mallexxx.duckdns.org "docker exec homeassistant python -m homeassistant --script check_config --config /config"
|
||||
```
|
||||
|
||||
### mbusd — Modbus TCP gateway
|
||||
### mbusd — Modbus RTU → TCP gateway
|
||||
|
||||
Мост Modbus RTU → TCP: пробрасывает серийный порт инвертора AT2 вентиляции в TCP 502.
|
||||
Мост Modbus RTU → TCP: пробрасывает серийный порт в TCP 502. Используется и для вентиляции (AT2), и для ZONT-шины.
|
||||
|
||||
- **Image:** `3cky/mbusd`
|
||||
- **Порт:** `502:502`
|
||||
- **Config:** `/mnt/RED_2TB/docker/mbusd/mbusd.conf` → `/etc/mbusd.conf`
|
||||
- **Device:** `/dev/ttyVent` → `/dev/ttyUSB0` (внутри контейнера)
|
||||
- **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 — AT2 Modbus → MQTT
|
||||
### modbus-bridge — 485-датчики + виртуальные slaves для ZONT
|
||||
|
||||
Кастомный Python-мост: читает регистры инвертора AT2 через mbusd и публикует в MQTT → Home Assistant.
|
||||
Кастомный Python-мост (`modbus_ha_bridge.py`, репо `HA-ZONT-Modbus`), контейнер `/mnt/RED_2TB/docker/modbus-bridge/`.
|
||||
|
||||
- **Image:** `modbus-bridge` (локальная сборка)
|
||||
- **Volumes:**
|
||||
- `/mnt/RED_2TB/docker/modbus-bridge/config.yml` → `/app/config.yml` (ro)
|
||||
- `/mnt/RED_2TB/docker/modbus-bridge/modbus_ha_bridge.py` → `/app/modbus_ha_bridge.py` (ro)
|
||||
- **Source:** `modbus_ha_bridge.py` в репозитории `HA-ZONT-Modbus`
|
||||
- **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/<room>/...`), а также пишет в 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 <c> --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
|
||||
|
||||
@@ -310,6 +479,50 @@ git -C /mnt/RED_2TB/storage/git/obsidian-vault.git log --oneline -10
|
||||
|
||||
---
|
||||
|
||||
## Печать / 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]].
|
||||
|
||||
> ✅ **2026-09-02: печать ИЗВНЕ сети TrueNAS работает через SSH → cups-splix.** Хотя `mallexxx.duckdns.org:631` (IPP) снаружи закрыт, документ (PDF, 1 стр A4) успешно напечатан с клиента вне подсети: `scp` → TrueNAS `/tmp` → `docker cp` внутрь `cups-splix:/tmp` → `docker exec cups-splix lp -d Samsung_CLX-216x_Series -o media=A4 file.pdf` → job в `completed`, `Rendering completed`. CUPS сам конвертит PDF→PS (gs/pdftops есть, PPD `*cupsFilter: 0 pstoqpdl`). Полный рецепт — [[mac-print-shared-services]] (раздел «Печать PDF извне сети TrueNAS»).
|
||||
|
||||
## Связанные заметки
|
||||
- [[truenas-access]] — SSH-доступ
|
||||
- [[truenas-rclone-backup]] — система бэкапов
|
||||
|
||||
@@ -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/<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-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 <path>`
|
||||
- Добавить запись: `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/<app>/`. Модель — **не один общий 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/<room>/...`), а также пишет в 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 <c> --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
|
||||
<style>
|
||||
@media (prefers-color-scheme: dark) {
|
||||
path, line, polyline, polygon, rect, circle, ellipse { stroke: white; }
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
> Ж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)
|
||||
@@ -1,8 +1,60 @@
|
||||
# TrueNAS — SATA порты и пулы
|
||||
|
||||
<<<<<<< HEAD
|
||||
> Обновлено: 2026-08-17
|
||||
|
||||
## ✅ РЕШЕНО: HGST 12TB завёлся — проблема была в 3.3V PWDIS, НЕ в карте
|
||||
=======
|
||||
> Обновлено: 2026-08-21 (данные спасены, пул RED_2TB OFFLINE, готовность к пересозданию). СТАТУС: выгрузка данных на IronWolf **завершена успешно** (4.56T на `/mnt/IRONWOLF`, подтверждено Alex). Пул RED_2TB **OFFLINE** (не импортирован), диски физически на месте. Идёт подготовка к пересозданию пула с новой топологией (добавляем WD2TB#2 зеркалом к WD2TB#1). HGST сломан (см. ниже).
|
||||
|
||||
## ✅ РЕШЕНО (2026-08-21): пул RED_2TB — данные спасены, пул OFFLINE, готовность к пересозданию
|
||||
|
||||
**ВЫГРУЗКА ДАННЫХ ЗАВЕРШЕНА УСПЕШНО.** Alex подтвердил: «операция завершилась успешно, ничего не было перезаписано». Данные RED_2TB (4.56T) лежат на IronWolf 12TB — пул `DEST`, `/mnt/IRONWOLF`. Ключевые конфиги подтверждены на `/mnt/IRONWOLF`: `system/tunnel.sh`+`tunnel_key`+`.pub` (критичный SSH-туннель), `docker.bak/` (309M), `docker/` (1.1G), `immich-photos-upload`, `dedupe_rm.sh`, `files.txt.xz`. `storage/obsidian` и `storage/git` существуют (Permission denied для `truenas_admin` из-за NFSv4 ACL, transmission-owner — это нормально, НЕ потеря).
|
||||
|
||||
**Текущее состояние (2026-08-21, live-проверка):**
|
||||
- **RED_2TB пул — статус OFFLINE** в БД TrueNAS (`midclt call pool.query` → `id=1, guid 3817880812699166755`), пул **НЕ импортирован**. `zpool export RED_2TB` → `no such pool` (уже выгружен/не в активном контексте).
|
||||
- `zpool import -d /dev` всё ещё **видит** RED_2TB как **ONLINE** импортируемый, члены: `sdc2` (simplex WD2TB#1) + `mirror-1 {sde2 WD4TB, sdd2 Seagate4TB}`.
|
||||
- rsync не запущен — проверочный прогон завершён.
|
||||
- Диски физически на месте (by-id, см. таблицу портов ниже).
|
||||
|
||||
**Актуальная раскладка дисков (2026-08-21, по `/dev/disk/by-id`, стабильные имена):**
|
||||
| Диск | by-id/model | Роль |
|
||||
|------|------------|------|
|
||||
| sda | `ata-KINGSTON_SA400S37120G_50026B77844E881C` | Boot SSD (не трогать) |
|
||||
| sdb | `ata-ST12000NT001-3LX101_WV700FQ5` | ⭐ IronWolf 12TB = DEST, `/mnt/IRONWOLF` (целевой, данные выгружены) |
|
||||
| sdc | `ata-WDC_WD20EFAX-68B2RN1_WD-WXH2A31D5HDJ` | **WD2TB#1** (исходный simplex-член RED_2TB) |
|
||||
| sdd | `ata-ST4000DM004-2CV104_WFN66CM2` | **Seagate4TB** (mirror-1 второй член) |
|
||||
| sde | `ata-WDC_WD40EZAZ-00SF3B0_WD-WX22D51JJFZ7` | **WD4TB** (mirror-1 первый член) |
|
||||
| sdf | `ata-WDC_WD20EFAX-68B2RN1_WD-WXJ2A31CUNNT` | **WD2TB#2** (доп., НЕ в исходном пуле) |
|
||||
|
||||
## ⚠️⚠️ АКТИВНАЯ ПРОБЛЕМА №1 (ЗАКРЫТО, история): пул RED_2TB импортирован READONLY, данные выгружались rsync
|
||||
|
||||
Пан-loop преодолён (рецепт ниже). RED_2TB импортирован readonly удачно — **паники больше нет**. **ПРОГРЕСС 2026-08-18:** дочерние datasets (`storage`, `backup`, `Photos`, `Edu`, `docker`, `old-bu`, `TimeMachine/guest`, `iocage/*`) **успешно смонтированы под root** (`zfs mount -a` + при необходимости `mount -o remount,rw /`). Данные видны. Выгрузка на IronWolf идёт **rsync** (см. блок ниже).
|
||||
|
||||
**ТЕКУЩИЙ БЛОКЕР (конец сессии):**
|
||||
- `zpool import`/`mount` требуют **root** (`some devices require root privileges`). `truenas_admin` НЕ root (sudo просит пароль). Все операции с пулом — только под root.
|
||||
- **Нужно добыть root:** SSH → включить root login (`PermitRootLogin`), или выполнять команды через WebUI-админ/консоль.
|
||||
- **IronWolf 12TB подключён к материнке** (sdc) как целевой диск для спасения данных. На нём **создан пул-приёмник `DEST`** (rw, ONLINE, ~10.6T свободно), монтируется на `/mnt/IRONWOLF`. Первая попытка rsync скопировала только 355G (см. блок 2026-08-18 ниже).
|
||||
- **WD 2TB#1 (sda2, simplex-член RED_2TB) СЕЙЧАС ОТКЛЮЧЁН** — чтобы загрузиться без паники его отсоединяли; на конец сессии он не в системе. RED_2TB без него может импортироваться, но его данные частично будут недоступны.
|
||||
|
||||
## ⚠️⚠️ ПРОБЛЕМА №2: HGST 12TB УРОНЕН НА ПОЛ — вероятный слом после падения
|
||||
|
||||
**2026-08-17 вечер.** HGST (HUH721212ALE600, сер. 8CKD08RE) **уронили на пол, будучи подключённым**. Развитие сценария (как происходило):
|
||||
|
||||
1. **После удара — сектор 0 стал нечитаем** (по USB-мосту): ядро давало `critical medium error, dev sdf, sector 0` → `Add. Sense: Unrecovered read error` → `unable to read partition table` / `unable to read RDB block 0`. Разметка (`sdf1`/`sdf2`) пропала. Это НЕ ошибка моста/кабеля — `hostbyte=DID_OK driverbyte=DRIVER_OK`, ошибку вернул сам диск.
|
||||
2. **smartctl мог прочитать INFO-секцию** (`Model: HGST HUH721212ALE600`, `8CKD08RE`, FW `LEBDT3P2`, 512e, SATA 6.0 Gb/s, SMART enabled) — контроллер жив, линк поднят.
|
||||
3. **На MacBook через USB-мост диск «щёлкает» и не шуршит головкой при старте** — признак механических проблем после удара (головки/мотор). КЛИК-ОФ-ДЕФ возможен, но также нельзя исключать нехватку питания через USB-мост на 12TB-диске.
|
||||
|
||||
**Состояние (на 2026-08-17):** **подтверждён аппаратный отказ — диск не ремонтопригоден.** Симптом: ритмичный «click-click, click-click» при работающем моторе = головки не могут выйти на дорожку/парковку (классический click of death после удара). Это механическое повреждение, НЕ лечится программно (SMART/прошивка), чинить может только профи-recovery и это дороже нового диска. **Данных на нём НЕТ** (не был добавлен в пул, только новая разметка sdf1/sdf2) — поэтому списан без recovery. Закрыто.
|
||||
|
||||
> ⚠️ Урок для будущего: enterprise-диск, уроненный на пол работающим — почти всегда аппаратная смерть (мотор/головки). Если на диске критичные данные — только профи-recovery, и шанс не 100%.
|
||||
|
||||
> 🔁 ИСТОРИЯ ВОПРОСА: до падения диск был ПОЛНОСТЬЮ рабочим. Причина исходного «молчания» по SATA — PWDIS (см. ниже). После снятия 3.3V завёлся и линковался. Затем урон на пол — аппаратный отказ (click of death).
|
||||
|
||||
---
|
||||
|
||||
## ✅ РЕШЕНО (исторически): HGST 12TB заводился — проблема была в 3.3V PWDIS, НЕ в карте
|
||||
>>>>>>> origin/main
|
||||
|
||||
**2026-08-17.** HGST **линуется и полностью работает** теперь. Ключевое изменение — **отключена/обезврежена 3.3V линия (PWDIS-контакт №3 на SATA-разъёме питания)**. Диск:
|
||||
- определяется как `/dev/sde`, `HGST HUH721212ALE600`, серийник `8CKD08RE`, **10.9T**, секторов `23437770752` (штатная ёмкость 12TB по SFF-8447)
|
||||
@@ -16,11 +68,16 @@
|
||||
**ASUS P8H77-V LE**, чипсет Intel H77.
|
||||
6 SATA портов на Intel контроллере (порт от ASMedia отсутствует).
|
||||
|
||||
<<<<<<< HEAD
|
||||
### Распределение портов (текущее состояние — после перетыкания 2026-08-17)
|
||||
=======
|
||||
### Распределение портов (актуально на конец 2026-08-17, после финального перетыкания)
|
||||
>>>>>>> origin/main
|
||||
|
||||
| Порт (ata) | Тип | Скорость | Цвет | Диск | by-id |
|
||||
|------------|-----|----------|------|------|-------|
|
||||
| ata1 (SATA6G_1) | SATA 3 | 6 Gb/s | серый | **sda** — WD 2TB (WD20EFAX) | WD-WXH2A31D5HDJ |
|
||||
<<<<<<< HEAD
|
||||
| ata2 (SATA6G_2) | SATA 3 | 6 Gb/s | серый | **sdb** — WD 2TB (WD20EFAX, второй, был на карте ata9) | WD-WXJ2A31CUNNT |
|
||||
| ata3 (SATA3G_1) | SATA 2 | 3 Gb/s | синий | **sdc** — WD 4TB (WD40EZAZ) | WD-WX22D51JJFZ7 |
|
||||
| ata4 (SATA3G_2) | SATA 2 | 3 Gb/s | синий | **sdd** — Kingston 120GB SSD (boot) | 50026B77844E881C |
|
||||
@@ -34,6 +91,24 @@
|
||||
- Несмотря на перетыкание пулы **здоровы** (см. раздел про пулы ниже) — подтверждено, что ZFS не зависит от порта.
|
||||
|
||||
> ⚠️ В отличие от изначального плана, диски сейчас не по плану — проверять актуальное распределение по `by-id`/модели, а не по буквам. Типичные буквы при стабильном подключении: sda=WD2TB#1, sdb=WD2TB#2, sdc=WD4TB, sdd=Kingston, sde=Seagate4TB.
|
||||
=======
|
||||
| ata2 (SATA6G_2) | SATA 3 | 6 Gb/s | серый | **sdb** — WD 4TB (WD40EZAZ) | WD-WX22D51JJFZ7 |
|
||||
| ata3 (SATA3G_1) | SATA 2 | 3 Gb/s | синий | **sdc** — ⭐ **IronWolf 12TB (ST12000NT001)** | WV700FQ5 |
|
||||
| ata4 (SATA3G_2) | SATA 2 | 3 Gb/s | синий | **sdd** — Kingston 120GB SSD (boot) | 50026B77844E881C |
|
||||
| ata5 (SATA3G_3) | SATA 2 | 3 Gb/s | синий | *(свободен/не иден-тиф.)* | — |
|
||||
| ata6 (SATA3G_4) | SATA 2 | 3 Gb/s | синий | **sde** — Seagate 4TB (ST4000DM004) | WFN66CM2 |
|
||||
| *(карта ASM1166)* | — | — | — | **НЕ В СЛОТЕ** (вытащена) | — |
|
||||
|
||||
**⚠️ Фактическое положение на конец сессии (2026-08-17, после подключения IronWolf для спасения):**
|
||||
- **Буквы разъехались ещё раз.** Финальный `lsscsi`: **sda=WD4TB**, **sdb=Kingston boot**, **sdc=⭐ IronWolf 12TB (целевой для спасения)**, **sdd=Seagate4TB**. **WD 2TB#1 (`WD-WXH2A31D5HDJ`) СЕЙЧАС ОТКЛЮЧЁН / НЕ в системе** (отсоединяли, чтобы загрузиться без паники).
|
||||
- **⭐ IronWolf 12TB подключён к материнке и ЛИНКУЕТСЯ** — `sdc` = `ST12000NT001-3LX101`, 10.9T, by-id `WV700FQ5`. Он свободен (не в пуле) и определён как **целевой диск для спасения данных с RED_2TB**. На нём ещё НЕ создан пул-приёмник.
|
||||
- **Карта ASMedia ASM1166 вытащена** — `lspci` показывает только Intel H77 (`00:1f.2`). WD 2TB#2 перенесён с карты, затем был намеренно отключён пользователем.
|
||||
- **HGST 12TB (`HUH721212ALE600`)** — УРОНЕН НА ПОЛ, аппаратный отказ (см. блок КРИТИЧНО), считается вышедшим из строя.
|
||||
|
||||
> ⚠️ Буквы (`sda`/`sdb`) **shift-аются при перетыкании** и сейчас разъехались: `sdb` = WD4TB (не WD2TB#2!), `sdc` = IronWolf. **Всегда сверять по by-id/модели, не полагаться на буквы.**
|
||||
|
||||
> ⚠️ ⚡ **СРОЧНО:** пул `RED_2TB` после этого перетыкания НЕ заимпортирован (см. блок «КРИТИЧНО» в разделе пулов). Все члены на месте — нужен Import Pool.
|
||||
>>>>>>> origin/main
|
||||
|
||||
## Плата расширения SATA в PCIe (установлена ~2026-07-30)
|
||||
|
||||
@@ -63,7 +138,11 @@
|
||||
|
||||
## ✅ Решение HGST 12TB (2026-08-17) — корень найден, диск работает
|
||||
|
||||
<<<<<<< HEAD
|
||||
> ⚠️ **Актуальный статус на 2026-08-17 вечер:** хоть HGST и завёлся (см. ниже КАК), в финальном перетыкании **карта ASM1166 вытащена из слота, HGST и IronWolf сейчас НЕ подключены** (подробнее в таблице портов выше). Этот блок фиксирует **как была решена причина не-линка** — пригодится, когда диск вернётся в систему.
|
||||
=======
|
||||
> ⚠️ **Актуальный статус на 2026-08-17 ночь:** HGST **УРОНЕН НА ПОЛ и сломан** (см. блок КРИТИЧНО в самом верху). Карта ASM1166 вытащена из слота, IronWolf подключён на материнку. Этот блок фиксирует **как изначально решалась причина не-линка** (PWDIS) — полезно для понимания, но теперь диск вышел из строя механически.
|
||||
>>>>>>> origin/main
|
||||
|
||||
Проблема не-линка HGST по SATA **решена: это 3.3V PWDIS на SATA-питании.** Разметка не трогалась — sde1=200M, sde2=10.9TB остались как были. Когда диск снова будет подключён — добавить в пул TrueNAS по by-id/GUID (ZFS к порту не привязана). После добавления — удалить этот блок.
|
||||
|
||||
@@ -102,20 +181,192 @@ lspci -k | grep -i sata
|
||||
## Важно про ZFS и перетыкание
|
||||
|
||||
- ZFS не привязана к букве диска или SATA порту. TrueNAS распознаёт пул по GUID на дисках.
|
||||
<<<<<<< HEAD
|
||||
- Можно перетыкать диски в любые порты — TrueNAS поднимет пул автоматически (подтверждено 2026-08-17).
|
||||
- Если пул не поднялся автоматически: WebUI → Storage → Import Pool.
|
||||
=======
|
||||
- **Перетыкание НЕ всегда поднимает пул автоматически** (2026-08-17: RED_2TB не заимпортировался сам после перетыкания, см. «КРИТИЧНО» ниже). Если пул не виден в `zpool list` — нужен ручной Import (WebUI Storage → Import Pool или `zpool import <pool>` под root). Данные при этом целы, пока все члены `ONLINE`.
|
||||
>>>>>>> origin/main
|
||||
- Проверка пула после перетыкания: `/sbin/zpool status <pool>` — убедиться что все члены `ONLINE`, ошибки `0 0 0`.
|
||||
|
||||
## Пулы TrueNAS (проверено 2026-08-17)
|
||||
|
||||
Имена пулов, топология и члены — проверять статус через `/sbin/zpool` (см. ниже про PATH).
|
||||
|
||||
<<<<<<< HEAD
|
||||
| Пул | Размер | Члены (по /dev со стабильным подключением) | Топология | Монтирование |
|
||||
|-----|--------|-----------|-----------|--------------|
|
||||
| **RED_2TB** | 5.44T (4.60T занято) | mirror: `sdc2` (WD4TB) + `sde2` (Seagate4TB); отдельно `sda2` (WD2TB) | 1 диск (sda2) + mirror-1 (2 диска) | `/mnt` |
|
||||
| **boot-pool** | 111G (7.65G занято) | `sdd3` (Kingston 120GB boot SSD) | 1 диск | — |
|
||||
|
||||
- RED_2TB: HEALTH **ONLINE**, нераспределённый свободный диск (данные не реплицируются на sda2 — он отдельный, а не парный). Если redun-dancy важна — учесть, что sda2 без зеркала.
|
||||
=======
|
||||
| Пул | Размер | Члены (по `/sbin/zpool status` от 2026-08-17) | Топология | Монтирование |
|
||||
|-----|--------|-----------|-----------|--------------|
|
||||
| **RED_2TB** | 5.44T (4.60T занято) | **state ONLINE, 0 0 0 ошибок, "No known data errors"**: `sdd2` (WD2TB#1) + mirror-1 `{sdc2 WD4TB, sdb2 Seagate4TB}` — буквы по последнему status, сверять by-id (буквы shift-аются) | 1 диsk (`WD2TB#1`) + mirror-1 (WD4TB+Seagate) | `/mnt` — **readonly-импорт, datasets не смонтированы, данные НЕ выгружены** |
|
||||
| **boot-pool** | 111G (7.65G занято) | `sdb3` (Kingston 120GB boot SSD) | 1 диск | — |
|
||||
|
||||
- RED_2TB: HEALTH **ONLINE** по `zpool status` (readonly-импорт не паникует), scrub «завис» на ~72% (при readonly не доходит — но это НЕ фикс, см. ниже). Все ошибки 0 0 0 — **данные целы**. Один vdev (`WD2TB#1`) simplex — без зеркала; WD2TB#1 сейчас физически отключён.
|
||||
|
||||
### ✅ ПРОГРЕСС (2026-08-17 глубокая ночь): READONLY-импорт УСПЕШЕН, паника преодолена
|
||||
|
||||
**Рабочий рецепт получения доступа к данным подтверждён на практике.** Члены пула физически на месте: `sda2`=WD2TB#1 (ata1), `sdb2`=WD4TB (ata2, буква сменилась), `sde2`=Seagate4TB (ata6).
|
||||
|
||||
**Что сработало (пошагово):**
|
||||
1. Тюнабели `zfs.zfs_recover=1 zfs.zil_replay_disable=1` в GRUB → **НЕ помогли** (всё равно паника). `rd.break=pre-mount` и `rd.break` → тоже НЕ помогли.
|
||||
2. **ЕДИНСТВЕННЫЙ рабочий способ загрузиться без паники:** физически ОТКЛЮЧИТЬ все диски проблемного пула (чтобы дойти до рабочего shell/WebUI), затем вставить обратно.
|
||||
- Включить с отключёнными дисками RED_2TB (WD2TB#, WD4TB, Seagate4TB) → boot-pool поднимается, паники нет.
|
||||
- Вставить диски обратно (горячо) в те же порты.
|
||||
3. **READONLY-импорт не паникует** (по mav из iXsystems: «read-only import doesn't even read space maps»):
|
||||
```bash
|
||||
zpool import -o readonly=on RED_2TB
|
||||
```
|
||||
→ **`Import was successful`** — паники нет, метаданные прочитаны! (попытка `zpool import -nRED_2TB` без `-F` невозможна; `-n` требует `-F` синтаксиса.)
|
||||
4. **⚠️ Текущий блок:** после readonly-импорта выдаются ошибки монтирования:
|
||||
```
|
||||
cannot mount '/RED_2TB': failed to create mountpoint: Read-only file system
|
||||
Import was successful, but unable to mount some datasets
|
||||
```
|
||||
Причина: корневая ФС readonly (после обхода паники). **Точки монтирования не создаются.**
|
||||
|
||||
**СЛЕДУЮЩИЙ ШАГ (не завершён):** смонтировать datasets вручную в существующую/записываемую точку (корневая / readonly). Порядок:
|
||||
```bash
|
||||
zfs list -r RED_2TB # какие datasets есть (zfs list работает без mount)
|
||||
# смонтировать в существующую пустую папку, не создавая новую (или через tmpfs/rw-точку)
|
||||
# например:
|
||||
# mkdir -p /mnt/rec 2>/dev/null; (если /mnt rw — иначе выбрать rw-точку)
|
||||
# zfs set mountpoint=/mnt/rec RED_2TB (или mount -o)
|
||||
# затем выгружать данные на запасные диски rsync
|
||||
```
|
||||
|
||||
**Критичные ограничения (выяснены по ходу):**
|
||||
- `zpool import` требует **root** (`some devices require root privileges`) — truenas_admin НЕ root (sudo просит пароль). Все операции import/mount — под root. **На конец сессии это главный блокер** — без root не смонтировать/выгрузить.
|
||||
- Раньше при readonly-импорте в тредах было: datasets показываются но пути «not found», и полностью нечитаемы (permission denied) если данные повреждены. Здесь readonly-импорт прошёл чисто (no panic) — но монтирование ещё не доведено до конца.
|
||||
- **Данные на пуле важно выгрузить на другие диски** (пул восстановится только пересозданием — аппаратная метаданная ошибка). Это главный незавершённый шаг.
|
||||
|
||||
**🧪 ИТОГ ПО «ПОЧИНИТЬ ПУЛ» (2026-08-17, важно для будущих сессий):**
|
||||
- **In-place «починки» НЕТ.** По mav (лидер OS-команды iXsystems) в тредах: *"I don't know a way to recover from this situation without data offload and pool recreation"*. Паника на space map не лечится флагами.
|
||||
- **Опции это НЕ решают:** `zfs.zfs_recover=1`, `zfs.zil_replay_disable=1` (в GRUB), `rd.break=pre-mount`, `rd.break` — все НЕ помогли (паника осталась). Readonly-импорт («doesn't even read space maps») — единственное, что не паникует и даёт доступ к данным.
|
||||
- **`-F` (восстановление) уже показал панику** в этой сессии (`adding existent segment to range tree`). Повторный `-F` на повреждённом пуле рискован — может углубить повреждение. Не жать вслепую.
|
||||
- **`zpool attach RED_2TB <wd2tb2>` (идея зеркала на 2 WD2TB) НЕ выполнима в текущем состоянии**: attach — это write, он пишет в space maps (обновляет метаданные) → паника. Readonly-импорт не даст attach; переимпорт в rw вернёт панику. Также 2TB не влезет под 4.6T данных целиком. Идея зеркала валидна только ПОСЛЕ пересоздания пула из спасённых данных.
|
||||
- **Правильная дорога (единственная надёжная):** readonly-импорт → смонтировать datasets вручную → выгрузить данные на целевой пул (IronWolf 12TB) → пересоздать RED_2TB → вернуть данные. Попытки «починить rw» возможны, но только ПОСЛЕ спасения данных и на свой риск.
|
||||
- **Для «100% восстановления с правами»:** `rsync -aHAX` (права, владельцы, ACL, xattr, хардлинки) или `zfs send | zfs recv` (идеально байт-в-байт со снимками, но требует пула-приёмника и снимка).
|
||||
|
||||
> ⚠️ После успешного монтирования и выгрузки — обновить таблицу членов пула и закрыть этот блок.
|
||||
|
||||
### 🆕 ПРОГРЕСС (2026-08-18): datasets смонтированы под root, выгрузка идёт rsync — НЕ send|recv
|
||||
|
||||
**Смонтирование дочерних datasets — РАБОТАЕТ под root.** Это снимает блокер «datasets не смонтированы» из прошлой сессии:
|
||||
```bash
|
||||
mount -o remount,rw / # если корневая ФС readonly мешает создавать mountpoint-ы
|
||||
zfs mount -a # смонтировать все datasets
|
||||
# проверить:
|
||||
df -h /RED_2TB # должно показать ~4.6T, а НЕ 1.1T/362G родительского
|
||||
ls /RED_2TB/storage | head # должно быть не пусто (Cartoons, Downloads, Movies...)
|
||||
```
|
||||
После `zfs mount -a` в `mount` видны все дочерние datasets на `/RED_2TB/*` (все `ro` — readonly, для чтения rsync это норм).
|
||||
|
||||
**⚠️ СМОНТИРОВАТЬ datasets под `truenas_admin` НЕЛЬЗЯ** — `zfs mount -a` даёт `Insufficient privileges`. Монтирование и выгрузка — только **под root**.
|
||||
|
||||
**🐛 Причина «только 355G» на первой выгрузке rsync (разгадана):** первая попытка `rsync /RED_2TB/ /mnt/IRONWOLF/` запускалась, когда **дочерние datasets НЕ были смонтированы**, поэтому `/RED_2TB/storage` (3.24T), `/RED_2TB/backup` (287G) и т.д. были **пустыми mountpoint-дирами**. rsync скопировал только ~355G, лежащих прямо в родительском dataset `RED_2TB` (REFER 362G: `.DS_Store`, `dedupe_rm.sh`, `files.txt.xz`, `docker.bak`, `system`, `immich-photos-upload`). **rsync не сломался — ему просто нечего было копировать из не смонтированных дочерних datasets.** После монтирования данных стало ~4.6T — rsync перезапущен.
|
||||
|
||||
**❌ `zfs send | zfs recv` НЕ работает на повреждённом пуле — использовать rsync:** при `zfs send RED_2TB/storage | zfs recv DEST/storage` (под root) recv падает с `signal received` / `Bad file descriptor` / `IOT instruction (core dumped)`, exit 1. ZFS не может прочитать данные/метаданные из пула с повреждённой space map на лету при stream-чтении. **rsync — правильный и единственный надёжный способ** (переживает ошибки чтения отдельных файлов, exit 23, копирует остальное).
|
||||
|
||||
**⚠️ ЛОВУШКА «zfs send -n» (dry-run) НЕ подтверждает права send:** под `truenas_admin` `zfs send -n RED_2TB/docker` возвращал **exit 0 без ошибок** — это ОБМАНЧИВО. Реальный `zfs send` (без `-n`) даёт `warning: cannot send 'RED_2TB/docker': permission denied`. Дочерние datasets доступны только root (ACL root-only). Не доверять dry-run для проверки прав send.
|
||||
|
||||
**Команды выгрузки (под root):**
|
||||
```bash
|
||||
rsync -aHAX --info=progress2 /RED_2TB/ /mnt/IRONWOLF/ > /tmp/rsync2.log 2>&1 &
|
||||
# прогресс:
|
||||
while true; do clear; date +%H:%M:%S; du -sh /mnt/IRONWOLF/; tail -3 /tmp/rsync2.log; pgrep -a rsync >/dev/null && echo RUNNING || echo DONE; sleep 15; done
|
||||
```
|
||||
**Итог выгрузки:** после монтирования datasets и перезапуска rsync должны лечь все ~4.6T (storage, backup, Edu, Photos, TimeMachine/guest, old-bu, docker...). После завершения — сверка `du -sh /mnt/IRONWOLF/` vs `zfs list RED_2TB` и обновить таблицу членов пула.
|
||||
|
||||
**Опция добавить WD2TB#2 как зеркало к WD2TB#1** (`zpool attach RED_2TB <wd2tb2>`): валидна, но ТОЛЬКО после успешного импорта пула и его стабилизации. Не пытаться до восстановления.
|
||||
|
||||
### ✅ ПЕРЕСОЗДАНИЕ ПУЛА (2026-08-21) — ВЫПОЛНЕНО
|
||||
|
||||
**Решение (подтверждено Alex):** пересоздаём RED_2TB с **новой топологией — ВКЛЮЧАЕМ WD2TB#2 (sdf) зеркалом к WD2TB#1 (sdc)**. В итоге: `mirror {sdc, sdf}` + `mirror {sde, sdd}` — оба исходных simplex-члена получают зеркала (ранее WD2TB#1 был simplex без защиты).
|
||||
|
||||
**✅ СТАТУС (2026-08-21, live): пул СОЗДАН успешно.** `zpool create RED_2TB mirror /dev/sdc /dev/sdf mirror /dev/sde /dev/sdd` → `state: ONLINE, 0 0 0 ошибок, No known data errors`, `SIZE 5.44T, ALLOC 384K, HEALTH ONLINE`. Пул пустой (данные ещё возвращаются).
|
||||
|
||||
**Записи TrueNAS, которые важно знать (2026-08-21):**
|
||||
- `midclt call pool.query` → `id=1, name=RED_2TB, status=OFFLINE`, `topology:null`. Устаревшая запись в БД.
|
||||
- **`midclt call pool.delete 1` НЕ существует** в этом билде (`'PoolService' object has no attribute 'do_delete'`) — запись через API не удалить. Пользоваться командной строкой `zpool` (root) или UI.
|
||||
- `zpool labelclear -f` **принимает только ОДИН vdev за раз** — «too many arguments» при передаче нескольких дисков.
|
||||
|
||||
**Команды пересоздания (под root, на консоли TrueNAS):**
|
||||
```bash
|
||||
# 1. Стереть старые метки ZFS с ПАРТИЦИЙ (пул был построен на разделах *2, НЕ на целых дисках!)
|
||||
zpool labelclear -f /dev/sdc2
|
||||
zpool labelclear -f /dev/sdf2
|
||||
zpool labelclear -f /dev/sde2
|
||||
zpool labelclear -f /dev/sdd2
|
||||
|
||||
# 2. Проверить, что RED_2TB исчез из импортируемых
|
||||
zpool import -d /dev
|
||||
|
||||
# 3. Создать пул заново на ЦЕЛЫХ дисках (TrueNAS создаст свои разделы *2)
|
||||
zpool create RED_2TB mirror /dev/sdc /dev/sdf mirror /dev/sde /dev/sdd
|
||||
|
||||
# 4. Проверить
|
||||
zpool status RED_2TB
|
||||
zpool list RED_2TB
|
||||
```
|
||||
|
||||
**⚠️ КРИТИЧЕСКИЕ ЛОВУШКИ labelclear (из openzfs issues #18027, #3156, #14869):**
|
||||
- **Целиться надо в ПАРТИЦИИ (`*2`), а не в целый диск.** TrueNAS строит пулы на разделах `...2`. `zpool labelclear -f /dev/sdc` (целый диск) даёт `failed to clear label for /dev/sdc` — метки лежат внутри раздела `sdc2`, на целом диске их «не видит» целиком.
|
||||
- **`failed to clear label` также выводится, когда метки УЖЕ стёрты** (issue #18027) — не обязательно ошибка. Если после `labelclear` `zpool import -d /dev` не показывает RED_2TB — значит метки стёрты, всё ок.
|
||||
- `labelclear` сам по себе может не стереть оба набора меток (`#14869`), если чистить не ту цель — поэтому чистить по разделам, которые реально добавлялись.
|
||||
|
||||
**🧭 НОВАЯ ТОПОЛОГИЯ ПОСЛЕ ПЕРЕСОЗДАНИЯ:**
|
||||
| vdev | Члены | Назначение |
|
||||
|------|-------|-----------|
|
||||
| mirror-0 | sdc (WD2TB#1) + sdf (WD2TB#2) | Пара WD 2TB (зеркалирование) |
|
||||
| mirror-1 | sde (WD4TB) + sdd (Seagate4TB) | Пара 4TB (зеркалирование) |
|
||||
|
||||
**После создания пула — НЕ забыть:**
|
||||
- пересоздать datasets по [[red2tb-dataset-map]] (storage, backup, Photos, Edu, TimeMachine/guest, docker, old-bu, iocage; `.system`/`ix-apps` TrueNAS создаст сама);
|
||||
- решить судьбу данных ВНЕ датасетов (`system/`, `docker.bak/`, `immich-photos-upload/`, корневые файлы) — после пересоздания окажутся в корневом dataset;
|
||||
- вернуть данные: `rsync -aHAX /mnt/IRONWOLF/ /RED_2TB/`;
|
||||
- восстановить инфраструктуру (docker: caddy, transmission, HA, immich...), доступы, cron-бэкапы, Obsidian sync.
|
||||
|
||||
### ✅ LIVE-СТАТУС ПОСЛЕ ПЕРЕСОЗДАНИЯ (2026-08-24, проверка Китом)
|
||||
|
||||
**Пул УЖЕ зарегистрирован в TrueNAS и работает — перезагрузка/импорт НЕ нужны:**
|
||||
- `zpool status RED_2TB` → **ONLINE** (mirror-0 {sdc,sdf} + mirror-1 {sde,sdd}), ошибки `0 0 0`.
|
||||
- `midclt call pool.query` → `id=1, name=RED_2TB, status=ONLINE`, topology заполнена новой (оба mirror, GUIDs). БД TrueNAS привязала пул по GUID, запись обновлена под новую топологию.
|
||||
- Пул смонтирован (`/mnt/RED_2TB/`, `mounted=yes`), CAP 79% (5.44T, ALLOC 4.35T, FREE 1.09T).
|
||||
- **rsync возврата данных ЗАВЕРШЁН.** Вернулись все datasets: storage 3.29T, immich-photos-upload 353G, backup 287G, Edu 214G, Photos 146G, old-bu 65.2G, docker 2.92G, docker.bak 789M, system 112K. Корни IronWolf↔RED_2TB идентичны по ls.
|
||||
|
||||
**⚠️ НЕ ЗАКРЫТО: TimeMachine (~277G) НЕ вернулся.** Причина: на IronWolf `/mnt/IRONWOLF/TimeMachine/` существует (277G), но root-only NFSv4 ACL → `truenas_admin` НЕ может прочитать (`Permission denied`) → rsync его не докопировал. На RED_2TB датасет `TimeMachine` НЕ воссоздан (нет в `zfs list`, каталога нет). **TODO под root:** создать dataset `RED_2TB/TimeMachine` (+ дочерний `guest` как было) и `rsync -aHAX /mnt/IRONWOLF/TimeMachine/ /mnt/RED_2TB/TimeMachine/`. iocage-каталог восстановлен, но старые jails не нужны (всё в docker) — решено ранее.
|
||||
|
||||
### ⚠️⚠️ АКТИВНАЯ ПРОБЛЕМА №3 (2026-08-24): Docker/слой приложений НЕ поднят — контейнеры лежат
|
||||
|
||||
Пул с файлами работает, но **слой приложений (docker/TrueNAS Apps) НЕ восстановлен**. Проверка live (Кит):
|
||||
- `docker ps` → `Cannot connect to the Docker daemon`. `systemctl status docker` → `inactive (dead)`, **disabled**.
|
||||
- **`docker daemon.json` (`/etc/docker/daemon.json`):** `{"data-root": "/mnt/.ix-apps/docker", "exec-opts": ["native.cgroupdriver=cgroupfs"], "iptables": true, "storage-driver": "overlay2", "default-address-pools": [{"base": "172.17.0.0/12", "size": 24}]}` → это классическая схема TrueNAS Apps.
|
||||
- **Датасета `.ix-apps`/`ix-applications` НЕТ** в `zfs list` на пересозданном пуле → docker storage/образы/volumes (в старом пуле это был датасет `ix-apps`, docker 23.6G) **НЕ мигрировали** / потеряны.
|
||||
- **Конфиги ВСЕХ приложений на месте** в `/mnt/RED_2TB/docker/` (29 каталогов): arr, backups, caddy, cups, filebrowser, gitea, ha, hermes, homeassistant, immich, inpx-web, inpxer, library, mbusd, modbus-bridge, mosquitto, nodered, portainer, portainer-mcp, python, rclone, ser2net, syncthing, transmission, vless-proxy, watchtower, webdav, xray-admin, zigbee2mqtt.
|
||||
- `override.conf` (`/etc/systemd/system/docker.service.d/override.conf`): только `ExecStartPost=iptables -P FORWARD ACCEPT && ip6tables -P FORWARD ACCEPT` — применяется при старте docker.
|
||||
|
||||
**Вывод:** `/mnt/RED_2TB/docker/` — это конфиги; docker-образы (layers) не сохранились → контейнеры надо пересоздавать с перекачкой образов.
|
||||
|
||||
**ПЛАН ВОЗВРАТА КОНФИГА В СТРОЙ (4 шага, пока НЕ выполнен):**
|
||||
1. **WebUI TrueNAS → Apps → Settings → Choose Pool → RED_2TB.** TrueNAS сама создаст датасет приложений (ним `ix-applications`), примонтирует docker storage в `/mnt/ix-applications` (data-root `.ix-apps/docker`), поднимет `docker.service`. *(`docker` сейчас disabled — старт произойдёт именно через настройку Apps, не вручную.)*
|
||||
2. Конфиги приложений уже лежат в `/mnt/RED_2TB/docker/<app>` — трогать не надо.
|
||||
3. **Пересоздать каждый контейнер** (WebUI Apps нативный/Custom App) с **bind-mount** `/mnt/RED_2TB/docker/<app>` → внутрь контейнера. Образы перекачаются при старте, контейнер подхватит свой существующий конфиг.
|
||||
4. Разовое: `override.conf` (iptables FORWARD) применится сам при старте docker; порты/сеть прежние; данные приложений (immich library, transmission downloads и т.д.) уже в `/mnt/RED_2TB/`.
|
||||
|
||||
**⚠️ Перезагрузка НЕ поможет** поднять контейнеры: docker `disabled` + пул приложений не настроен. Перезагрузка полезна только ПОСЛЕ шага 1.
|
||||
**⚠️ Вопрос к Alex:** docker storage `.ix-apps` (образы, ~23.6G) точно НЕ переносили на IronWolf? Если перенесли — указать куда, вернуть и настройка упростится (образы сохранятся). Если нет — только перекачка.
|
||||
|
||||
## ⚠️ НЕ ВХОДИТЬ В RW-ИМПОРТ ПОВРЕЖДЁННоГО ПУЛА
|
||||
**Импорт RED_2TB в не-readonly режиме (`zpool import` без `-o readonly=on`) — ВСЕГДА даёт kernel panic** (`zfs: adding existent segment to range tree`). Это правило подтверждено много раз. При пересоздании пул НЕ импортировать — только стереть метки (`labelclear`) и создать заново. `zpool import -d /dev` (dry-list) безопасен, но не запускает пул.
|
||||
|
||||
|
||||
|
||||
>>>>>>> origin/main
|
||||
- Идёт регулярный scrub (запускается ночью воскресенья).
|
||||
- **`zpool` не в PATH для zsh truenas_admin** — вызывать через абсолютный путь `/sbin/zpool` или `/usr/sbin/zpool` (иначе `command not found`).
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Vault Git Sync — Architecture & Scripts
|
||||
updated: '2026-06-20'
|
||||
updated: '2026-09-02'
|
||||
type: tech
|
||||
tags:
|
||||
- vault
|
||||
@@ -12,6 +12,12 @@ tags:
|
||||
|
||||
# Vault Git Sync
|
||||
|
||||
> **STATE 2026-09-02 (позднее обновление):** Eagle/bare repo снова **синхронны** (ahead=0/behind=0, `2fab879`). Ранее (см. ниже) git-sync стоял из-за битых прав `storage/git` — **починено** полной dacl-заменой (`family/documents/vault-sync/2026-09-02-restore-privilege-scope.md` §RESOLVED).
|
||||
>
|
||||
> **⛔ НОВАЯ проблема 2026-09-02 (не решена):** оба **Taiga-клиента** (`/storage/obsidian` и `/storage/obsidian-syncthing`) **отстали на месяц** — HEAD `ceea848` (2026-08-01) vs bare repo `2fab879` (2026-09-02). Причина: контейнер `hermes-taiga` в **crash-loop** (16339 рестартов) — `uv run hermes gateway run` не может докачать депы (pytz/markdown-it-py) с PyPI, т.к. весь HTTP идёт через **мёртвый `socks5://vless-proxy:1080`**, а `UV_CACHE_DIR=/tmp/uv-cache` пустеет на каждом рестарте. Taiga 3-phase sync (крон внутри агента) не выполняется => телефон видит устаревший vault. Подробно: `family/documents/vault-sync/2026-09-02-hermes-taiga-crashloop.md`. Фикс НЕ применён (ждёт Alex).
|
||||
|
||||
> **Триггер cron на маке (Eagle) — это launchd, НЕ Hermes cron:** `~/Library/LaunchAgents/com.sync-vault.plist` → `/Users/admin/scripts/sync-vault.sh`, `StartInterval=300` (5 мин). Скрипт `sync-vault-lib.sh` намеренно глушит dead remote (`git fetch` fail → `exit 0`), поэтому launchd показывает `last exit code = 0` даже при фактически стоящем sync. Системный crontab на маке пуст.
|
||||
|
||||
Obsidian vault is a bare git repo on TrueNAS:
|
||||
`/mnt/RED_2TB/storage/git/obsidian-vault.git`
|
||||
Also mirrored in Gitea: `https://git.mallexxx.duckdns.org/git_admin/obsidian-vault`
|
||||
@@ -50,10 +56,16 @@ No stash. No GIT_DIR/GIT_WORK_TREE workarounds.
|
||||
|
||||
| Host | Script | Type | Trigger |
|
||||
|--------|-------------------------------|---------------|----------------------|
|
||||
| Eagle | `~/scripts/sync-vault.sh` | full clone | Hermes cron */5 |
|
||||
| Eagle | `~/scripts/sync-vault.sh` | full clone | **launchd** `com.sync-vault` (⚠️ НЕ Hermes cron) `StartInterval=300` |
|
||||
| Kraken | `~/scripts/sync-vault.sh` | sparse clone | host crontab */5 |
|
||||
| Taiga | `/opt/data/sync-vault.sh` | 3-phase orch. | Hermes cron */5 |
|
||||
|
||||
> **⭐ УТОЧНЕНО 2026-09-02 (Eagle/мак sync-механизм):** автосинка на маке запускается **НЕ Hermes cron, а launchd-агентом** `~/Library/LaunchAgents/com.sync-vault.plist`:
|
||||
> - Программа: `/Users/admin/scripts/sync-vault.sh`, `StartInterval = 300` сек (5 мин)
|
||||
> - `launchctl list` → активен, `runs = 3762`, `last exit code = 0`
|
||||
> - ⚠️ **`sync-vault-lib.sh` умышленно глушит недоступность remote**: если `git fetch` падает → логирует `Fetch failed (...)` и `exit 0`. Поэтому launchd показывает `exit code 0`, даже когда sync фактически сломан (см. случай ahead 55 при сломанном bare repo после restore). Это **не** отсутствие cron и не сбой — диагностировать нужно по `git status` (ahead count), а не по exit-code агента.
|
||||
> - Системный crontab и `/etc/crontab` на маке отсутствуют.
|
||||
|
||||
All clients share a common library: `sync-vault-lib.sh` (same dir as sync-vault.sh).
|
||||
Source of truth for scripts: `~/Developer/vault-sync-test/scripts/` on Eagle.
|
||||
|
||||
@@ -121,6 +133,7 @@ cd ~/Developer/vault-sync-test && bash test-sync.sh
|
||||
- `git add -A` in sparse worktree still stages deletions of out-of-cone files tracked in index — need to unstage them (fixed in old script; irrelevant with proper clone)
|
||||
- `core.quotePath=true` (default) escapes Cyrillic paths in `git ls-files` output — use `-c core.quotePath=false`
|
||||
- ZFS on TrueNAS blocks `chmod` — `git init` fails from host; must run from inside Docker container or create `.git` structure manually
|
||||
- **NFS4 `owner@ DENY READ_DATA` ACL breaks push (fake "corrupt" objects)** — see History 2026-09-02. Key: after a TrueNAS **pool restore**, a subset of loose git objects in the bare repo can carry an inverted NFS4 ACL `owner@ type=DENY READ_DATA=True`. In NFSv4 a DENY overlays ALLOW, so the owning uid (e.g. 950) can't mmap-read those objects → on receive, `git-receive-pack`/`index-pack` reports `loose object ... is corrupt` and rejects push, even though data is intact (`git fsck --full` under root is clean). Fix = `filesystem.setacl <repo> ... {stripacl:true}` (chmod/chown do NOT remove DENY ACEs). Tell-tale: POSIX file mode `40` (`r--------`) on loose objects vs normal `750`.
|
||||
|
||||
## History
|
||||
|
||||
|
||||
@@ -1,20 +1,30 @@
|
||||
---
|
||||
title: VPS qentra.top
|
||||
created: '2026-05-24'
|
||||
updated: '2026-05-27'
|
||||
updated: '2026-09-01'
|
||||
type: tech
|
||||
namespace: personal
|
||||
tags: [infra, vps]
|
||||
confidence: medium
|
||||
status: retired
|
||||
related:
|
||||
- "[[tech/xray-reverse-tunnel-kraken-truenas]]"
|
||||
- "[[tech/kraken-network]]"
|
||||
- "[[tech/wireguard-vpn]]"
|
||||
---
|
||||
|
||||
# VPS qentra.top
|
||||
|
||||
**IP:** 91.207.28.205
|
||||
**Stack:** nginx + Python 3.11, Cloudflare proxy
|
||||
> ## ⛔ УДАЛЁН на 2026-09-01
|
||||
> **VPS `91.207.28.205` (qentra.top) больше НЕ существует.** Вся инфраструктура на нём (nginx, Xray/VLESS+REALITY, x-ui panel, OpenVPN, WebSocket v.qentra.top, backup-скрипты, nolvu/panel vhosts) — утрачена вместе с сервером.
|
||||
> **Следствия:**
|
||||
> - На TrueNAS контейнер `vless-proxy` (teddysun/xray) outbound указывает на `v.qentra.top:443` → **сейчас мёртв**. Hermes-Taiga (SOCKS5 через `vless-proxy:1080`) **без рабочего прокси**.
|
||||
> - WireGuard Eagle↔VPS↔Kraken: VPS-звено мёртво.
|
||||
> - Rasputin-роутер VLESS-туннель (`188.239.191.235` / node3.sysnx.net) — это ДРУГОЙ сервер (не qentra), не трогать.
|
||||
> - Замена для выхода клиентов сети TrueNAS → Kraken: см. **[[tech/xray-reverse-tunnel-kraken-truenas]]** (Xray reverse, ЧАСТИЧНО внедрён: 3x-ui на TrueNAS развёрнут 2026-09-01, reverse-клиент на Kraken ещё нет).
|
||||
|
||||
**IP:** 91.207.28.205 *(недоступен с 2026-09-01)*
|
||||
**Stack:** nginx + Python 3.11, Cloudflare proxy *(исторические данные ниже)*
|
||||
**Panels:** https://panel.qentra.top (x-ui, проксируется nginx на 8443 → 5430), v.qentra.top:8964
|
||||
|
||||
## Subdomain Setup
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
# WireGuard VPN — Eagle ↔ Kraken
|
||||
|
||||
> Создано: 2026-05-14
|
||||
> Статус: ✅ работает
|
||||
> Статус: ⚠️ **СЛОМАНО на 2026-09-01** — VPS-узло (10.99.0.1/10.99.1.1) **удалён** вместе с qentra.top.
|
||||
> Вся hub-and-spoke топология (wg-quick@wg0/wg1, SNAT, dnsmasq-резолвинг `kraken`, nftables forward) жила на VPS и **утрачена**. `ssh kraken` с Eagle извне через WG больше не работает.
|
||||
> Альтернатива для внешнего доступа к Kraken на 2026-09-01: reverse-SSH туннель через VPS-заменитель не существует; локально дома — напрямую по LAN 192.168.1.15 (см. [[kraken-access]]). План замены сети: [[tech/xray-reverse-tunnel-kraken-truenas]].
|
||||
> ⚠️ **Дома Eagle подключается к Kraken напрямую по LAN** (wg-auto.sh детектит домашний роутер и делает `wg-quick down`) — это направление работает. Проблема только во внешнем (не-дома) подключении.
|
||||
|
||||
## Топология
|
||||
|
||||
@@ -10,6 +13,8 @@ Eagle (10.99.0.2) ←→ wg0 VPS (10.99.0.1) ←→ wg1 VPS (10.99.1.1) ←→ K
|
||||
:51820 :51821
|
||||
```
|
||||
|
||||
> ⚠️ Топология выше — ИСТОРИЧЕСКАЯ, VPS-звено мертво.
|
||||
|
||||
Два интерфейса на VPS чтобы избежать hairpin forwarding. FORWARD идёт wg0→wg1, SNAT меняет src Eagle на `10.99.1.1`.
|
||||
|
||||
---
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
---
|
||||
status: implemented
|
||||
tags:
|
||||
- family
|
||||
- homeautomation
|
||||
- zont
|
||||
- modbus
|
||||
title: Защита modbus-bridge от гонки с udev (ZONT датчики)
|
||||
updated: '2026-08-25'
|
||||
---
|
||||
# Защита modbus-bridge/mbusd от гонки с udev (ZONT датчики)
|
||||
|
||||
> Статус: **внедрено** (2026-08-25, шаги 1–3). Датчики в ZONT снова отвечают, скрипт и init script на месте.
|
||||
|
||||
## Проблема
|
||||
ZONT (192.168.0.10) — Modbus master на RS-485 шине `ttyZONT`. 485-датчики: Dining=1, Kids=2, Bedroom=3.
|
||||
Контейнер `modbus-bridge` сниффит их и подставляет виртуальные slaves 101/102/103 → ZONT опрашивает как внешние датчики. Если modbus-bridge не слушает шину → **ZONT показывает датчики «недоступными»**.
|
||||
|
||||
**Первопричина (2026-08-25):** гонка загрузки TrueNAS — docker стартовал раньше udev, `/dev/ttyZONT` и `/dev/ttyVent` ещё не существовали → контейнеры `modbus-bridge` (Exit 128) и `mbusd` (Exit 255) упали на старте:
|
||||
`error gathering device information while adding custom device "/dev/ttyZONT": no such file or directory` (RestartCount=0).
|
||||
Фикс был: ручной `docker start modbus-bridge mbusd`.
|
||||
|
||||
## Почему контейнеры сами НЕ поднялись (RestartCount=0)
|
||||
`restart: unless-stopped`/`always` ретраит в ДВУХ случаях:
|
||||
1. Процесс контейнера **стартовал и завершился** с ненулевым кодом → демон ретраит с backoff.
|
||||
2. **Перезапуск docker daemon** → демон пробует поднять `unless-stopped`/`always` контейнеры.
|
||||
|
||||
Наш случай — ТРЕТИЙ, особый: контейнер **вообще не стартовал** — ошибка на этапе монтирования устройства.
|
||||
- Нет процесса, который «завершился бы» → **restart policy не на что применять** → `RestartCount=0`, демон не ретраит.
|
||||
- После падения (13:24) демон не перезапускался → второго триггера не было.
|
||||
**Вывод:** отказ на этапе mount устройства НЕ перезапускается restart policy. Авто-подъём гарантирован только скриптом, ждущим устройства.
|
||||
|
||||
## Ключевое ограничение (задержка в entrypoint НЕ помогает)
|
||||
У обоих контейнеров устройство проброшено через `devices: /dev/ttyZONT:/dev/ttyUSB0` / `devices: /dev/ttyVent:/dev/ttyUSB0`.
|
||||
**Docker при `start` монтирует устройство ДО запуска процесса** — если `<src>` отсутствует на момент старта, контейнер вообще не стартует, и `sleep` внутри entrypoint/CMD **не выполняется**. Поэтому решение — на уровне init скрипта.
|
||||
|
||||
## Внедрённое решение
|
||||
|
||||
### 1. Скрипт `/mnt/RED_2TB/system/start-modbus.sh` (root, `-rw-r--r--`)
|
||||
Ожидает появления tty-алиасов от udev (до ~50с), затем запускает контейнеры:
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Ждём tty-алиасы от udev (макс ~25с), затем стартуем modbus контейнеры.
|
||||
for i in $(seq 1 50); do
|
||||
[ -e /dev/ttyZONT ] && [ -e /dev/ttyVent ] && break
|
||||
sleep 1
|
||||
done
|
||||
sleep 2
|
||||
docker start modbus-bridge mbusd 2>/dev/null
|
||||
```
|
||||
|
||||
### 2. Init script (TrueNAS, id=3)
|
||||
- **when:** POSTINIT, **type:** COMMAND, **timeout:** 30, **enabled:** true
|
||||
- **command:** `bash /mnt/RED_2TB/system/start-modbus.sh`
|
||||
- **comment:** `Start modbus-bridge/mbusd after udev tty aliases`
|
||||
|
||||
### Порядок POSTINIT скриптов
|
||||
| id | command | comment | enabled |
|
||||
|----|---------|---------|---------|
|
||||
| 1 | `cp .../99-tty-alias.rules /etc/udev/rules.d/ && udevadm control --reload-rules && udevadm trigger` | Map ttyUSB | ✅ |
|
||||
| 2 | `bash /mnt/RED_2TB/system/tunnel.sh &` | — | ✅ |
|
||||
| 3 | `bash /mnt/RED_2TB/system/start-modbus.sh` | Start modbus-bridge/mbusd after udev tty aliases | ✅ |
|
||||
|
||||
## Проверка
|
||||
- `/dev/ttyZONT` → `ttyUSB1` (CH340), `/dev/ttyVent` → `ttyUSB0` — симлинки появляются после POSTINIT id=1.
|
||||
- После reboot: `docker ps` — modbus-bridge и mbusd Up; датчики в ZONT отвечают.
|
||||
- Просмотр init scripts: `midclt call initshutdownscript.query`
|
||||
- Откат: `midclt call initshutdownscript.delete <ID>` + удалить скрипт с диска.
|
||||
|
||||
## Связанные заметки
|
||||
- [[family/how-to/home-automation.md]] — карта slave ID, ZONT, датчики
|
||||
- [[family/how-to/truenas-infrastructure.md]] — docker, modbus-bridge, mbusd, udev rules, init scripts
|
||||
@@ -0,0 +1,281 @@
|
||||
# Reverse Xray (3x-ui) — TrueNAS ↔ Kraken
|
||||
|
||||
> Создано: 2026-09-01. Цель: проксировать трафик локальных клиентов (сеть TrueNAS 192.168.2.x) через TrueNAS → Kraken → интернет. **Kraken = точка выхода (exit node).** TrueNAS = bridge/контроллер.
|
||||
|
||||
## Архитектура
|
||||
|
||||
```text
|
||||
ЛОКАЛЬНЫЕ КЛИЕНТЫ (192.168.2.x)
|
||||
│ подключаются к прокси TrueNAS:1080/1081 (SOCKS/HTTP) ИЛИ на поддомен
|
||||
▼
|
||||
TRUENAS = 3x-ui (Xray-сервер, bridge/контроллер) — белый IP, mallexxx.duckdns.org
|
||||
│ принимает клиентский трафик; reverse-канал к Kraken
|
||||
▼ ▲
|
||||
KRAKEN = Xray-клиент (outbound reverse) + exit node — держит исходящий канал к TrueNAS
|
||||
▼
|
||||
интернет
|
||||
```
|
||||
|
||||
- **TrueNAS** (3x-ui): принимает от локальных клиентов + держит reverse-вход, куда подключается Kraken.
|
||||
- **Kraken**: сам **инициирует** канал к TrueNAS (за NAT, не может принимать), получает по нему трафик клиентов, отпускает в интернет.
|
||||
- Кра́кен за NAT ⇒ направление канала **от Kraken к TrueNAS** (Xray reverse).
|
||||
|
||||
## Ключевые факты (прояснены)
|
||||
|
||||
1. **На 443 у TrueNAS — Caddy** (reverso-proxy, валидные LE-серты), НЕ Xray REALITY. Хостовый маппинг: `0.0.0.0:8443→443` (контейнер), `2019` (admin), `8088→80`.
|
||||
2. **Xray на TrueNAS** раньше был задуман как 3x-ui:
|
||||
- База `/mnt/RED_2TB/docker/xray-admin/x-ui.db` (3x-ui), inbound `vless-ws` port `10095`, tag `in-10095-tcp`, path `/vless`, host `vpn.mallexxx.duckdns.org`, protocol vless.
|
||||
- Композ-файла в `xray-admin/` нет; контейнер НЕ запущен.
|
||||
3. **Caddyfile** уже проксирует (мёртвые ссылки на `xray-admin`):
|
||||
- `vpn.mallexxx.duckdns.org` → `@ws path /vless` → `xray-admin:10095`
|
||||
- `vpn-panel.mallexxx.duckdns.org` → `xray-admin:443` / `xray-admin:2053` (path /sub/*)
|
||||
- Сертификаты для этих поддоменов уже выданы (DNS на TrueNAS IP).
|
||||
4. **`vless-proxy`** (teddysun/xray) на TrueNAS — КЛИЕНТ: слушает 1080/1081 (SOCKS/HTTP), outbound на мёртвый `v.qentra.top:443` (VPS удалён). Используется Hermes-Taiga.
|
||||
5. **VPS qentra.top (91.207.28.205) УДАЛЁН.** Вся старая VLESS+REALITY инфраструктура на нём недоступна.
|
||||
6. Открытые порты TrueNAS наружу: **22, 443** (8443 ведёт внутрь контейнера Caddy:443 → но Caddy обрабатывает HTTPS-домены).
|
||||
|
||||
## Образ 3x-ui
|
||||
|
||||
- Официальный: `ghcr.io/mhsanaei/3x-ui:latest`
|
||||
- Контейнер должен называться **`xray-admin`** (как в Caddyfile) и быть в сети **`caddy_default`** (чтобы Caddy резолвил имя).
|
||||
- Volume: `/mnt/RED_2TB/docker/xray-admin:/etc/x-ui` (там лежит готовая `x-ui.db`).
|
||||
- Порт панели: 54321 (web UI, через Caddy поддомен `vpn-panel.mallexxx.duckdns.org`).
|
||||
- VLESS inbound 10095 принимается извне через Caddy `vpn.mallexxx.duckdns.org/vless` (WS), НО для reverse к Kraken нужен подход через панель.
|
||||
|
||||
## Композ-файл
|
||||
|
||||
Файл: `/mnt/RED_2TB/docker/xray-admin/docker-compose.yml`
|
||||
|
||||
```yaml
|
||||
services:
|
||||
xray-admin:
|
||||
image: ghcr.io/mhsanaei/3x-ui:latest
|
||||
container_name: xray-admin
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- /mnt/RED_2TB/docker/xray-admin:/etc/x-ui
|
||||
environment:
|
||||
- XRAY_VMESS_AEAD_FORCED=false
|
||||
networks:
|
||||
- caddy_default
|
||||
ports:
|
||||
- "54321:54321" # 3x-ui панель (web UI)
|
||||
|
||||
networks:
|
||||
caddy_default:
|
||||
external: true
|
||||
```
|
||||
|
||||
⚠️ ПОРТЫ 10095 и 2053/443 НЕ пробрасывать на host отдельно — Caddy стоит перед 443 и маршрутизирует /vless → xray-admin:10095 по имени в общей сети. Если нужно наружу снаружи (не через Caddy), проброс отдельный — обсудить.
|
||||
|
||||
## Сеть: reverse к Kraken
|
||||
|
||||
`xray-admin` должен быть в сети `caddy_default` — там же Caddy. Проверено: caddy_default содержит caddy, syncthing, webdav, gitea.
|
||||
|
||||
## Reverse-схема (Xray portal/bridge) — 2026-09-01, спроектировано
|
||||
|
||||
Целевое: локальные клиенты сети TrueNAS (192.168.2.x) выходят в интернет через Kraken.
|
||||
|
||||
Роли Xray reverse (по эталону Xray-examples/ReverseProxy):
|
||||
- **Kraken = BRIDGE** (reverse bridges) — держит исходящий канал к TrueNAS, публикует "интернет-выход" (freedom).
|
||||
- **TrueNAS = PORTAL** (reverse portals) — принимает от локальных клиентов (external-inbound) и пересылает в Kraken по reverse-каналу (interconn).
|
||||
|
||||
Конкретные порты/транспорт:
|
||||
| Компонент | Хост | Контейнер/роль | Транспорт | Вход/выход |
|
||||
|---|---|---|---|---|
|
||||
| portal | TrueNAS | `xray-reverse-portal` | VLESS-WS | interconn `:12346` → Caddy path `/rvs`; external `:12345` для клиентов сети |
|
||||
| bridge | Kraken | `xray-reverse-bridge` | VLESS-WS | interconn → `vpn.mallexxx.duckdns.org` path `/rvs`; свобода → интернет |
|
||||
|
||||
Транспорт: VLESS + WebSocket (т.к. снаружи TrueNAS только 443 через Caddy; WS подходит для reverse поверх outbound). Отдельный путь Caddy `/rvs` (не `/vless` 3x-ui) → `xray-reverse-portal:12346`, чтобы не смешивать с inbound 3x-ui.
|
||||
|
||||
Caddy правка: `vpn.mallexxx.duckdns.org` добавить маршрут `@rvs path /rvs` → `reverse_proxy @rvs xray-reverse-portal:12346`.
|
||||
|
||||
## Статус деплоя (2026-09-01)
|
||||
|
||||
✅ **3x-ui развёрнут на TrueNAS и работает:**
|
||||
- Контейнер `xray-admin` (ghcr.io/mhsanaei/3x-ui:latest, **3.7.0**, Xray 26.7.28) в сети `caddy_default`, volume `/mnt/RED_2TB/docker/xray-admin:/etc/x-ui`.
|
||||
- Панель web UI: **`https://vpn-panel.mallexxx.duckdns.org/` → HTTP 200** (Caddy резолвит `xray-admin:2053`).
|
||||
- Sub-сервер: `[::]:443` (путь /sub), панель `[::]:2053` — как в Caddyfile.
|
||||
- Inbound: `vless-ws` port **10095**, tag `in-10095-tcp`, path `/vless`, host `vpn.mallexxx.duckdns.org` (Caddy path /vless → xray-admin:10095).
|
||||
- 3x-ui **поддерживает reverse** (в бинарнике `clientReverseTags`) — настройка через панель.
|
||||
- Бэкап: `/mnt/RED_2TB/docker/backups/reverse-xray-3xui-20260901-113625/` (Caddyfile + x-ui.db + docker-inventory).
|
||||
|
||||
### Фактически развёрнутый compose (deployed на TrueNAS)
|
||||
```yaml
|
||||
services:
|
||||
xray-admin:
|
||||
image: ghcr.io/mhsanaei/3x-ui:latest
|
||||
container_name: xray-admin
|
||||
hostname: xray-admin
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- TZ=Asia/Novosibirsk
|
||||
- PUID=950
|
||||
- PGID=950
|
||||
volumes:
|
||||
- /mnt/RED_2TB/docker/xray-admin:/etc/x-ui
|
||||
ports:
|
||||
- "54321:54321" # 3x-ui web UI (внутри панель реально на 2053)
|
||||
networks:
|
||||
- caddy_default
|
||||
networks:
|
||||
caddy_default:
|
||||
external: true
|
||||
```
|
||||
> Черновик выше (секция «Композ-файл») — предварительный; фактический файл на TrueNAS содержит `hostname`, `TZ`, `PUID/PGID`. Панель внутри слушает **2053** (не 54321) — это то, что Caddyfile проксирует через `vpn-panel`. Хостовый 54321-проброс не используется панелью (панель = 2053), можно убрать.
|
||||
|
||||
**Следующий шаг:** ✅ Выполнено — reverse развёрнут (см. ниже). Основной doc архитектуры: `personal/tech/xray-reverse-tunnel-kraken-truenas.md`.
|
||||
|
||||
## Reverse деплой — ПОЛНЫЙ СТАТУС (2026-09-01) — РЕШЕН переезд на TCP+REALITY
|
||||
|
||||
### 🔀 РЕШЕНИЕ: WS → прямой TCP+REALITY (принято в сессии 2026-09-01)
|
||||
WS-вариант reverse НЕ пропускал payload (curl через SOCKS → 000; portal логировал `accepted tcp:... [local -> reverse-out]`, но bridge не получал). Официальный Xray-reverse пример = прямой TCP + flow `xtls-rprx-vision`. Alex согласовал проброс порта → переводим reverse канал Kraken↔TrueNAS на **прямой TCP+REALITY** порт 12346.
|
||||
|
||||
**REALITY-ключи (для interconn :12346):** server PrivateKey `0JTjeirfviDqCr63wSnisvU7DV6SpR9_9V2l_EUHmkk`; server PublicKey (для bridge) `GhsphQLT_0fwOvK45MHeAgG3sBQsFtw7lQfUIbrLMQU`; shortId `1451ef281caf5905`; serverName/SNI `www.cloudflare.com`; flow `xtls-rprx-vision`.
|
||||
|
||||
**⚠️ Pitfall Xray 26.x:** VLESS без TLS/шифрования к публичному адресу ЗАПРЕЩЁН (`vless without TLS or other encryption is prohibited unless the server address is a private IP`). → bridge TCP-VLESS обязателен с REALITY.
|
||||
|
||||
Обновлённые конфиги (оба `Configuration OK` при `xray run -test`):
|
||||
- **portal** `/mnt/RED_2TB/docker/reverse-portal/config.json`: interconn `:12346` VLESS-TCP reality (dest www.cloudflare.com:443, client a81c3179..., flow xtls-rprx-vision, reverse tag reverse-out); local `:12345` SOCKS; routing local→reverse-out.
|
||||
- **bridge** `/home/kraken/xray-reverse/config.json`: outbound `conn` VLESS simplified → mallexxx.duckdns.org:12346, flow, reality (publicKey=server PublicKey, shortId, serverName www.cloudflare.com, fingerprint random), reverse tag reverse-in; direct=freedom; routing reverse-in→direct.
|
||||
- **compose portal**: добавлен проброс `- "12346:12346"`.
|
||||
|
||||
### Доступ к роутеру OpenWrt (TrueNAS сети) — из `truenas-access`
|
||||
- OpenWrt = main router сети 192.168.2.0/24, SSH `root@192.168.2.2`, пароль root **`1316261`**. Доступ с TrueNAS через docker+sshpass.
|
||||
- ✅ Бэкап firewall OpenWrt: `/mnt/RED_2TB/docker/backups/openwrt-firewall-20260901-130558.txt` (212 строк).
|
||||
- Порт-форвардинг: `uci add firewall redirect` ... `src_dport` → `dest_ip=192.168.2.197` `dest_port` `target=DNAT`; `/etc/init.d/firewall reload`.
|
||||
|
||||
### ✅ ВНЕДРЕНО (2026-09-01, после согласия Alex) — TCP+REALITY переход выполнен
|
||||
Все 4 шага перехода на TCP+REALITY **ВЫПОЛНЕНЫ**:
|
||||
1. ✅ Пересоздан `xray-reverse-portal` на TrueNAS (compose `12345:12345` + `12346:12346`, config REALITY TCP). Проверено: `ss -tlnp` → `0.0.0.0:12346 LISTEN`.
|
||||
2. ✅ OpenWrt DNAT добавлен: redirect `xray-reverse-12346`, `src_dport=12346` → `dest_ip=192.168.2.197:12346`, `target=DNAT`, `/etc/init.d/firewall reload` → `DNAT_ADDED`. Проверено: `mallexxx.duckdns.org:12346` → **OPEN** извне.
|
||||
3. ✅ Пересоздан `xray-reverse-bridge` на Kraken (config REALITY TCP). Reverse-канал снова ESTABLISHED: Kraken `172.24.0.2 → 90.189.160.148:12346 ESTABLISHED` + лог `common/mux: received request for udp:reverse:0`.
|
||||
4. ❌ **Тест payload НЕ прошёл даже на TCP+REALITY**: `curl --socks5 127.0.0.1:12345 http://api.ipify.org` на TrueNAS → **всё ещё `code=000`** (прямой curl → 200). Portal: `accepted tcp:8.6.112.0:80 [local -> reverse-out]`, но bridge НЕ логирует приход TCP-payload (`no accepted/received` в `reverse-in`).
|
||||
|
||||
### ❌ Дополнительно пробовано: снятие `flow: xtls-rprx-vision`
|
||||
- Убрал `flow: xtls-rprx-vision` с обеих сторон (portal interconn client + bridge conn outbound), пересоздал оба контейнера (оба `Configuration OK`).
|
||||
- Результат: **по-прежнему `code=000`**. Reverse-канал устанавливается (`udp:reverse:0`), TCP-payload до bridge не доходит.
|
||||
- **Вывод: проблема НЕ в `flow` и НЕ в WS-транспорте — даже на «каноничном» TCP+REALITY payload между portal-reverse-out и bridge-reverse-in не передаётся.** Ранее выдвинутая гипотеза (WS не пропускает reverse-payload) **опровергнута** переходом на TCP.
|
||||
|
||||
### 🔑 КОРЕНЬ ПРОБЛЕМЫ НАЙДЕН (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+** у outbound `freedom`/`direct` дефолтная политика безопасности **блокирует VLESS Reverse payload**, пока не задан явный `finalRules`. Reverse-канал при этом живёт — «выглядит подключено», но payload молча дропается.
|
||||
**Фикс (bridge, место egress reverse-in→интернет):**
|
||||
```json
|
||||
{ "protocol": "freedom", "tag": "direct",
|
||||
"settings": { "domainStrategy": "AsIs", "finalRules": [ { "action": "allow" } ] } }
|
||||
```
|
||||
**Ссылки:** #6612 (фикс), #6027 (корень — finalRules у Direct), docs freedom, 3x-ui #4782, #2664 (flow vision на bridge+REALITY), #6242/#6195/#6248 (регресс роутинга reverse v26.5+, кварк = пин v26.4.25).
|
||||
**Проверено из поиска:** placeholder-freedom на portal нужен (есть); routing `reverse-in→direct` на bridge нужен (есть); у VLESS outbound поле `encryption` обязательно `"none"` (есть).
|
||||
|
||||
### ✅ ФИКС ПРИМЕНЁН, но заблокирован (2026-09-01)
|
||||
Новый bridge-конфиг с `finalRules:[{action:"allow"}]` в `direct` **залит** на Kraken (`/home/kraken/xray-reverse/config.json`, 1098 байт). **НО 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-...`, ранее в доке фигурировал `6194539b...` (sda1 1.8T). Сейчас `sda`=0B без раздела.
|
||||
- **`docker compose down/up` для bridge не выполнен** — контейнер всё ещё со старым конфигом.
|
||||
**Шаг продолжения (нужно подтверждение Alex):** починить HDD/docker на Kraken (reboot или физ. переподключение USB), `cd /home/kraken/xray-reverse && docker compose up -d`, тест `curl --socks5 127.0.0.1:12345 http://api.ipify.org` на TrueNAS → ожидаем IP Kraken.
|
||||
|
||||
**Статус: задание НЕ завершено — остаётся применить bridge-фикс после восстановления docker на Kraken.**
|
||||
|
||||
### ⚠️ Kraken status — диск/докер были нестабильны
|
||||
- Несколько `System is booting up` (pam_nologin) — Kraken перезагружался из-за USB-диска в цикле enumeration (`device descriptor read/64 error -110`, `device not accepting address error -62`, `[sda] Read Capacity(10) failed`, `0 B`).
|
||||
- Итог: диск появился, Docker `active`, **30 образов целы, 0 контейнеров** (контейнеры потеряны, data-root на HDD).
|
||||
- Docker Root Dir Kraken: `/srv/dev-disk-by-uuid-6194539b-.../docker-data` (UUID **6194539b**, не 49e8f586).
|
||||
- Прямой интернет Kraken работает (api.ipify → 92.62.70.41). Контейнеры Kraken (jellyfin/transmission/radarr/hermes-kraken...) НЕ восстановлены — отдельная задача при необходимости.
|
||||
|
||||
### Историческая справка (WS-версия, суперсидившаяся)
|
||||
- Канал до перехода: Kraken→TrueNAS `172.24.0.2 → 90.189.160.148:443 ESTABLISHED`; portal `172.16.1.7:12346 ← Caddy 172.16.1.3 ESTABLISHED`; bridge лог `common/mux: received request for udp:reverse:0`. payload ❌ НЕ проходил (причина перехода на TCP).
|
||||
|
||||
#### Развёрнутые контейнеры (WS-версия, историческая справка)
|
||||
|
||||
**TrueNAS — `xray-reverse-portal`** (VLESS/W S, reverse portal): `/mnt/RED_2TB/docker/reverse-portal/`
|
||||
- compose в `/mnt/RED_2TB/docker/reverse-portal/docker-compose.yml`, image `teddysun/xray:latest` (Xray 26.7.28)
|
||||
- конфиг `config.json` (portal reverse):
|
||||
- inbound `interconn`: VLESS на `:12346`, ws path `/rvs`, host `vpn.mallexxx.duckdns.org`, client `a81c3179-312b-4c5e-8a46-6bf3c30c2941`, `"reverse":{"tag":"reverse-out"}`
|
||||
- inbound `local`: SOCKS на `:12345` (для клиентов сети TrueNAS), `udp:true`
|
||||
- routing: `inboundTag:["local"] → outboundTag:"reverse-out"`
|
||||
- outbounds: `freedom` (placeholder)
|
||||
- проброс на host: **только `12345:12345`** (SOCKS для сети). Порт 12346 в docker-сети (к нему обращается Caddy по имени `xray-reverse-portal:12346`), наружу НЕ проброшен.
|
||||
- сеть `caddy_default`, папку создавал через `docker run --rm -v /:/host alpine sh -c "mkdir -p ...; chown 950:950 ..."` (truenas_admin не имеет прав на `/mnt/RED_2TB/docker/`).
|
||||
|
||||
**TrueNAS — Caddy**: в блок `vpn.mallexxx.duckdns.org` добавлен маршрут `/rvs`:
|
||||
```caddy
|
||||
@rvs path /rvs
|
||||
reverse_proxy @rvs xray-reverse-portal:12346
|
||||
```
|
||||
- Caddyfile на хосте: `/mnt/RED_2TB/docker/caddy/Caddyfile` (bind-mount; **нельзя `docker cp`** → `device or resource busy`; править на хосте через alpine `cp /host/tmp/...`).
|
||||
- Бэкап перед правкой: `Caddyfile.pre-reverse` в той же папке. Caddy валидация: `docker exec caddy caddy validate --config /tmp/Caddyfile.new` → "Valid configuration". Перезапуск: `docker restart caddy` (безопасно).
|
||||
- Проверка маршрута: `curl -sk https://vpn.mallexxx.duckdns.org/rvs` → HTTP 400 (ожидаемо для WS-эндпоинта Xray при не-WS GET).
|
||||
|
||||
**Kraken — `xray-reverse-bridge`** (VLESS-WS reverse bridge): `/home/kraken/xray-reverse/`
|
||||
- compose + `config.json` (bridge reverse):
|
||||
- outbounds: `direct` = `freedom` + `"finalRules":[{"action":"allow","network":"tcp,udp","ip":["0.0.0.0/0"]}]`; `conn` = VLESS simplified style (НЕ vnext) → `vpn.mallexxx.duckdns.org:443`, ws `/rvs`, `"reverse":{"tag":"reverse-in"}`, security tls
|
||||
- routing: `inboundTag:["reverse-in"] → outboundTag:"direct"`
|
||||
- **Питфолл:** VLESS-outbound для reverse ДОЛЖЕН быть в *упрощённом* стиле (`settings.address/port/id/encryption/reverse`) — при использовании `vnext[]/users[]` Xray 26.x ругается: `VLESS users: please use simplified outbound's config style to use "reverse"`.
|
||||
- `loglevel debug` включён для диагностики.
|
||||
- Порт 443 на Kraken свободен; образ `teddysun/xray:latest` скачан.
|
||||
|
||||
### Развёрнутый reverse-канал — работает
|
||||
- Kraken → TrueNAS: `netstat` на Kraken показывает `172.24.0.2:xxxxx → 90.189.160.148:443 ESTABLISHED`.
|
||||
- Portal (TrueNAS): `::ffff:172.16.1.7:12346 ::ffff:172.16.1.3:52616 ESTABLISHED` (172.16.1.3 = Caddy, передающий WS от Kraken).
|
||||
- Bridge логи: `common/mux: received request for udp:reverse:0` — reverse-канал установлен (TCP+UDP).
|
||||
|
||||
### ❌ НЕ работает: payload (end-to-end curl 000)
|
||||
- `curl --socks5 127.0.0.1:12345 http://api.ipify.org` на TrueNAS → `code=000` (прямой curl с того же хоста → 200).
|
||||
- Portal логи: `accepted tcp:8.47.69.0:80 [local -> reverse-out]` — portal отправил запрос в reverse-out.
|
||||
- **Bridge НЕ логирует accepted/received для этого TCP-payload** — данные теряются между portal reverse-out и bridge reverse-in.
|
||||
- Kraken имеет прямой интернет (api.ipify → `92.62.70.41`, code=200), поэтому проблема НЕ в egress Kraken.
|
||||
|
||||
### 💡 Гипотеза по неработающему payload (ВЕРОЯТНАЯ)
|
||||
**WebSocket-транспорт НЕ пропускает reverse-payload должным образом.** В официальном Xray reverse-примере используется **прямой TCP** + `flow: xtls-rprx-vision` (REALITY) для канала bridge↔portal. Обратный UDP reverse создаётся (`udp:reverse:0`), но TCP-payload по WS не доходит до bridge.
|
||||
**Решение (предполагаемое):** перевести reverse-канал на **прямой TCP**: на TrueNAS VLESS-inbound interconn на отдельном TCP-порту (напр. 12346 наружу) + проброс на роутере `внешний :12346 → 192.168.2.197:12346`; bridge VLESS-outbound → TCP (не WS). Выполнение отложено — Alex согласовал проброс порта («не проблема»), но внедрение не завершено.
|
||||
|
||||
## Порядок работ (отметки → фактический статус 2026-09-01, финал)
|
||||
|
||||
1. ✅ Бэкап: `/mnt/RED_2TB/docker/backups/reverse-xray-3xui-20260901-113625/` (Caddyfile + x-ui.db + docker-inventory).
|
||||
2. ✅ Создан `/mnt/RED_2TB/docker/xray-admin/docker-compose.yml` (deployed версия — см. «Фактически развёрнутый compose»).
|
||||
3. ✅ Поднят `docker compose up -d` → контейнер Up.
|
||||
4. ✅ Проверено: панель `https://vpn-panel.mallexxx.duckdns.org/` → HTTP 200, inbound vless-ws:10095 активен.
|
||||
5. ✅ Создан portal-контейнер `xray-reverse-portal` на TrueNAS (interconn :12346 + SOCKS `local`:12345) + Caddy маршрут `/rvs`. [Затем: переведён на TCP+REALITY, см. секции «Reverse деплой».]
|
||||
6. ✅ Создан bridge-контейнер `xray-reverse-bridge` на Kraken (→ TrueNAS, egress direct). Reverse-канал установлен. [Затем: переведён на TCP+REALITY.]
|
||||
7. 🔑 **End-to-end НЕ работал** (curl через SOCKS 12345 → 000) на WS и на TCP+REALITY (flow и без flow) — **причина найдена (issue #6612)**: с v26.5+ у freedom/direct дефолт блокирует VLESS Reverse payload без явного `finalRules`. **Фикс залит** на bridge-конфиг /home/kraken/xray-reverse/config.json, но **не применён** — Kraken по docker недоступен (USB-HDD `sda`=0B, docker в `activating`). См. «КОРЕНЬ ПРОБЛЕМЫ НАЙДЕН» и «ФИКС ПРИМЕНЁН, но заблокирован» выше. **Статус: задание НЕ завершено — нужен фикс HDD/docker Kraken + пересоздать bridge + тест.**
|
||||
8. ⏳ Обновить Obsidian: truenas-infrastructure.md, kraken-access.md, vps-qentra.md. **TODO для следующей сессии.** (Основной tech-doc `personal/tech/xray-reverse-tunnel-kraken-truenas.md` уже обновлён 2026-09-01 с корнем/фиксом.)
|
||||
|
||||
## ❌ ФИНАЛ СЕССИИ 2026-09-02: downgrade обеих сторон НЕ помог — reverse по-прежнему мёртв
|
||||
|
||||
> Гипотезы выше (#6612, #6242 → «понизить bridge до 26.4.25») были **проверены на практике и НЕ решили проблему**. Это фактический итог — читать вместо старых «корень найден» теорий.
|
||||
|
||||
### Выполнено (по согласованию, не трогая vpn.mallexxx/xray-admin)
|
||||
- **Bridge (Kraken)** `docker-compose.yml`: образ `teddysun/xray:latest` → **`teddysun/xray:26.4.25`** (бэкап `.bak-26.7.28`). Контейнер на 26.4.25 (arm64).
|
||||
- **Portal (TrueNAS)** `/mnt/RED_2TB/docker/reverse-portal/docker-compose.yml`: тоже → **`teddysun/xray:26.4.25`** (бэкап `.bak-26.7.28`). Образ 21.6MB Pull, контейнер пересоздан (amd64).
|
||||
- Portal `config.json` → `loglevel: debug` (на время диагностики).
|
||||
- Локальные копии на Mac для правки: `~/xray-test/` (`docker-compose.bridge.yml`, `docker-compose.portal.yml`, `portal.config.json`, `config.json` — тестовый xray-клиент vpn.mallexxx).
|
||||
- После смены версий bridge перезапускался для переустановки канала к новому portal.
|
||||
|
||||
### Результат end-to-end (обе стороны 26.4.25)
|
||||
- Reverse-канал у bridge **есть**: `dialing TCP → tunneling → received request for udp:reverse:0`. Portal принимает (`received request for tcp:v1.rvs.cool:0 → dispatching to udp:reverse:0`).
|
||||
- **Payload НЕ проходит**: `curl` через `xray-reverse-portal:12345` → `Empty reply from server` / `exit=52`.
|
||||
- **Portal debug (ключевое):** `taking detour [reverse-out] for [tcp:api.ipify.org:80]` → **и ничего дальше** (ни dial, ни ошибки). Dispatch в reverse-out молча глотается. Фоново: `common/mux: failed to read metadata ... connection reset by peer` (:12346).
|
||||
- **На TrueNAS НЕТ постоянного ESTABLISHED TCP на :12346** от bridge (`ss -tn sport=:12346` пусто) → reverse-канал **не удерживается постоянным** (только эфемерные контрольные прочёты), data-stream до bridge не доходит. Bridge никогда не логирует приём reverse-in TCP-payload.
|
||||
|
||||
### Итог
|
||||
Проблема **НЕ** регрессия bridge-v26.5+ (#6242) — downgrade до заведомо рабочей пары 26.4.25↔26.4.25 не помог. **Настоящая причина лежит глубже:** VLESS Reverse sub-protocol нестабилен (предупреждение PR #5101) и между разнесёнными docker-реализациями (Kraken arm64 ↔ TrueNAS amd64) reverse-канал не удерживается постоянным на TCP-уровне → портал не может передать данные в bridge.
|
||||
|
||||
### Нереализованные гипотезы (на будущее, треб.WB)
|
||||
1. Убрать REALITY/camouflage с канала TrueNAS↔Kraken (это внутренний обмен между сервисами, не извне) — оставить чистый VLESS-TCP/простой шифр, исключив REALITY-handshake как источник нестабильного mux.
|
||||
2. Аудит конфига bridge — что именно заставляет xray НЕ держать постоянный единственный канал (в reverse bridge обычно держит persistent-соединение).
|
||||
3. При необходимости консультация/живой разбор рабочего egress-конфига (канон доки не дал полного рабочего варианта).
|
||||
|
||||
### ⚠️ Текущее состояние системы (2026-09-02)
|
||||
- **Версии:** portal + bridge сейчас **обе на `teddysun/xray:26.4.25`** (исходно `:latest`=26.7.28). Откат: вернуть в compose образ `teddysun/xray:latest` → `docker compose up -d`.
|
||||
- Bridge config содержит фикс #6612 (`finalRules:allow`). Portal config на `loglevel: debug`.
|
||||
- `vpn.mallexxx` / `xray-admin` (3x-ui) / Caddy — НЕ тронуты, работают (рабочий Xray-VPN через TrueNAS, end-to-end проверен 2026-09-02).
|
||||
- **Reverse к Kraken НЕ внедрён/не работает end-to-end** — остаётся открытой задачей.
|
||||
|
||||
## Ограничения / риски
|
||||
|
||||
- Кра́кен в NAT ⇒ только исходящие соединения; reverse-канал держит Kraken.
|
||||
- Не ломать существующий Caddy/домены (бэкапить Caddyfile, перезапуск Caddy аккуратно).
|
||||
- `vless-proxy` (Hermes-Taiga) не трогать — настроен под local SOCKS.
|
||||
- Внешний Xray-порт: через Caddy по пути `/vless` (WS). Для полноценного reverse возможно потребуется отдельный VLESS+Reality inbound на отдельном порту + проброс на роутере для Kraken — ДОБАВИТЬ после проверки связности панели.
|
||||
@@ -0,0 +1,73 @@
|
||||
---
|
||||
created: '2026-08-24'
|
||||
updated: '2026-08-24'
|
||||
tags:
|
||||
- tax
|
||||
- russia
|
||||
- residency
|
||||
---
|
||||
# Налоговая резиденция РФ — статус и план
|
||||
|
||||
## Контекст
|
||||
|
||||
- ИП в Кыргызстане, доход от иностранных IT-клиентов
|
||||
- Живу в Бишкеке, гражданин РФ
|
||||
- Цель: **не становиться налоговым резидентом РФ** (порог — 183 дня в любые 12 последовательных месяцев)
|
||||
- Пока нерезидент — доход от КР-ИП РФ не касается
|
||||
|
||||
---
|
||||
|
||||
## Въезды/выезды в РФ
|
||||
|
||||
| Период | Дней |
|
||||
| ----------------------- | ------- |
|
||||
| 29.11.2025 → 14.03.2026 | 106 |
|
||||
| 04.07.2026 → 12.09.2026 | 71 |
|
||||
| 29.11.2026 → ? | считаем |
|
||||
|
||||
---
|
||||
|
||||
## Подсчёт скользящего окна
|
||||
|
||||
### На дату приезда 29.11.2026
|
||||
|
||||
Окно 29.11.2025 → 28.11.2026:
|
||||
- 29.11.25 → 14.03.26 = **106 дней**
|
||||
- 04.07.26 → 30.08.26 = **58 дней**
|
||||
- **Итого: 164 дней** (запас: **18 дней** до 183)
|
||||
- 06.09.26 → 23.09.26 = 18
|
||||
|
||||
### Динамика окна при пребывании с 29.11.2026
|
||||
|
||||
- **29.11.26 → 14.03.27:** из окна выпадают дни 29.11.25→14.03.26 — все в РФ → +1 −1 = **счётчик стоит на 177**
|
||||
- **15.03.27:** из окна начинают выпадать дни с 15.03.26 (КР) → каждый день в РФ даёт **чистый +1**
|
||||
- Запас 6 дней → нужно выехать до **~21.03.2027**
|
||||
|
||||
### ⚠️ Безопасный выезд при поездке 29.11.2026
|
||||
|
||||
**Выехать не позднее 20.03.2027**
|
||||
|
||||
---
|
||||
|
||||
## Риски и что отслеживать
|
||||
|
||||
- ФНС планирует автоматическое определение резидентства по загранпаспорту (данные о въездах/выездах) — статус инициативы неясен
|
||||
- Для стран ЕАЭС (КР, Армения, Казахстан) граница по внутреннему паспорту не фиксируется автоматически — но это может измениться
|
||||
- При смешанном резидентстве (РФ + КР одновременно по 183+ дней) применяется СИДН РФ–КР (соглашение от 13.01.1999)
|
||||
|
||||
---
|
||||
|
||||
## СИДН РФ–КР (на случай если всё же стану резидентом РФ)
|
||||
|
||||
1. Получить **сертификат налогового резидентства КР** (ГНС Кыргызстана)
|
||||
2. Подать **3-НДФЛ** в РФ, указать доход от КР-ИП, сослаться на СИДН (ст. 7 — предпринимательская деятельность)
|
||||
3. Приложить: сертификат резидентства КР, квитанции об уплате налога в КР, контракты
|
||||
4. Налог уплаченный в КР засчитывается — доплачивается только разница (КР ~4–6%, РФ 13%)
|
||||
|
||||
---
|
||||
|
||||
## Вывод / план
|
||||
|
||||
- **Сейчас:** нерезидент РФ, всё чисто
|
||||
- **Поездка 29.11.2026:** можно сидеть до **20.03.2027** — счётчик нейтрален пока выпадают дни зимы 2025/26 (были в РФ), с 15.03.27 начинает расти
|
||||
- **Принцип:** следить за датами, особенно после длинного лета в РФ — запас резко сокращается
|
||||
@@ -0,0 +1,80 @@
|
||||
# Интерактивные билеты охотника (a1-tir.ru/bilety)
|
||||
|
||||
Проект: скачать страницу билетов для экзамена на гражданское оружие и превратить в интерактивный тренажёр.
|
||||
|
||||
**Возможности:** номер правильного ответа скрыт · ответы кликабельны · выбранный неправильный → красный, правильный → зелёный.
|
||||
|
||||
**Файлы (исходники в `~/Downloads/`):**
|
||||
- `bilety.html` — финальная статичная страница (кнопки вшиты в HTML, 181 карточка / 543 кнопки, ≈902 КБ); деплой в `/Library/WebServer/Documents/bilety.html`
|
||||
- `origen_raw.html` — оригинальная скачанная копия (чистый источник для генерации)
|
||||
- `gen2.py` — Python-генератор оригинала → `bilety.html` (статические кнопки, без JS-скрипта)
|
||||
- `gen_fix.py`, `fix216.py` — точечные скрипты восстановления потерянных вопросов
|
||||
- `bilety.js`, `bilety.css` — ранняя (отклонённая) версия enhancer'а на клиентском JS; в финале НЕ используются
|
||||
- `a1-tir_bilety_raw.html` — оригинальная скачанная копия (альтернативное имя)
|
||||
|
||||
---
|
||||
|
||||
## Статус
|
||||
- ✅ Страница скачана и переработана в интерактив.
|
||||
- ✅ **Задеплоено в Eagle Dashboard Pages** — `/Library/WebServer/Documents/bilety.html` (902285 байт), URL `/local-pages/bilety.html`. Рестарт дашборда не нужен (сканируется живьём).
|
||||
- ✅ **Все 181 вопрос покрыты** (1.1→1.93, 2.1→2.42, 58→103), каждая карточка ровно 3 кнопки, номер правильного скрыт, клик красит красный/зелёный.
|
||||
- Изначально терялось 5 вопросов (1.93, 81, 83, 94, 2.16) из-за нестандартной обёртки `<em>` и вопроса без `<strong>`. Восстановлены скриптами `~/Downloads/gen_fix.py` и `~/Downloads/fix216.py`. Подробности — в `personal/tech/bilety-oxota-interaktiv.md`.
|
||||
|
||||
---
|
||||
|
||||
## Источник и структура (Tilda)
|
||||
|
||||
Страница — Tilda-лендинг, весь исходный HTML на одной строке (`a1-tir_bilety_raw.html`, строка 228 содержит контент).
|
||||
|
||||
Экзамен разложен по **4 блокам** `data-record-type="106"` (Tilda text-блок `div.field-text.t-text`):
|
||||
- `rec465410787` — «Правовая подготовка», вопросы 1.1–1.49
|
||||
- `rec1120437831` — без заголовка (продолжение правовой), 1.50–1.93
|
||||
- `rec1120438216` — «Огневая подготовка», 2.1–2.41
|
||||
- `rec465410788` — без заголовка (правила охоты), 58–103 · **вопросы из нескольких `<strong>`**
|
||||
- Итого ~180 вопросов.
|
||||
|
||||
### Структура одного вопроса в DOM (проверено по сырым данным)
|
||||
Каждый блок — один большой div; внутри `childNodes`:
|
||||
- `<br/>` — разделители (шум)
|
||||
- `<strong>Вопрос</strong>` — текст вопроса; может занимать **несколько подряд** `<strong>` (напр. вопрос 58); внутри возможен вложенный `<a>` (consultantplus)
|
||||
- шапка раздела — `<p><strong>Заголовок</strong></p>` (strong вложен в p → не ловится как вопрос)
|
||||
- текстовые узлы ответов: `"1. Текст"`, `"2. ..."`, `"3. ..."` (бывают ведущие пробелы)
|
||||
- `<em>N</em>` — **номер правильного ответа** (чистое число)
|
||||
- примечание — `<em><u>Примечание</u>: …</em>` (НЕ номер, сохранить)
|
||||
- шум: `<strong> </strong>`, `<em> </em>`, пустой `<em>` с `<strong data-redactor-tag>`
|
||||
|
||||
Контентных `<img>`/`<svg>` в блоках вопросов нет — только текст.
|
||||
|
||||
---
|
||||
|
||||
## Решение — чисто клиентский JS (без библиотек/backend)
|
||||
|
||||
`bilety.js` на `DOMContentLoaded` обрабатывает каждый `[data-record-type="106"] .t-text`:
|
||||
|
||||
**Парсер `parseQuiz` (конечный автомат по childNodes):**
|
||||
- `<strong>` с непустым текстом, не ` `: если у текущего вопроса ещё нет ответов и фаза `question` → **мержим** текст (многострочный вопрос); иначе → **новый вопрос**.
|
||||
- текстовый узел, матчащий `^\d+[\.\s:]` и при отсутствии заданного `correct` → ответ `{n, text}` (фаза → `answers`); иначе — продолжение последнего ответа.
|
||||
- `<em>` с чистым числом → `question.correct = N` (только в фазе `answers`, чтобы не спутать с «Примечание»); с текстом → `question.note = innerHTML` (сохранить); пустой/` ` → шум.
|
||||
- `<p>` при `cur === null` и нет вопросов → `headerHTML` (заголовок раздела сохраняем).
|
||||
- фильтр: оставляем только вопросы с `correct !== null`.
|
||||
|
||||
**Рендер `renderQuestion`:** карточка `.whale-q` → `.whale-q-text` (вопрос, `textContent`, жирный) + `.whale-answers` с кнопками `.whale-a` (`data-n` = номер ответа) + опционально `.whale-note`.
|
||||
|
||||
**Click-логика:** первый клик блокируется (`data-locked`). Если `n === correct` → класс `correct` (зелёный); иначе класс `wrong` (красный) **и** правильный ответ получает `correct` (чтобы показать верный). Управляется `data-correct` на карточке.
|
||||
|
||||
**Инъекция в страницу:**
|
||||
- `<link rel="stylesheet" href="bilety.css">` перед `</head>`
|
||||
- `<script src="bilety.js" charset="utf-8"></script>` перед `</body>`
|
||||
- мета для дашборда в `<head>`: `eagle-test-purpose`, `eagle-test-contains`.
|
||||
|
||||
**Дизайн .whale-a:** карточки-кнопки (flex column), `#f5f5f5`, hover `#ececec`; `.correct`=`#d4edda`/`#28a745`, `.wrong`=`#f8d7da`/`#dc3545` (с `!important`).
|
||||
|
||||
---
|
||||
|
||||
## Pitfall: локальное открытие `file://`
|
||||
Страница Tilda использует `sessionStorage` для анимации появления `.t-records` — при открытии локально это работает. Просто открыть `bilety.html` двойным кликом достаточно для проверки функционала.
|
||||
|
||||
---
|
||||
|
||||
## Связанное
|
||||
- Доставка в дашборд — механика Pages: `personal/projects/personal-os/eagle-dashboard.md`.
|
||||
@@ -0,0 +1,91 @@
|
||||
---
|
||||
tags:
|
||||
- research
|
||||
- agents
|
||||
- landscape
|
||||
- ai
|
||||
- trends
|
||||
created: '2026-09-02'
|
||||
updated: '2026-09-02'
|
||||
related:
|
||||
- personal-os-architecture
|
||||
- hermes-agent-improvements
|
||||
- agent-memory-architecture
|
||||
---
|
||||
# AI Agent Landscape — прогресс и тренды (сентябрь 2026)
|
||||
|
||||
> Запрос Whale: «какой сейчас прогресс и что трендится в ИИ-агентских системах как замена текущему Hermes-конфигу».
|
||||
> Дата обзора: 2026-09-02. Ниша Whale = self-hosted, always-on персонал-агент (Hermes + Obsidian-MCP + cron + webhook + Zulip).
|
||||
|
||||
## Главный вывод
|
||||
|
||||
**Hermes Agent — не «устаревший конфиг», а один из двух доминирующих open-source рантаймов в своей нише** (личный self-hosted агент с memory/skills). Поле «замен» в этой категории очень узкое, и ближайший конкурент OpenClaw не является функциональной заменой, а скорее дополнением (или сценарием «полного переезда», невыгодным после вложенных кастомизаций). Плюс есть движок «пилотирования» / оркестратора сверху.
|
||||
|
||||
## Тренды отрасли (2026)
|
||||
|
||||
- **От демо к инфраструктуре**: 2026 = год, когда агенты перестали быть демо и стали инфраструктурой. Автономность измеряется «как долго агент работает до вмешательства человека» (Prosus State of AI Agents).
|
||||
- **Adoption gap 4–8×**: 88% orgs используют AI в ≥1 функции, но только 17–23% разворачивают агентов; ≤10% в каждой отдельной функции. Gartner: 40% агент-проектов отменят к 2027 (неясный ROI).
|
||||
- **Фреймворк-использование ≠ звёзды GitHub**: OpenClaw 345–373K★, Hermes ~110–160K★. Но по фактическому объёму токенов Hermes берёт верх (8.14 трлн cumulative, #1 на OpenRouter с ~апреля-мая 2026). Kейс «звёзды измеряют любопытство, токены — работу».
|
||||
- **Модельная универсальность = стандарт**: маршрутизация (дорогая модель на сложный reasoning, дешёвая — на фон) едва ли не главный рычаг экономии. Спред 100×+ (open-weight $0.07–0.12/1M против фронтира $15/1M).
|
||||
- **Память стала конкурентным преимуществом**: gap «есть/нет памяти» важнее gap между backbone-моделями. Три уровня (episodic/semantic/procedural) + proc-memory (навыки как процедурная память) — распространённая зрелая архитектура (ваша уже так построена).
|
||||
- **Governance/ROI/security — блокер масштабирования**: лучшие практики — least-privilege creds, approval на destructive-действия, аудит скиллов до установки.
|
||||
- **Регулирование**: EU AI Act high-risk требования вступают в силу с 2026-08-02. Прозрачность фондовых моделей падает (Stanford Transparency Index 40 vs 58 в 2025) → риск для procurement.
|
||||
|
||||
## Матрица «замен» применительно к Whale-конфигу
|
||||
|
||||
### 1. OpenClaw — НЕ замена, конкурент/гибрид
|
||||
- Gateway «control plane», первая-class интеграции с мессенджерами, 13.7K+ community-скиллов.
|
||||
- Слабее Hermes по: self-improving learning loop (у OpenClaw скиллы статичны/человеко-писаны), память кросс-сессионная слабее, нет checkpoint/rollback.
|
||||
- **Security-инциденты**: CVE-2026-25253 (RCE, CVSS 8.8, 40K+ инстансов раскрыты, 63% уязвимы на момент), 341 вредоносных скилла в ClawHub (supply-chain poisoning).
|
||||
- Миграция: у Hermes есть `hermes claw migrate`.
|
||||
- *Паттерн комьюнити* (~25% Reddit): **OpenClaw как оркестратор + Hermes как исполнитель** (через ACP/profiles).
|
||||
|
||||
### 2. Кодинг-агенты (Claude Code, Cursor, OpenHands, Swarm…) — НЕ в этой нише
|
||||
- Если работа — в основном кодинг → релевантны, но способности OpenHands (72% SWE-Bench) к персональному always-on агенту отношения не имеют. Whale этим заниматься не должен.
|
||||
|
||||
### 3. Узкие фреймворки (LangGraph, CrewAI, Microsoft Agent Framework, Google ADK, OpenAI Agents SDK, Mastra, AutoGen)
|
||||
- Это **продукт-ориентированные SDK для building apps**, НЕ self-hosted персональные рантаймы. Для Whale-сценария — не конкуренты. Полезны как справочник паттернов (оракестрация, human-in-the-loop, observability), но переписывать на них личную систему незачем.
|
||||
- LangGraph: state control / durable execution лидирует (38M PyPI downloads/mo, v1.0).
|
||||
- CrewAI: ~44–49K★, role-based teams, 82% task success, но pain points (async, отладка, память).
|
||||
- Microsoft Agent Framework: наследник AutoGen+Semantic Kernel.
|
||||
- OpenAI Agents SDK: «opinionated handoff», простые multi-agent.
|
||||
- AutoGen/AG2: Microsoft перевёл в maintenance (заменён Agent Framework).
|
||||
|
||||
## Куда движется поле — тренды, релевантные Whale
|
||||
|
||||
### a) Длительный автономный ран (суверенность)
|
||||
- «Deep Agents»/harness для long-running задач (research/coding): планирование + context management. Прямой аналог широты ваших cron-agent'ов.
|
||||
- Валюта рынка = **continuous-time autonomy**; ставит вопрос о функциях типа pause/resume, отмена mid-flight у Whale агентов.
|
||||
|
||||
### b) Пилотирование/проактивность
|
||||
- Трендовые личные агенты (rho «checks in on its own», Gaia с расписаниями) — эксперимент: агент сам инициирует. У вас уже есть cron-слой (по расписанию) и watchdogs; рынок двигается в сторону **условно-событийной** проактивности (не только по таймеру).
|
||||
- Дуальность «timer-driven vs event-driven automation» — зрелая тема в memory stacks (event-driven triggers: new source→ingest etc.). Частично покрыто вашей архитектурой, но выраженно event-driven (на изменения в vault, новые MCP-инструменты) — точка роста.
|
||||
|
||||
### c) Память и контекст
|
||||
- **Summarization drift** и overflow правила (это у вас уже есть).
|
||||
- Confidence scoring + temporal decay (smart-aвторы памяти: Mem0/Letta/LangMem pattern) — ваш MEMORY.md overflow и curation похожи, но «система без явного scoring» может добавить confidence + decay для SEMANTIC.
|
||||
- Сторонние движки памяти (Letta/Mem0/Agno memory) — кандидаты на «апгрейд» semantic-tier позже, но сегодня у вас связка собственный MEMORY + SQLite already.
|
||||
|
||||
### d) Observability / отладка агентов
|
||||
- LangSmith/её аналоги + «action trace против фактического исполнения» — известная боль CrewAI (traces не отражают реальное исполнение). У вас подход «facts over self-reports», verify handles — уже в правильную сторону. Формальный лог «намерение→факт» — вещь, которую рынок догоняет.
|
||||
|
||||
### e) Физический/десктопный контур
|
||||
- Desktop app (Hermes v0.16 native desktop, June 2026) и iMessage-support (Photón/Agents, v0.17 June 2026) — движение к «агент в каждом приложении». Вы on macOS + webhook/Zulip — десктопный/локальный контур для вас опционален (Apple-скиллы уже есть: Notes/Reminders/FindMy).
|
||||
|
||||
## Рекомендации (кратко)
|
||||
|
||||
1. **Гонку «сменить фреймворк» не выигрывает никто из альтернатив** — текущий Hermes-конфиг уже implemented лучшие практики (3-tier memory, skills как proc-memory, SOUL.md, Observable vault-as-truth). Switching = решение проблем, которых у вас нет, ценой переписывания кастомизаций.
|
||||
2. **Присмотреться к OpenClaw** исключительно как к оркестратору на *дополнительных* каналах/аппах, если появится потребность «один агент во всех чатах» шире текущих (webhook/Zulip + локальные скиллы). Не как замена.
|
||||
3. **Усилить event-driven проактивность** (триггеры на изменение vault/новые файлы/сигналы) поверх timer-driven cron.
|
||||
4. **Security posture как у фронтира**: least-privilege, approval на деструктив, аудит любых устанавливаемых скиллов (урок из ClawHub poisoning + собственный CVE-опыт Hermes v0.16).
|
||||
5. **Модельная маршрутизация** — самый дешёвый рычаг снижения токен-расхода в личной системе в 2026.
|
||||
6. **Не полагаться на звёзды как на критерий** при сравнении — смотреть на устойчивый объём работы (у Hermes он вверху — #1 OpenRouter).
|
||||
|
||||
## Источники
|
||||
- DEV: 10 Best Open-Source AI Agents 2026
|
||||
- Turing Post: Hermes Agent vs OpenClaw (2026-06-13)
|
||||
- HundredTabs: Hermes vs OpenClaw honest comparison (2026-05-10) — 1,300+ Reddit comments
|
||||
- Context Studios: OpenClaw vs Hermes 2026 (2026-06-22)
|
||||
- LangChain: best AI agent frameworks 2026 (2026-06-06)
|
||||
- DigitalApplied: State of AI Agents 2026 (220+ data points, 2026-05-22) — McKinsey/Stanford HAI/Gartner/IDC
|
||||
- openclaw/hermes GitHub (статистика на дату обзора)
|
||||
@@ -149,6 +149,21 @@ PID-file-based — survives Dashboard restarts without crashing.
|
||||
|
||||
**Pages** — URL input + metadata table for `/Library/WebServer/Documents/*.html` test pages. Each row shows filename, title, purpose, contents, modified date, and opens the page in a new browser tab.
|
||||
|
||||
### Как добавить страницу в Pages (2026-08-24, проверено)
|
||||
|
||||
Механика — просто копия `*.html` файла в webroot `/Library/WebServer/Documents/`. Дашборд читает каталог **живьём** через `GET /api/pages` → `_read_page_metadata()` — рестарт дашборда и `launchctl kickstart` **не нужны**. Страница отдаётся по `/local-pages/<filename>` (mount `app.mount("/local-pages", StaticFiles(...))`).
|
||||
|
||||
Метаданные парсятся из HTML:
|
||||
| Поле дашборда | Источник |
|
||||
|---|---|
|
||||
| `title` | `<title>...</title>` |
|
||||
| `purpose` | `<meta name="eagle-test-purpose" content="...">`, fallback — `<meta name="description">` |
|
||||
| `contains` | `<meta name="eagle-test-contains" content="...">` |
|
||||
|
||||
**Pitfall — относительные `href`/`src`:** если страница ссылается на свои `.js`/`.css` относительными путями (как `bilety.html` → `bilety.js`, `bilety.css`), эти файлы тоже обязаны лежать рядом в `/Library/WebServer/Documents/`, иначе запрос уйдёт на `/local-pages/bilety.js` и не найдётся.
|
||||
|
||||
**Pitfall — права (блокер):** `/Library/WebServer/Documents/` принадлежит `root:wheel`, права `drwxr-xr-x`. `admin` писать туда **не может** без sudo. NOPASSWD-правил для этого пути в sudoers **нет** (`admin` имеет только `(ALL) ALL` с паролем + спец. pmset/launchctl NOPASSWD). Из неинтерактивного шелла Hermes `sudo cp` встаёт на запрос пароля → **требуется пароль пользователя или ручная команда**: `sudo cp ~/Downloads/bilety.* /Library/WebServer/Documents/`.
|
||||
|
||||
**Files** — FileBrowser iframe at `http://localhost:8181`.
|
||||
|
||||
**Crons** (2-я вкладка) — управление cron jobs из 3 источников:
|
||||
@@ -299,6 +314,7 @@ When a launchd cron is created and `launchctl print gui/<uid>/<label>` shows `la
|
||||
|
||||
## History
|
||||
|
||||
|- 2026-08-24: **bilety.html added to Pages.** Deployed interactive hunting-license exam page (`/Library/WebServer/Documents/bilety.html`, ~894 KB). 176 question cards, 532 answer buttons. All markup embedded in the HTML: each answer is a `<button class="whale-a" data-correct="N" data-n="M" onclick="...">`, correct-answer number hidden from display (lives only in `data-correct`), inline onclick colors wrong=red / correct=green. No JS-builder script — everything static. Built from `~/Downloads/origen_raw.html` via `~/Downloads/gen2.py`. Pitfalls learned: (1) `_read_page_metadata()` reads files live — no dashboard restart needed; (2) webroot is root-owned, `sudo cp` needed unless perms loosened; (3) relative `href`/`src` deps must sit in webroot too.
|
||||
|- 2026-06-25 (round 10): **Launchd status — PID/exit code from launchctl list.** Added PID parsing (next-format "PID" = N) and LastExitStatus parsing in `_list_launchd_crons()`. `last_status` is None for running processes, integer exit code otherwise. Frontend shows `· exit <code>` or `· never run`. Legacy tab-separated format no longer supported. macOS launchctl returns next-format plist (not JSON) — regex parsing, not json.loads.
|
||||
|- 2026-06-25 (round 9): **RunAtLoad checkbox for launchd crons.** Added `RunAtLoad` field to launchd plist creation. Backend: `main.py` line 636 changed from `pd["RunAtLoad"] = False` to `pd["RunAtLoad"] = body.get("run_at_load", False)`. Frontend: checkbox "Run on load" in cron modal, shown only for source=launchd via `x-show`; `openAddCron()`, `openCronEdit()`, `saveCronModal()` all wired. Backend `_list_launchd_crons()` returns `run_at_load` for edit modal. **Also fixed:** `_msg` auto-dismiss bug — stale object reference after `fetchCrons()` replaced with `find` in fresh array (both crons and services).
|
||||
- 2026-06-25 (round 7): **Launchd schedule — source-dependent validation.** `validateSchedule()` now takes `source` param. For `launchd`: only `every Ns/m/h/d` accepted; cron and ISO rejected with explicit message. For Eagle/Whale: all three formats. Hints, placeholders, and `prettySchedule()` also differ by source. `Query` import added to FastAPI.
|
||||
|
||||
@@ -60,6 +60,17 @@ Eagle использует custom agents — текущий подход.
|
||||
|
||||
**Fix:** cron 02:00 AM ежедневно — читает свежие сессии, обновляет `memory.md` и `personal/projects/`. Вписывается в слот между inbox-sort (01:00) и vault-enrichment (03:00 вс).
|
||||
|
||||
### Бэклог из обзора рынка ИИ-агентов (2026-09-02)
|
||||
|
||||
Полный разбор: [[ai-agent-landscape-2026]]. Вывод: смена фреймворка нецелесообразна (Hermes — #1 по объёму работы на OpenRouter в нише self-hosted перс.агента; альтернативы не перекрывают кастомизации). Из трендов, применимых к конфигу, растут следующие потенциальные улучшения (в порядке ценности):
|
||||
|
||||
1. **Event-driven проактивность поверх timer-driven cron** — триггеры на изменение vault / новые файлы / сигналы, а не только по расписанию. Точка роста: сейчас проактивность только cron/watchdog.
|
||||
2. **Confidence scoring + temporal decay для semantic-tier памяти** — сейчас MEMORY.md overflow есть, но нет явного скоринга/устаревания фактов (паттерн Mem0/Letta/LangMem). Позже, кандидат на апгрейд semantic-tier сторонним движком (Letta/Mem0).
|
||||
3. **Аудит скиллов до установки** — урок из ClawHub supply-chain poisoning (341 вредоносный скилл) и CVE-2026-48710 (Hermes v0.16). Касается Skills Hub / установки сторонних скиллов.
|
||||
4. **Модельная маршрутизация** — самый дешёвый рычаг снижения токен-расхода (спред 100× между open-weight и фронтиром).
|
||||
|
||||
Статус каждого: *не начато / потенциально* — это research-findings, не подтверждённый план. Пересмотреть при планировании следующего спринта улучшений.
|
||||
|
||||
---
|
||||
|
||||
## Вынос хардкода промптов в файлы
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
---
|
||||
created: 2026-08-24
|
||||
tags: [html, quiz, tilda, static-page, python, eagle-dash]
|
||||
updated: 2026-08-24
|
||||
---
|
||||
|
||||
# Билеты охотника — статичный интерактив (a1-tir.ru/bilety → bilety.html)
|
||||
|
||||
## Итог (2026-08-24)
|
||||
|
||||
Скачал `https://a1-tir.ru/bilety` (билеты для экзамена на гражданское оружие/охотничий минимум) и превратил в **статичную страницу с кнопками-ответами, вшитыми в HTML** (БЕЗ JS-скрипта-генератора). Задеплоено в Eagle Dashboard Pages: `/Library/WebServer/Documents/bilety.html` (≈902 КБ, 902285 байт), URL `/local-pages/bilety.html`, вкладка Pages.
|
||||
|
||||
- **181 карточка-вопрос, 543 кнопки-ответа** — **все вопросы** покрыты (1.1→1.93, 2.1→2.42, 58→103), каждая карточка ровно 3 кнопки. Нет дублей и пропусков.
|
||||
- Каждый ответ — `<button class="whale-a" data-correct="N" data-n="M" onclick="...">`.
|
||||
- Номер правильного ответа **скрыт** — живёт только в `data-correct`, не рендерится на экран.
|
||||
- Клик (инлайн `onclick` в каждой кнопке): выбрал неверно → кнопка красная `wrong` + правильная подсвечивается зелёной `correct`; верно → зелёная.
|
||||
- CSS (`.whale-answers`, `.whale-a`, `.correct`, `.wrong`) вшит в `<head>` страницы.
|
||||
|
||||
### Восстановление потерянных вопросов (2026-08-24, исправление)
|
||||
|
||||
Изначально генератор давал **176 карточек** (терял 5 вопросов). Причины потери и фикс:
|
||||
1. **Номер правильного в нестандартной обёртке** — парсер ждал только простой `<em>N</em>`, а у части вопросов был `<strong><em data-redactor-tag="em">N</em></strong>` (вопросы 81, 83, 94) или `<p style="text-align:center;"><em>N</em></p>` (1.93, последний в разделе). Вопрос без распознанного `correct` отбрасывался (`flush()` требует `cur["c"] is not None`).
|
||||
2. **Вопрос без `<strong>`-обёртки** — вопрос 2.16 («Отдачей оружия называется:») в оригинале записан голым текстом «`2.16. …`» без `<strong>`. Парсер не распознал его как новый вопрос и **склеил его ответы с карточкой 2.15** (у 2.15 вышло **7 кнопок** вместо 3, а 2.16 вообще пропал как отдельный вопрос).
|
||||
|
||||
**Как исправлено** (точечные скрипты в `~/Downloads/`, без переписывания gen2):
|
||||
- `gen_fix.py` — вставляет 4 карточки (1.93, 81, 83, 94) в правильные позиции **после своих предшественников** (по поиску границ соседних карточек `<div class="whale-q">`, сортировка вставок по убыванию позиции, чтобы не сдвигать индексы).
|
||||
- Дальше обнаружен и 2.16 → `fix216.py` заменяет сегмент карточки 2.15 (по абсолютным индексам от находки `2.15.` до начала `2.17.`) на корректные 2.15 (3 кнопки) + 2.16 (3 кнопки, correct=2).
|
||||
|
||||
**Pitfall при точечной вставке**: первый вариант regex-патча (`.*?</div>...`) оказался слишком жадным и удалил соседние карточки (181→155). **Надёжно — по границам**: карточки в файле идут подряд без разделителя, конец одной = начало следующей `<div class="whale-q">`. Вставлять по позициям, а не regex-далящим патчем.
|
||||
|
||||
**Как проверял полноту** (главный урок): не полагаться на «~180», а сверять множества номеров оригинала vs сгенерированного:
|
||||
```python
|
||||
orig_nums = set(...) # номера из <strong>N. и голых N. в оригинале
|
||||
gen_nums = set(re.findall(r'whale-q-text">(\d+(?:\.\d+)?\.)\s', gen))
|
||||
missing = orig_nums - gen_nums
|
||||
```
|
||||
Номера «1.», «2.», «3.» в результатах — это **ложные вхождения** (номера ответов, не вопросов), их отфильтровывать по наличию точки-разделителя (`'.' in n`).
|
||||
|
||||
## Универсальная структура исходника (Tilda text-блок)
|
||||
|
||||
Одна строка-контейнер на раздел, `div field="text" class="t-text t-text_md ">` (4 таких блока на странице). Внутри:
|
||||
|
||||
```
|
||||
<p style="text-align:center;"><strong>Заголовок раздела</strong></p> (не всегда)
|
||||
<strong>1.1. Текст вопроса</strong>
|
||||
<br/>1. Вариант1
|
||||
<br/>2. Вариант2
|
||||
<br/>3. Вариант3
|
||||
<br/><em>2</em> ← номер правильного (скрывать)
|
||||
<br/><strong> </strong><br/>
|
||||
<strong>1.2. ...</strong>
|
||||
...
|
||||
```
|
||||
|
||||
- Вопрос может занимать несколько подряд идущих `<strong>` (фрагмент без номера — продолжение).
|
||||
- Ответы — текстовые узлы после `</strong>` между `<br/>`, каждый начинается с `N. `.
|
||||
- `<em>N</em>` — чистый номер правильного. Исключение: `<em><u>Примечание</u>: …</em>` — это примечание, не номер.
|
||||
- Мусор: `<strong> </strong>`, `<em> </em>`, пустые `<em>`/`<strong data-redactor-tag="strong">`.
|
||||
|
||||
## Генератор: `~/Downloads/gen2.py`
|
||||
|
||||
Python (без внешних зависимостей), превращает `origen_raw.html` → `bilety.html`.
|
||||
|
||||
```bash
|
||||
python3 gen2.py # вывод: containers=4 cards=176 buttons=532 bytes=816979
|
||||
```
|
||||
|
||||
Ключевые моменты:
|
||||
- `find_end(html, start)` — баланс `<div>`/`</div>` от индекса открывающего `<div field="text">` до его закрытия.
|
||||
- `transform_container` — **сначала вырезает `<p[^>]*>.*?</p>`** (заголовки разделов). Это критично: без этого блоки с `<p>`-заголовком (раздел «Правовая подготовка» и «Огневая подготовка») давали 0 карточек, вопросы терялись целиком. Убирание заголовков заставляет обрабатывать каждый `<strong>` единообразно (как в блоках без заголовка).
|
||||
- `_scan(inner)` — токенизация текста/тегов; каждый `N. `-ответ → `cur["a"]`; `<em>`-цифра → `cur["c"]` (правильный); strong без номера при пустых ответах → мержится в текущий вопрос.
|
||||
- `_btn(num, text, correct)` — инлайн `onclick`, красящий красный/зелёный.
|
||||
|
||||
## Pitfalls
|
||||
|
||||
1. **Блоки с `<p>`-заголовком**: если не вырезать `<p>.../p>` первым шагом, такие блоки дают 0 карточек (вопросы теряются). Симптом: в собранном файле `cards` вдвое меньше (~86 вместо ~180).
|
||||
2. **Скрытие номера**: не выводить `<em>` в разметку — только `data-correct` на кнопке.
|
||||
3. **`grep -c` по однострочному HTML** вернёт 1 (файл — одна гигантская строка), даже если совпадений сотни. Считать через `python` (`s.count(...)`), не через grep.
|
||||
4. **Файл после генерации большой** (~894 КБ): на каждую кнопку инлайн-`onclick` — приемлемо для статики.
|
||||
5. Node парсеры/`node --max-old-space-size` тут НЕ нужны — на больших минифицированных Tilda-файлах node легко падает в OOM (heap limit) при самопальных токенизаторах. Python + `str.find`/`regex` надёжнее и не жрёт память.
|
||||
|
||||
## Деплой в Eagle Dashboard Pages
|
||||
|
||||
- Механика + права — в `personal/projects/personal-os/eagle-dashboard.md` (секция «Как добавить страницу в Pages»).
|
||||
- Скопировать `bilety.html` в `/Library/WebServer/Documents/` (root-owned, нужен sudo) → страница подхватывается живьём, рестарт дашборда не нужен.
|
||||
@@ -0,0 +1,59 @@
|
||||
---
|
||||
title: Межсайтовая пропускная способность — TrueNAS (Taiga) ↔ Mac/TV
|
||||
created: '2026-09-02'
|
||||
updated: '2026-09-02'
|
||||
type: tech
|
||||
namespace: personal
|
||||
tags: [network, truenas, throughput, rtt, tcp, jellyfin, xray, bottleneck]
|
||||
related:
|
||||
- "[[xray-reverse-tunnel-kraken-truenas]]"
|
||||
- "[[../how-to/truenas-infrastructure]]"
|
||||
---
|
||||
|
||||
# Межсайтовая пропускная способность — 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, транскодинг не идёт**.
|
||||
|
||||
## Решение / направление
|
||||
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`) предложен неверно.
|
||||
|
||||
### 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`.
|
||||
@@ -0,0 +1,174 @@
|
||||
---
|
||||
type: tech
|
||||
topic: print
|
||||
tags:
|
||||
- print
|
||||
- printer
|
||||
- samsung
|
||||
- cups
|
||||
- macos
|
||||
created: 2026-08-26T00:00:00.000Z
|
||||
updated: '2026-09-02T00:00:00.000Z'
|
||||
---
|
||||
|
||||
# Печать и общие сервисы (Mac + сеть)
|
||||
|
||||
Проверка службы печати 2026-08-26: «не видит принтер с телефона».
|
||||
|
||||
## Состояние на момент проверки
|
||||
|
||||
На Mac (admin, macOS 26.6.1, arm64) в системе зарегистрированы два принтера:
|
||||
|
||||
| Принтер | Способ подключения | Статус |
|
||||
|---|---|---|
|
||||
| **Samsung CLX-216x** | Сетевой `ipp://192.168.2.197/printers/Samsung_CLX-216x_Series`, драйвер Generic PostScript | не pингуется в текущей сети |
|
||||
| **Samsung M2020 Series** (SEC84251974A6B3) | AirPrint `dnssd://…_ipp._tcp.local.`, дефолтный, PPD Samsung M2020 Series-AirPrint | не отвечает по сети |
|
||||
|
||||
Системный дефолт: `Samsung_M2020_Series__SEC84251974A6B3_` (idle, enabled 2026-07-29).
|
||||
|
||||
## Ключевые находки
|
||||
|
||||
- **CUPS слушает только локально**: в `/etc/cups/cupsd.conf` → `Listen localhost:631` + `Listen /private/var/run/cupsd`. Наружу (по сети, для AirPrint) служба печати НЕ отдаётся.
|
||||
- **Шеринг печати выключен** (`SharePrinters` в cupsd.conf закомментирован/неактивен; в `system_profiler` оба принтера `Shared: No`, `System Printer Sharing: No`).
|
||||
- **Порт 631 наружу закрыт**: `nc -z 192.168.2.197 631` → closed.
|
||||
- Сеть Мака — `192.168.6.x` (адрес `192.168.6.173`, шлюз `192.168.6.1`). Принтер прописан в подсети `192.168.2.x`.
|
||||
|
||||
## ⚠️ Важное наблюдение (пересечение с TrueNAS)
|
||||
|
||||
Адрес **`192.168.2.197` — это TrueNAS** (truenas_admin, SSH через `mallexxx.duckdns.org`), НЕ сам принтер. Samsung CLX-216x физически подключён к TrueNAS (USB) и печатается через docker-контейнер **cups-splix** (драйвер splix). Запись `ipp://192.168.2.197/printers/Samsung_CLX-216x_Series` в системе Мака — результат обнаружения расшаренной печати TrueNAS на этом адресе.
|
||||
|
||||
## ✅ НаСТОЯЩИЙ ДИАГНОЗ (2026-08-26, подтверждено SSH на TrueNAS)
|
||||
|
||||
**Корень проблемы: cups-splix контейнер НЕ запущен на TrueNAS.**
|
||||
- На TrueNAS **нет ни одной работающей службы печати**: `lpstat`/`cupsd` в системе не установлены, порт 631 закрыт (и локально, и снаружи).
|
||||
- Ни одного docker-контейнера по печати в `docker ps` нет (cup/sprint/ipp — пусто). **Официальный список контейнеров** (docker ps -a): immich(redis/server/postgres), modbus-bridge, mbusd, zigbee2mqtt, webdav, vless-proxy, hermes-taiga, portainer(-mcp), homeassistant, caddy, watchtower, transmission, syncthing, ser2net, rclone, nodered, mosquitto, library, inpxer, inpx-web, gitea, filebrowser. **`cups-splix` отсутствует.**
|
||||
- Образ `cups-splix` не собран (`docker images | grep cups|splix` → пусто).
|
||||
|
||||
### Конфиг cups-splix (цел, на месте)
|
||||
|
||||
Папка `/mnt/RED_2TB/docker/cups/`: `Dockerfile`, `docker-compose.yml`, `docker build.txt`, `data/`, `cache/`, `spool/`, `uld/`.
|
||||
|
||||
**docker-compose.yml:**
|
||||
```yaml
|
||||
services:
|
||||
cups-splix:
|
||||
image: cups-splix
|
||||
container_name: cups-splix
|
||||
command: ["/usr/sbin/cupsd", "-f"]
|
||||
network_mode: host
|
||||
privileged: true
|
||||
volumes:
|
||||
- /dev/bus/usb:/dev/bus/usb
|
||||
- /mnt/RED_2TB/docker/cups/data:/etc/cups
|
||||
- /mnt/RED_2TB/docker/cups/cache:/var/cache/cups
|
||||
- /mnt/RED_2TB/docker/cups/spool:/var/spool/cups
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
**Dockerfile** (debian:12-slim): ставит `cups-daemon cups-client cups-common printer-driver-splix avahi-utils dbus usbutils nano`, пользователь `cupsadmin:admin` (в группе lpadmin), `EXPOSE 631`, CMD `cupsd -f`.
|
||||
|
||||
**Как поднять** (из доки, раздел «Сборка»):
|
||||
```
|
||||
cd /mnt/RED_2TB/docker/cups/
|
||||
docker build -t cups-splix .
|
||||
docker compose up -d # или docker run из build.txt
|
||||
# проверить: порт 631 открылся, принтер подцепился
|
||||
```
|
||||
|
||||
### Почему выпал
|
||||
`.ix-apps` вызов docker data-root при пересоздании пула НЕ переносился → образы (=кеш) потеряны, перекачиваются заново. `cups-splix` — локальная сборка, она не «перекачается», нужно пересобрать. Конфиги целы.
|
||||
|
||||
## ✅ РЕЗОЛЮЦИЯ (2026-08-26, выполнено)
|
||||
|
||||
**cups-splix поднят, печать восстановлена.** Шаги, фактически выполненные на TrueNAS:
|
||||
|
||||
```bash
|
||||
cd /mnt/RED_2TB/docker/cups
|
||||
docker build -t cups-splix . # образ собран успешно (~225s), splix установлен
|
||||
docker compose up -d # контейнер запущен
|
||||
docker exec cups-splix lpstat -p -d # printer Samsung_CLX-216x_Series ... idle, enabled
|
||||
docker exec cups-splix lpstat -a # ... accepting requests
|
||||
nc -z 192.168.2.197 631 # 631 OPEN снаружи
|
||||
```
|
||||
|
||||
- **Принтер подключён по USB к TrueNAS**: `usb://Samsung/CLX-216x%20Series?serial=9566BAGQ213134Z.&interface=1` (Bus 002 Device 008, `04e8:3425` Samsung CLX-216x).
|
||||
- CUPS-конфиг сохранился в `/mnt/RED_2TB/docker/cups/data` (это `/etc/cups`) → принтер прописан и подцепился после рестарта сам.
|
||||
- Образ собрался без ошибок → **раньше его просто не запускали собирать** (не поломка Dockerfile), а потеряли при восстановлении стека вместе с `.ix-apps`.
|
||||
- Порт 631 открыт наружу → печать доступна по сети на `192.168.2.197:631`.
|
||||
|
||||
**Условие для телефона:** телефон должен быть в сети `192.168.2.x` (той же, что и TrueNAS), чтобы увидеть принтер. Если телефон в другой подсети (напр. `192.168.6.x`) — это сетевой вопрос, не печатный.
|
||||
|
||||
Полный рецепт на будущее продублирован в `truenas-infrastructure.md` → раздел «Печать / cups-splix».
|
||||
|
||||
## ✅ Печать PDF извне сети TrueNAS (когда клиент НЕ в подсети, `mallexxx.duckdns.org:631` закрыт)
|
||||
|
||||
Когда принтер физически в TrueNAS, а клиент НЕ в подсети `192.168.2.x` → прямой IPP до `:631` закрыт. Печатать через SSH `mallexxx.duckdns.org` в контейнер `cups-splix` (проверено 2026-09-02):
|
||||
|
||||
```bash
|
||||
# 1. Залить PDF на TrueNAS
|
||||
scp -i ~/.ssh/id_rsa file.pdf truenas_admin@mallexxx.duckdns.org:/tmp/evrika_print.pdf
|
||||
# 2. Скопировать внутрь контейнера
|
||||
ssh -i ~/.ssh/id_rsa truenas_admin@mallexxx.duckdns.org \
|
||||
'docker cp /tmp/evrika_print.pdf cups-splix:/tmp/evrika_print.pdf'
|
||||
# 3. Отправить в очередь (CUPS сам конвертит PDF→vnd.cups-postscript→pstoqpdl; gs+pdftops в контейнере есть)
|
||||
ssh -i ~/.ssh/id_rsa truenas_admin@mallexxx.duckdns.org \
|
||||
'docker exec cups-splix lp -d Samsung_CLX-216x_Series -o media=A4 /tmp/evrika_print.pdf'
|
||||
```
|
||||
|
||||
**Проверка успеха:** `lpstat -W completed | grep "<reqid>"` (искомый job появляется строкой `Samsung_CLX-216x_Series-<N> <user> <bytes> ... <дата>`), очередь пуста (`lpstat -o`), принтер `idle … Rendering completed`. access_log контейнера: `Create-Job successful-ok` + `Send-Document successful-ok`.
|
||||
|
||||
**Важно:** `lp -d <printer> file.pdf` сам создаёт job (`Create-Job`) — НЕ комбинировать с отдельным print-job-id, иначе `client-error-not-found`. PPD CLX-216x принимает `application/vnd.cups-postscript` (`*cupsFilter: 0 pstoqpdl`), поэтому чистый PDF конвертится автоматически. Job в `lpstat -W completed` показывает владельцем `root` (выполняется через docker по SSH) — это нормально.
|
||||
|
||||
Полный шаги: залить → `docker cp` → `docker exec cups-splix lp` → проверить `completed` → убрать временные файлы (`/tmp/...` на хосте и внутри контейнера).
|
||||
|
||||
## ⚠️ ТОПОЛОГИЯ ИЗМЕНЕНА (2026-08-31) — TrueNAS больше НЕ в локальной сети
|
||||
|
||||
TrueNAS ушла из локальной сети и доступна **только** через публичный DNS `mallexxx.duckdns.org` (внешка `90.189.160.148`). Локальный `192.168.2.197` физически **недостижим** (пинг 100% потеря) — TrueNAS не в `192.168.2.x` и не в сети телефона.
|
||||
|
||||
**Подтверждено SSH на TrueNAS (2026-08-31):**
|
||||
- `cups-splix` **Up** (4 days), принтер `Samsung_CLX-216x_Series` **idle / enabled / accepting requests**.
|
||||
- Принтер подключён по USB: `usb://Samsung/CLX-216x%20Series?serial=9566BAGQ213134Z.&interface=1`.
|
||||
- CUPS слушает **`0.0.0.0:631`** (все интерфейсы, `network_mode: host`).
|
||||
- CUPS config: `Port 631`, `WebInterface Yes`, `ServerAlias *` (раздел `cupsd.conf`).
|
||||
- **Снаружи `mallexxx.duckdns.org:631` — CLOSED** (наружу не проброшен).
|
||||
|
||||
**Реальная картина печати:**
|
||||
- **Samsung Mobile Print (app)** — печатает. У приложения адрес вписан вручную/закэширован (не обязательно `192.168.2.197`).
|
||||
- **Штатная Android print service** — добавлял вручную `ipp://192.168.2.197:631/printers/Samsung_CLX-216x_Series` → **«недоступен»**. Ожидаемо: TrueNAS ушла из локальной сети, а адрес `192.168.2.197` из телефона недостижим.
|
||||
|
||||
**Вывод:** «недоступен» в штатной службе — НЕ баг настройки и НЕ проблема порта. Это прямое следствие того, что CUPS-хост (TrueNAS) физически вне сети телефона: локального пути нет, а публичный `mallexxx.duckdns.org:631` закрыт. Android-штатная служба не умеет удалённый IPP через интернет без открытого наружу порта.
|
||||
|
||||
**ОТКРЫТЫЙ ВОПРОС** (не разобран, нет доступа к настройкам приложения): по какому именно адресу Samsung Mobile Print реально шлёт печать, раз 631 снаружи закрыт. Гипотезы: (1) приложение кэширует соединение с времён, когда TrueNAS была локально; (2) используется другой публичный путь (реверс-прокси Caddy на ином порту/HTTPS), не записанный в доках. Для полного разбора нужен адрес/хост из настроек принтера внутри Samsung Mobile Print. Отмечено: **лог CUPS access_log показывает, что практически вся печать шла с IP `192.168.2.141`** (26-30 авг, POST /printers/... Print-Job → 200 successful-ok) — т.е. Samsung Mobile Print ходил по локальному IP, когда TrueNAS ещё была в сети. Похоже, приложение реально кэшировало локальное соединение.
|
||||
|
||||
## ✅ НАСТОЯЩИЙ МЕХАНИЗМ «недоступен» в Android print service (2026-08-31, подтверждено ipptool)
|
||||
|
||||
Дополнительная проверка **внутри контейнера** (`ipptool -tv` → CUPS) дала ключевой факт:
|
||||
|
||||
- **`printer-dns-sd-name = no-value`**
|
||||
- В контейнере cups-splix **НЕ запущен `avahi-daemon`** (процессы: только `cupsd`; `ps aux | grep avahi` — пусто). Пакеты `dbus` + `avahi-utils` в образе есть, но **`avahi-daemon` не установлен и не стартует**, а CMD — только `cupsd -f`.
|
||||
|
||||
**Механика:** Samsung Mobile Print — вендорское приложение, ходит на CUPS **напрямую по IPP** (POST Print-Job по IP) → работает даже без mDNS. **Android штатная служба печати** (Mopria/Default) даже при ручном добавлении по IP затем делает **mDNS/AirPrint-проверку** принтера (`_ipp._tcp` / `_ipps._tcp.local`), чтобы получить `printer-uuid` и capabilities. Если mDNS-анонса нет (`printer-dns-sd-name = no-value`, avahi не запущен) — Android помечает принтер **«недоступен»**, даже если IPP по-IP физически отвечает. Полный ответ CUPS на Get-Printer-Attributes — `successful-ok [PASS]`, принтер idle/accepting/shared — подтверждает: CUPS здоров, всё дело в отсутствии mDNS-анонса.
|
||||
|
||||
## ✅ РЕЗУЛЬТАТ (2026-08-31, выполнен полностью): mDNS поднят через avahi-daemon
|
||||
|
||||
**Место:** папка `/mnt/RED_2TB/docker/cups/`.
|
||||
|
||||
**Выполнено и проверено (все шаги):**
|
||||
- ✅ **Бэкап** конфига: `/mnt/RED_2TB/docker/cups/backup_20260831-003619.tar.gz` (создан внутри контейнера `tar` → `docker cp`; md5 `0e303a6a57ae767d1e14cd72c8039fe4`). Внутри: `/etc/cups`, `/var/spool/cups`, `/var/cache/cups`. Дубль в `/tmp/cups_backup_<ts>.tar.gz` на хосте.
|
||||
- ✅ **Новый `Dockerfile`** (в cups/, заменил старый): в apt добавлен **`avahi-daemon`** + `procps`; добавлен `COPY entrypoint.sh /entrypoint.sh`; `ENTRYPOINT ["/entrypoint.sh"]` вместо `CMD ["cupsd","-f"]`.
|
||||
- ✅ **`entrypoint.sh`** (в cups/): стартует `dbus-daemon --system --fork`, затем `avahi-daemon --no-drop-root --syslog` в фоне, затем `exec cupsd -f`.
|
||||
- ✅ **`cupsd.conf`**: `Browsing Off` → `Browsing On` + `BrowseLocalProtocols dnssd` (бэкап `cupsd.conf.pre-avahi`). Валидность: `/usr/sbin/cupsd -t` → OK.
|
||||
- ✅ **Образ**: собрал `cups-splix-new`, затем пометил **старый образ как `cups-splix-old`** (откат), а новый — как `cups-splix`.
|
||||
- ✅ **Контейнер пересоздан**: `docker stop cups-splix && docker rm cups-splix && docker compose up -d`.
|
||||
|
||||
**Проверка mDNS (всё сошлось):**
|
||||
- `ps aux`: запущены `cupsd` (PID1), `dbus-daemon --system`, `avahi-daemon: running [truenas.local]`.
|
||||
- `ipptool` Get-Printer-Attributes: `printer-dns-sd-name` больше не `no-value` → теперь анонс зарегистрирован.
|
||||
- `avahi-browse -rt -p _ipp._tcp`: на физическом интерфейсе **`;enp3s0;IPv4;`** по адресу **`192.168.2.197;631`** с TXT **`mopria-certified=1.3`**, `pdl=application/pdf,...`, `rp=printers/Samsung_CLX-216x_Series`, `UUID=68e3b8c6-...`.
|
||||
- CUPS по-прежнему слушает `0.0.0.0:631`, принтер `idle/enabled/accepting`.
|
||||
|
||||
**Pitfall (важно):** НЕ использовать **`docker restart cups-splix`** после правки конфига — он убивает avahi-daemon (становится `<defunct>`), dbus тоже пропадает. Подъём ТОЛЬКО полным пересозданием: **`docker stop cups-splix && docker rm cups-splix && docker compose up -d`**, чтобы `entrypoint.sh` выполнился с нуля.
|
||||
|
||||
**Pitfall (compose):** `docker-compose.yml` в cups/ — `-rw------- root:root` (600), **truenas_admin перезаписать не может** (Permission denied) → compose НЕ менял. Это ок: ENTRYPOINT переопределяет `command`, лишний cupsd не стартует (скрипт сам делает `exec cupsd -f`, аргументы `$@` игнорирует). Если потребуется убрать `command` из compose — править через root/UI.
|
||||
|
||||
**Pitfall (бэкап):** `data/ cache/ spool/` под TrueNAS — `drwx------ root:lp` (0700), truenas_admin их напрямую не читает → **бэкап делать ТОЛЬКО через контейнер** (`docker exec ... tar` → `docker cp`), либо через /admin (root).
|
||||
@@ -0,0 +1,78 @@
|
||||
---
|
||||
title: TrueNAS NFS4 ACL repair + cross-container media PUID
|
||||
created: 2026-09-02
|
||||
updated: 2026-09-02
|
||||
type: tech
|
||||
namespace: personal
|
||||
tags: [truenas, nfs4, acl, midclt, arr, radarr, sonarr, jellyfin, transmission, docker]
|
||||
related:
|
||||
- "[[truenas-zfs-panic-recovery]]"
|
||||
- "[[arr-stack-taiga]]"
|
||||
---
|
||||
|
||||
# TrueNAS NFS4 ACL repair + cross-container media PUID
|
||||
|
||||
> Hard-won lessons from the 2026-08-31/09-01/09-02 TrueNAS restore-incident remediation. Mirror of skill `truenas-nfs4-acl-and-arrmultiuser`. Detailed incident log: `family/documents/vault-sync/2026-09-02-restore-privilege-scope.md`.
|
||||
|
||||
## Trigger
|
||||
Any "permission denied" / file not readable / git `loose object ... corrupt` / empty Jellyfin library on **TrueNAS SCALE** (acltype=nfsv4) after a zfs restore, OR wiring Prowlarr/Radarr/Sonarr/Jellyfin/Transmission so container-written files are readable by other containers.
|
||||
|
||||
## Core facts
|
||||
- TrueNAS SCALE uses **NFSv4 ACL**, not plain POSIX. `ls -la` shows a POSIX mask that can mislead.
|
||||
- Read real ACL: `midclt call filesystem.getacl <path>`; write: `midclt call filesystem.setacl`.
|
||||
- **`truenas_admin` is FULL_ADMIN in midclt** → can chown/setacl without passwordless root.
|
||||
- Web UI ACL editing only works on zfs **datasets**, not arbitrary subdirs under one dataset → use midclt/CLI.
|
||||
- Post-restore a tree may be owned by wrong uid (e.g. 921 `transmission`) with files `mode 0000`.
|
||||
|
||||
## The two big gotchas
|
||||
### 1. setacl takes ONE JSON with `path` INSIDE it
|
||||
`midclt call filesystem.setacl /path {…}` → `[EFAULT] Too many arguments (expected 1, found 2)`.
|
||||
Correct form:
|
||||
```
|
||||
midclt call filesystem.setacl '{"path":"/x","uid":950,"gid":950,"acltype":"NFS4","dacl":[...],"options":{...}}'
|
||||
```
|
||||
Jobs run async → returns a job id; verify `midclt call core.get_jobs` (state `SUCCESS`).
|
||||
|
||||
### 2. stripacl does NOT remove DENY; full dacl replacement does
|
||||
`options.stripacl:true` reported `SUCCESS` but left the `owner@ DENY` ACE intact. Only passing a **complete dacl array** works — setacl treats it as a full REPLACE of the ACL.
|
||||
|
||||
## NFSv4 DENY overrides ALLOW (the corrupt-object trap)
|
||||
A file owned by uid 950 carrying `owner@ DENY READ_DATA=True` cannot be read by uid 950 itself. Git then reports `loose object ... corrupt` — this is **ACL, not data damage** (data intact; root reads fine).
|
||||
Diagnostic trap: `git fsck` under **root** is clean, but fetch/push under the owning uid fails → ACL, not corruption.
|
||||
Broken files often show POSIX `mode 40` (`r--------`); healthy objects `750`.
|
||||
|
||||
## Repair / cross-container recipe (linuxserver media stack)
|
||||
Goal: all containers run under ONE uid (950) so transmission→radarr/sonarr→jellyfin all read each other's files.
|
||||
- transmission: add `PUID=950 PGID=950` to env in `docker-compose.yml`. It mounts `storage`→`/mnt/storage`, download-dir `/mnt/storage/Downloads`.
|
||||
- radarr/sonarr/prowlarr/jellyfin compose: add `PUID=950 PGID=950` to each (retain `TZ`).
|
||||
- linuxserver s6 images (Entrypoint `/init`, `/etc/s6-overlay`) honor PUID/PGID natively. Default (unset) = runs **root** → creates root-owned files that 950-services can't read → always set PUID/PGID.
|
||||
- Recreate from proper folder: `cd /mnt/RED_2TB/docker/<svc> && docker compose up -d` (+`--force-recreate` if env changed). Verify daemon uid via `ps aux` inside container (process as `abc`/950 = applied). NOTE `docker exec id` ≠ daemon uid.
|
||||
- Simple datasets: recursive POSIX `chown -R 950:950` + `chmod` under root SUFFICE (ACLs were trivial). Use midclt/ACL only when non-trivial ACEs present (check `filesystem.getacl` → `trivial:true`).
|
||||
- Bare git repo with `owner@ DENY` on objects → full dacl replacement recursively (perms JSON like above).
|
||||
|
||||
### GOTCHA 3 — root dataset traverse (Permission denied despite clean file ACL)
|
||||
After chown-ing all leaf dirs/files to 950, if a service still gets `Permission denied` reading `/storage/Movies/...` (or jellyfin FFmpeg exit 243), check the **root of the dataset** `/mnt/RED_2TB/storage` itself. In the restore it stayed `921:921` with `owner@/group@ ALLOW` but `everyone@ EXECUTE=False`. uid 950 (not owner, not in gid-921-group) falls under `everyone@` → **cannot traverse past the root** into the tree, even though every nested ACL is clean. Fix (root):
|
||||
```bash
|
||||
chown 950:950 /mnt/RED_2TB/storage
|
||||
chmod 750 /mnt/RED_2TB/storage # rwxr-x---: gid 950 = truenas_admin (containers' group) gets r-x traverse
|
||||
```
|
||||
Kernel needs EXEC (traverse) on EVERY path component. Diagnostic via `setpriv --reuid=950 ... ls` shows `Permission denied` on a dir whose `getacl` looks clean → suspect root/parent traverse. `stat` via root shows clean 770 but uid 950 can't ls.
|
||||
|
||||
### GOTCHA 4 — transmission "all torrents No Data Found" after data migration
|
||||
If every transmission torrent shows `error 3: No Data Found` right after a container recreate/pool migration:
|
||||
- Check: `docker exec -u` fine to read? downloadDir & files present? If files ARE there and readable as uid 950, the error is likely **stale from daemon startup while traverse was blocked** (see GOTCHA 3).
|
||||
- `torrent-verify` on a single torrent does NOT clear it. Fix is trivial & non-destructive:
|
||||
```bash
|
||||
docker restart transmission
|
||||
```
|
||||
On restart the daemon re-validates → torrents clear (e.g. **254/255 instantly**). Leftover #1 → Verify Local Data in Web UI.
|
||||
|
||||
## Docker network persistency (per-service compose)
|
||||
- `docker network connect <net> <container>` is LOST on recreate → declare `<net>` in the service's compose `networks:`.
|
||||
- Caddy must co-own a network with its reverse-proxy target. transmission Web UI works because caddy is ALSO in `transmission_default`; radarr↔transmission works because both in `media_net`.
|
||||
- `external: true` networks (media_net/caddy_default) aren't created by compose — if they vanish (pool rebuild), `docker network create media_net`.
|
||||
|
||||
## Containers / uid summary (as of 2026-09-02, TrueNAS "Taiga")
|
||||
- prowlarr/radarr/sonarr/jellyfin: all running, all daemons under **uid 950**, project `arr`.
|
||||
- transmission: PUID/PGID=950, in networks `media_net` + `transmission_default` (both external).
|
||||
- Radarr/sonarr/jellyfin mount `/mnt/RED_2TB/storage` as `/storage` (NOT `/media` as on Kraken) → set radarr root-folder accordingly.
|
||||
@@ -0,0 +1,86 @@
|
||||
# TrueNAS — Восстановление ZFS пула при kernel panic (space map corruption)
|
||||
|
||||
> Создано 2026-08-17. Зеркало скила `truenas-zfs-panic-recovery`.
|
||||
|
||||
## Когда это нужно
|
||||
|
||||
Пул TrueNAS не импортируется и вызывает **kernel panic / boot loop**:
|
||||
```
|
||||
panic - not syncing: zfs: adding existent segment to range tree
|
||||
ZFS: space_map_load / metaslab_activate / zio_dva_allocate → zfs_panic_recover
|
||||
```
|
||||
Это **повреждение space map (метаданных ZFS)**. НЕ обязательно потеря данных, но структура пула повреждена. Read-write импорт паникует, т.к. читает битые space maps.
|
||||
|
||||
## Ключевая идея
|
||||
|
||||
**Read-only import НЕ читает space maps и НЕ паникует** (mav/iXsystems: "read-only imports don't even read space maps"). Стратегия: обойти панику → readonly-импорт → выгрузить данные → пересоздать пул.
|
||||
|
||||
**Пул НЕ «чинится»** — только выгрузка данных и пересоздание.
|
||||
|
||||
## Проверенные шаги (2026-08-17, TrueNAS SCALE 24.10)
|
||||
|
||||
### 1. Загрузка без паники — единственный рабочий способ:
|
||||
|
||||
**Физически отключить все диски проблемного пула** → boot-pool поднимается, паники нет → дошли до shell/WebUI → **воткнуть диски обратно (горячо)** в те же порты.
|
||||
|
||||
**Что НЕ работает (проверено):**
|
||||
- Тюнабели в GRUB `zfs.zfs_recover=1 zfs.zil_replay_disable=1` — не помогли
|
||||
- `rd.break=pre-mount` и `rd.break` — не помогли
|
||||
- `zfsforce=1` — не помогает
|
||||
|
||||
### 2. Readonly-импорт (под root):
|
||||
|
||||
```bash
|
||||
/usr/sbin/zpool import -o readonly=on RED_2TB
|
||||
```
|
||||
→ `Import was successful, but unable to mount some datasets` — это нормально/ожидаемо.
|
||||
|
||||
### 3. Монтирование datasets (2026-08-18: подтверждено под root)
|
||||
|
||||
Если корневая ФС readonly мешает создавать mountpoint-ы (`cannot mount '/RED_2TB': failed to create mountpoint: Read-only file system`) — сначала сделать root ФС rw, затем смонтировать всё:
|
||||
```bash
|
||||
mount -o remount,rw /
|
||||
zfs mount -a
|
||||
```
|
||||
После этого дочерние datasets (`storage`, `backup`, `Photos`, `Edu`, `docker`, `old-bu`, `TimeMachine/guest`, `iocage/*`) видны на `/RED_2TB/*` (все `ro` — readonly; для чтения rsync это ок). Проверка: `df -h /RED_2TB` покажет ~4.6T (НЕ 1.1T родительского), `ls /RED_2TB/storage` не пуст.
|
||||
> ⚠️ Монтирование — **только под root**. Под `truenas_admin` `zfs mount -a` даёт `Insufficient privileges`.
|
||||
|
||||
### 4. Выгрузка:
|
||||
|
||||
```bash
|
||||
rsync -aHAX --info=progress2 /RED_2TB/ /mnt/IRONWOLF/ > /tmp/rsync2.log 2>&1 &
|
||||
```
|
||||
Лучше в tmux. Затем `zpool destroy` + пересоздать пул.
|
||||
|
||||
**⚠️ ВАЖНО (2026-08-18): использовать именно `rsync`, НЕ `zfs send | zfs recv`.** `zfs send` на пуле с повреждённой space map падает (`signal received` / `Bad file descriptor` / `IOT (core dumped)`, exit 1) — ZFS не может прочитать данные на лету при stream-чтении. rsync переживает ошибки чтения отдельных файлов (exit 23) и копирует остальное.
|
||||
|
||||
**⚠️ Почему первая попытка rsync дала только 355G (разгадано 2026-08-18):** дочерние datasets НЕ были смонтированы, поэтому `/RED_2TB/storage` и др. были пустыми mountpoint-дирами; rsync скопировал только ~355G из родительского dataset. **Сначала смонтировать datasets (`zfs mount -a`), потом rsync** — иначе скопируется лишь несколько сотен ГБ.
|
||||
|
||||
**Целевой диск для выгрузки (2026-08-17):** **IronWolf 12TB** подключён к материнке (`sdc`, by-id `WV700FQ5`, 10.9T, свободен/не в пуле) — создай на нём пул-приёмник и копируй туда. Места достаточно (10.9T > 4.6T данных).
|
||||
|
||||
**Что на RED_2TB спасать (структура datasets от 2026-08-17):**
|
||||
- Критично (пользовательские данные): `storage` (3.24T), `backup` (287G), `Photos` (146G), `Edu` (214G), `TimeMachine` (+`guest`, 277G), `old-bu` (65.5G), `openbsd` (10.2G).
|
||||
- Конфиги (если нужно): `docker` (2.98G), `iocage/*` jails (plex, emby, homeassistant, transmission, worker), `ix-apps` (24G).
|
||||
- Служебное не критично: `RED_2TB/.system/*`.
|
||||
- Итого ~4.6T. Для «100% восстановления с правами»: `rsync -aHAX` или `zfs send | zfs recv`.
|
||||
|
||||
### 5. Пул НЕ чинится in-place — только пересоздание
|
||||
|
||||
`zpool attach` (идея зеркала на 2 WD2TB) НЕ выполним в текущем состоянии — attach это write → паника. Всегда: спасти → destroy → recreate.
|
||||
|
||||
## Подводные камни
|
||||
|
||||
- `zpool` не в PATH для zsh-юзеров (`command not found`) — использовать `/sbin/zpool` или `/usr/sbin/zpool`.
|
||||
- `zpool import` требует **root** (`some devices require root privileges`). `truenas_admin` НЕ root, sudo просит пароль. **На конец 2026-08-17 это главный блокер** — для импорта/монтирования/выгрузки нужен root (через WebUI-админ, консоль, или включив `PermitRootLogin` в SSH).
|
||||
- **WD 2TB#1 (`sdd2` simplex-член RED_2TB) сейчас отключён** — чтобы загрузиться без паники его отсоединяли. RED_2TB импортируется без него (mirror-1 жив), но его данные частично недоступны. Учесть при восстановлении.
|
||||
- `zpool import -n RED_2TB` — нелегальный синтаксис без `-F` (`-n` только с `-F`).
|
||||
- **НЕ повторять `import -F` настойчиво** — углубляет риск. Сначала readonly.
|
||||
- `zpool import -f -F -X` НЕ работает для этой паники (TrueNAS forum).
|
||||
- **⚠️ ЛОВУШКА «zfs send -n» (dry-run) НЕ подтверждает права send:** под `truenas_admin` `zfs send -n` возвращал exit 0 без ошибок — обманчиво. Реальный `zfs send` даёт `permission denied`. Дочерние datasets доступны только root (ACL root-only). Не доверять dry-run для проверки прав send.
|
||||
- Данные могут показать `Permission denied` если сами данные повреждены (в тяжёлых случаях — частичное восстановление).
|
||||
- **Проверить RAM** — на non-ECC (P8H77-V) повреждение space map часто от плохой памяти. memtest.
|
||||
- Буквы дисков shift-аются — сверять по by-id/модели, не по буквам.
|
||||
|
||||
## Root cause
|
||||
|
||||
`adding existent segment to range tree` = openzfs #15030 / #13483. Триггер: члены пула отвалились при перетыкании/перезагрузке, либо RAM corruption (non-ECC).
|
||||
@@ -0,0 +1,454 @@
|
||||
---
|
||||
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/<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-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, поэтому делать только для диагностики/отката.
|
||||
|
||||
## ✅ 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)
|
||||
|
||||
Замер пропускной способности каждого 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-звено теперь мёртво)
|
||||
@@ -0,0 +1,332 @@
|
||||
---
|
||||
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: medium
|
||||
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 downgraded 2026-09-02 — payload still dead (корень глубже
|
||||
#6242)
|
||||
---
|
||||
|
||||
# Xray Reverse Tunnel — Kraken ↔ TrueNAS
|
||||
|
||||
> **Статус: НЕ ВНЕДРЕНО (2026-09-02, финал сессии аудита).** Reverse TrueNAS↔Kraken по-прежнему НЕ работает end-to-end. **Выполнен полный downgrade обеих сторон (portal+bridge) до Xray 26.4.25 — это НЕ помогло**: payload по-прежнему мёртв (`Empty reply`/exit 52). ✅ 3x-ui (`vpn.mallexxx`) жив и работает (рабочий Xray-VPN через TrueNAS). ✅ Kraken восстановлен (диск/docker/контейнеры). ⛔ **Остаётся открытым**: reverse-канал portal↔bridge не удерживается постоянным (нет ESTABLISHED :12346), dispatch портала в reverse-out теряется. Подробности+гипотезы: см. секцию «❌ ФАКТИЧЕСКИЙ РЕЗУЛЬТАТ 2026-09-02» ниже. Не трогать `vpn.mallexxx`.
|
||||
> Архитектурное решение: проксировать исходящий трафик локальных клиентов сети 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/<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** — **ИСТИННЫЙ КОРЕНЬ НАЙДЕН (2026-09-02, issue #6242)**. Несмотря на то что фикс `finalRules:[{action:"allow"}]` применён на bridge и Kraken полностью восстановлен (docker active, bridge перезапущен с фиксом, reverse-канал `udp:reverse:0` жив), payload всё равно не проходит: тест временным curl-контейнером в сети `caddy_default` через `xray-reverse-portal:12345` → verbos `Opened SOCKS connection... Empty reply from server`. **Причина: регрессия роутинга VLESS Reverse на BRIDGE-стороне в Xray v26.5+** (bridge на `teddysun/xray:latest` = 26.7.28). Issue #6242 закрыта "not planned" — фикса нет. **Решение/кварк: сдаунгрейд bridge до `teddysun/xray:26.4.25`** (образ существует на Docker Hub), portal-сторона (26.7.28) остаётся. План согласован с Alex, выполнение ждёт команды. См. секцию «✅ 2026-09-02: Kraken восстановлен + ИСТИННЫЙ КОРЕНЬ #6242» ниже.
|
||||
|
||||
## Связанные заметки
|
||||
- [[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-звено теперь мёртво)
|
||||
@@ -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/<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-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-звено теперь мёртво)
|
||||
@@ -86,6 +86,7 @@ confidence: 0.9
|
||||
|
||||
- Home automation (Home Assistant, Zigbee, RPi)
|
||||
- 3D-печать — [[3d-print-wishlist]]
|
||||
- **Сетевые принтеры (домашние):** Samsung CLX-216x (шарится через TrueNAS, адрес `192.168.2.197`) + Samsung M2020 (по AirPrint, дефолт на Mac). Диагностика печати: см. [[personal/tech/mac-print-shared-services]]
|
||||
- **Видеоигры:** игровой ПК собран как TV-приставка (лончер, джойстики, эмуляторы настроены). Играет редко — паттерн накопления без использования. Прогресс: прошёл с Лизой уровень Shovel Knight, запустил Witcher 3 (вводная сцена).
|
||||
- Настолки: Руммикуб, Шакал, Ticket to Ride, Hive, Rush Hour, Диксит
|
||||
- Совместные игры с Лизой — [[games-wishlist]]
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
# Privacy Triage: Apple - CPM Extension Health Pixels
|
||||
|
||||
Status: **DRAFT**
|
||||
|
||||
**Name:** Alex M
|
||||
**Email:** amartemyanov@duckduckgo.com
|
||||
**Objective:** O-E
|
||||
**PR:** [Add PR link]
|
||||
**Project:** https://app.asana.com/1/137249556945/project/1163321984198618/task/1216761517055116?focus=true
|
||||
|
||||
## Pixels
|
||||
|
||||
| Pixel | Trigger | Frequency |
|
||||
| -------------------------------------------------------------------------- | --------------------------------------------------------------------- | --------------- |
|
||||
| `debug_web_extension_cpm_initialization_failed_after_session_restoration` | CPM fails after a restored-page navigation. | Daily |
|
||||
| `debug_web_extension_cpm_initialization_failed_after_tab_crash` | CPM fails on the first eligible navigation after a tab crash. | Daily |
|
||||
| `debug_web_extension_cpm_initialization_failed_after_extension_reload` | CPM fails on the first eligible navigation after an extension reload. | Daily |
|
||||
| `debug_web_extension_cpm_initialization_failed_after_other` | CPM fails after another eligible navigation. | Daily |
|
||||
| `debug_web_extension_cpm_messaging_stuck_session_restoration` | Messaging remains stuck after a restoration-originated failure. | Daily + count, once/episode |
|
||||
| `debug_web_extension_cpm_messaging_stuck_tab_crash` | Messaging remains stuck across attempts associated with a tab crash. | Daily + count, once/episode |
|
||||
| `debug_web_extension_cpm_messaging_stuck_other` | Messaging remains stuck across other independent navigations. | Daily + count, once/episode |
|
||||
| `debug_web_extension_cpm_messaging_recovered_without_extension_reload` | A failed tab or stuck episode recovers without an extension reload. | Daily + count, once/episode |
|
||||
| `debug_web_extension_cpm_messaging_recovered_after_extension_reload` | A failed tab or stuck episode recovers after an extension reload. | Daily + count, once/episode |
|
||||
| `debug_web_extension_cpm_messaging_extension_reload_failed` | CPM still fails after a successful extension reload. | Daily + count, once/episode |
|
||||
|
||||
iOS and macOS send the exact same pixel names. Parameters distinguish `platform=ios|macos` and `form_factor=phone|tablet|desktop`.
|
||||
`appVersion` is included; macOS also includes `pixelSource` and `channel`.
|
||||
|
||||
## Detection Rules
|
||||
|
||||
- Check only finished, current, main-frame HTTP(S) document navigations after a grace period. A failure means the extension is loaded and the dashboard remains `.waiting`; `cpmStage` is diagnostic data, not part of detection.
|
||||
- A redirected restored-page navigation remains classified as session restoration.
|
||||
- After restoration, any independent eligible document navigation can be the next attempt: reload, typed URL, link, new-tab navigation, or a real back/forward load.
|
||||
- Redirects do not count separately. Same-document, failed, non-HTTP(S), and BFCache navigations do not count when CPM is not expected to initialize again.
|
||||
- A tab crash marks only the next eligible navigation in that tab.
|
||||
- A successful extension reload marks only the next eligible CPM attempt.
|
||||
- `stuck` keeps the reason of the first initialization failure; a later failure does not replace it.
|
||||
- Any successful CPM initialization breaks the failure sequence. Recovery is reported when that success belongs to a previously failed tab or follows a stuck state.
|
||||
|
||||
## Privacy Questions
|
||||
|
||||
**Do the pixels use transparent names?**
|
||||
Yes.
|
||||
|
||||
**Do they share parameters with other pixels?**
|
||||
Yes. They use `platform` and `form_factor` to combine both apps under the same pixel names.
|
||||
|
||||
**Could the parameters link pixels to the same user?**
|
||||
No. Both parameters are coarse enums and contain no identifier.
|
||||
|
||||
**Do the pixels include a URL or search query?**
|
||||
No. They also exclude hostnames, page titles, tab IDs, document IDs, navigation types, errors, and CPM rules.
|
||||
|
||||
**Are the pixels temporary?**
|
||||
The session-restoration and post-crash/reload pixels are diagnostics. The stuck-state and recovery pixels are permanent health monitoring.
|
||||
|
||||
**Why are the permanent pixels needed?**
|
||||
To measure how often CPM messaging becomes stuck and whether extension reload recovers it.
|
||||
|
||||
**Do any parameters or suffixes fall outside the standard criteria?**
|
||||
`platform` and `form_factor` are explicit enum parameters used instead of platform-specific pixel names.
|
||||
|
||||
**Do the pixels fire on sensitive user events?**
|
||||
No. They report only CPM extension health states.
|
||||
|
||||
**Can occurrences be tied to the same user or a small group?**
|
||||
No. There is no correlation identifier or browsing data.
|
||||
|
||||
**Does this meet the self-service criteria?**
|
||||
Yes.
|
||||
Reference in New Issue
Block a user