diff --git a/Untitled 1.md b/Untitled 1.md
deleted file mode 100644
index e69de29b..00000000
diff --git a/Untitled.md b/Untitled.md
deleted file mode 100644
index e69de29b..00000000
diff --git a/family/documents/vault-sync/2026-08-31-syncthing-truenas-incident.md b/family/documents/vault-sync/2026-08-31-syncthing-truenas-incident.md
new file mode 100644
index 00000000..b37cefff
--- /dev/null
+++ b/family/documents/vault-sync/2026-08-31-syncthing-truenas-incident.md
@@ -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]] — основная документация по этой схеме
diff --git a/family/documents/vault-sync/2026-09-02-hermes-taiga-crashloop.md b/family/documents/vault-sync/2026-09-02-hermes-taiga-crashloop.md
new file mode 100644
index 00000000..6c685038
--- /dev/null
+++ b/family/documents/vault-sync/2026-09-02-hermes-taiga-crashloop.md
@@ -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 (решена)
diff --git a/family/documents/vault-sync/2026-09-02-restore-privilege-scope.md b/family/documents/vault-sync/2026-09-02-restore-privilege-scope.md
new file mode 100644
index 00000000..e447379b
--- /dev/null
+++ b/family/documents/vault-sync/2026-09-02-restore-privilege-scope.md
@@ -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_<дата>/.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 \
+ '{"uid":950,"gid":950,"dacl":[<эталон-ACE obsidian>],"options":{"recursive":true,"traverse":true,"stripacl":false}}'
+ ```
+3. **Verify**: все каталоги → uid 950; тест `git --git-dir=/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` у сервисов** → при подъёме будет дефолт-сеть `_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 = `) → `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 ` вываливалась `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":[, ],"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`)
diff --git a/family/how-to/arr-stack-taiga.md b/family/how-to/arr-stack-taiga.md
index 8064641a..96703f1e 100644
--- a/family/how-to/arr-stack-taiga.md
+++ b/family/how-to/arr-stack-taiga.md
@@ -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.
+
diff --git a/family/how-to/hermes-docker-kraken.md b/family/how-to/hermes-docker-kraken.md
index af9290cf..c710ec88 100644
--- a/family/how-to/hermes-docker-kraken.md
+++ b/family/how-to/hermes-docker-kraken.md
@@ -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@`.
+3. Закрытый ключ на хосте **обязан быть 600**: `ssh kraken@ "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@ "echo OK && hostname" # доступен ли хост
+ssh kraken@ "sudo docker ps --filter name=hermes-kraken --format '{{.Names}} {{.Status}}'"
+# изнутри контейнера на хост (loopback алиас kraken-host)
+ssh kraken@ "sudo docker exec hermes-kraken ssh -o ConnectTimeout=5 kraken-host 'echo HELLO'"
+# verbose — какие конфиги читает SSH
+ssh kraken@ "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@ "sudo docker exec hermes-kraken getent passwd 1000" # uid 1000 в passwd?
+ssh kraken@ "sudo docker exec hermes-kraken ls -la /opt/data/.ssh/id_ed25519"
+ssh kraken@ "sudo docker exec hermes-kraken cat /opt/data/.ssh/config"
+ssh kraken@ "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
diff --git a/family/how-to/home-automation.md b/family/how-to/home-automation.md
index 18f1a19a..f064665d 100644
--- a/family/how-to/home-automation.md
+++ b/family/how-to/home-automation.md
@@ -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 не менялись.)
+
## Карта регистров контроллера вентиляторов
```
diff --git a/family/how-to/kraken-access.md b/family/how-to/kraken-access.md
index 2c897695..ec1c26a3 100644
--- a/family/how-to/kraken-access.md
+++ b/family/how-to/kraken-access.md
@@ -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]]
+
diff --git a/family/how-to/kraken-network.md b/family/how-to/kraken-network.md
index fa702dc2..667f66f6 100644
--- a/family/how-to/kraken-network.md
+++ b/family/how-to/kraken-network.md
@@ -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
diff --git a/family/how-to/obsidian-sync.md b/family/how-to/obsidian-sync.md
index 5d890e96..f57a3be6 100644
--- a/family/how-to/obsidian-sync.md
+++ b/family/how-to/obsidian-sync.md
@@ -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) |
diff --git a/family/how-to/red2tb-dataset-map.md b/family/how-to/red2tb-dataset-map.md
new file mode 100644
index 00000000..8d597fcd
--- /dev/null
+++ b/family/how-to/red2tb-dataset-map.md
@@ -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]] (общие данные доступа).
diff --git a/family/how-to/samsung.md b/family/how-to/samsung.md
index 24819f98..1a33f809 100644
--- a/family/how-to/samsung.md
+++ b/family/how-to/samsung.md
@@ -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
diff --git a/family/how-to/syncthing-truenas-android.md b/family/how-to/syncthing-truenas-android.md
index 61631142..b1292f5c 100644
--- a/family/how-to/syncthing-truenas-android.md
+++ b/family/how-to/syncthing-truenas-android.md
@@ -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
diff --git a/family/how-to/truenas-access.md b/family/how-to/truenas-access.md
index 9652c40f..9272cf54 100644
--- a/family/how-to/truenas-access.md
+++ b/family/how-to/truenas-access.md
@@ -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)
diff --git a/family/how-to/truenas-infrastructure.md b/family/how-to/truenas-infrastructure.md
index e05d5a98..a8745eb8 100644
--- a/family/how-to/truenas-infrastructure.md
+++ b/family/how-to/truenas-infrastructure.md
@@ -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/`.
+> **Контейнеры запускались через `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, ПЕРЕСМОТРЕНО:** Между этими двумя сетями нет 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//`. Модель — **не один общий 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//...`), а также пишет в HA.
+2. **Mappings (виртуальные slaves для ZONT)** — подставляет на **slave 101/102/103** (регистр 100) значения temperature от 485-датчиков: Dining→101, Kids→102, Bedroom→103. **ZONT (Modbus master) опрашивает 101/102/103 как свои внешние датчики температуры.** Есть также wifi-термостат как slave 100 (`sensor.0xa4c13862d39377e6_temperature`) и Socket 1 = slave 101 через switch (обратим внимание: 101 занят и Dining temp — переиспользуется на одном slave с разными функциями; сверить в config.yml).
+3. Также через mbusd может работать с AT2 вентиляции.
+
+**Если modbus-bridge не слушает `ttyZONT`** (упал/не запущен) → ZONT не получает ответ на запросы slave 101/102/103 → в интерфейсе ZONT 485-датчики отображаются **«недоступные»**.
+
+### Проблема modbus-bridge/mbusd после рестарта TrueNAS (гонка с udev)
+
+**Симптом:** после перезагрузки TrueNAS `/dev/ttyZONT` и `/dev/ttyVent` присутствуют (`ttyZONT`→ttyUSB1, `ttyVent`→ttyUSB0, создаются init script id=1), НО контейнеры `modbus-bridge`/`mbusd` упали на старте и не перезапустились; 485-датчики в ZONT «недоступные».
+
+**Причина:** docker стартует раньше udev → при `start` контейнера устройство ещё не существует → падение ДО запуска процесса:
+```
+docker inspect --format '{{.State.Error}}'
+error gathering device information while adding custom device "/dev/ttyZONT": no such file or directory
+# ExitCode 128 / 255, RestartCount=0
+```
+`restart: unless-stopped` такой отказ **не подхватывает** (RestartCount=0), и задержка внутри entrypoint не поможет (device mount происходит до старта процесса).
+
+**Ручной фикс:** `docker start modbus-bridge mbusd` (после того как симлинки созданы).
+
+**Защита от рецидива (план, НЕ внедрён, ждёт OK Alex):** `family/plans/zont-modbus-bridge-udev-race-protection.md` — POSTINIT init script `/mnt/RED_2TB/system/start-modbus.sh`, который ждёт появления `ttyZONT`/`ttyVent` (≤25с) и делает `docker start modbus-bridge mbusd`.
### USB device aliases
@@ -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]] — система бэкапов
diff --git a/family/how-to/truenas-infrastructure.md.bak-per-user-20260902-1229 b/family/how-to/truenas-infrastructure.md.bak-per-user-20260902-1229
new file mode 100644
index 00000000..3e2ea34c
--- /dev/null
+++ b/family/how-to/truenas-infrastructure.md.bak-per-user-20260902-1229
@@ -0,0 +1,511 @@
+# TrueNAS — инфраструктура
+
+> Обновлено: 2026-09-02 (vpn.mallexxx:443 = РАБОЧИЙ Xray-сервер, проверено end-to-end; vless-proxy outbound мёртв)
+
+> ## ⚠️ ПРИОРИТЕТ 2026-09-01: VPS qentra.top УДАЛЁН → vless-proxy и сетевые туннели сломаны
+> - **VPS `91.207.28.205` больше НЕ существует** (вся его Xray/OpenVPN/WG-инфраструктура утрачена). Подробно: [[family/how-to/vps-qentra]].
+> - **Контейнер `vless-proxy`** (teddysun/xray): inbound SOCKS `0.0.0.0:1080` + HTTP `0.0.0.0:1081`, но **outbound ⇒ мёртвый `v.qentra.top:443`** (VLESS+WS+TLS, path `/qentra`, id `2D9F24C4-21FE-4784-9843-F11C384DA67A`). ⇒ Hermes-Taiga (ходит через `vless-proxy:1080`) **сейчас БЕЗ рабочего прокси**. **Уточнено 2026-09-02:** `v.qentra.top` по-прежнему ресолвится, но в **Cloudflare IP** (`104.21.54.239`, `2606:4700:...`) — DNS-запись на qentra.top осталась в Cloudflare, хотя VPS сам удалён; origin'а за ней нет, поэтому трафик через прокси не идёт. Контейнер `vless-proxy` сам ЖИВ (Up 8 days), путь через его SOCKS наружу не проходит.
+> - **⚠️ На корневом `mallexxx.duckdns.org:443` НЕ Xray**, а обычный **Caddy/nginx с валидным Let's Encrypt сертификатом** (проверено `openssl s_client` 2026-09-01). **НО на поддомене `vpn.mallexxx.duckdns.org:443` — РАБОЧИЙ Xray-сервер** (см. раздел `xray-admin` ниже, проверено end-to-end 2026-09-02).
+> - **Наружу открыты только 22 (SSH) и 443 (HTTPS/TLS)** с Kraken; `8443/8964/8080/9000` closed.
+> - **План замены** (выход клиентов сети TrueNAS через Kraken, Xray reverse — НЕ внедрён): [[personal/tech/xray-reverse-tunnel-kraken-truenas]].
+
+> ## ✅ СТАТУС на 2026-08-25: пул ONLINE, docker поднят, почти все контейнеры Up
+> **Пул RED_2TB пересоздан (2026-08-21) и работает:** `zpool status` ONLINE, rsync возврата данных завершён, `/mnt/RED_2TB/` смонтирован.
+> **Docker: ПОДНЯТ на 2026-08-25.** Почти все контейнеры Up (zigbee2mqtt, webdav, vless-proxy, homeassistant, caddy, transmission, syncthing, mosquitto, nodered, immich*, gitea, filebrowser, portainer*, hermes-taiga и др.). ✅ **cups-splix поднят 2026-08-26** — образ собран заново (`docker build -t cups-splix .`), контейнер запущен `docker compose up -d`, порт 631 открыт, принтер `Samsung_CLX-216x_Series` активен (USB `04e8:3425`). Причина былого падения: образ локальный, потерян при восстановлении пула (`.ix-apps` не переносился), вручную не пересобирали. Рецепт — ниже, раздел «Печать / cups-splix». Ещё не подняты (проверить при надобности): inpxer/inpx-web/arr/ser2net.
+> **⚠️ Известная проблема modbus-bridge/mbusd — гонка с udev при рестарте TrueNAS:**
+> - После перезагрузки docker стартует раньше udev, поэтому `/dev/ttyZONT` и `/dev/ttyVent` на момент старта контейнеров ещё не существуют.
+> - Контейнеры с `devices: /dev/ttyZONT:...` падают на `start` с `error gathering device information while adding custom device "/dev/ttyZONT": no such file or directory` (ExitCode 128/255, RestartCount=0).
+> - `restart: unless-stopped` НЕ перезапускает такой контейнер (отказ до старта процесса).
+> - Следствие: modbus-bridge не отвечает на шине → 485-датчики в ZONT отображаются **«недоступные»**.
+> - Ручной фикс: `docker start modbus-bridge mbusd` (после готовности tty-симлинков).
+> - Защита от рецидива (план, НЕ внедрён — ждёт OK Alex): `family/plans/zont-modbus-bridge-udev-race-protection.md` — POSTINIT init script с ожиданием симлинков + `docker start`.
+> **⚠️ ДРУГОЕ (открытое):** пул `DEST` (IronWolf) на 2026-08-24 `DEGRADED` — разобраться, почему (отвалился mirror-член). TimeMachine (~277G) не возвращён (бэкапы macOS, вероятно не нужен — решение Alex не подтверждено). SSH с Mac по 192.168.2.197 нестабилен — использовать `mallexxx.duckdns.org`.
+
+> ## 🔒 ИСТОРИЯ: статус до восстановления (2026-08-24)
+> **Пул RED_2TB пересоздан и УЖЕ зареган в TrueNAS** — `zpool status` ONLINE (`mirror-0{sdc,sdf}`+`mirror-1{sde,sdd}`), `midclt call pool.query` id=1 RED_2TB ONLINE. rsync возврата данных ЗАВЕРШЁН (storage 3.29T, immich 353G, backup 287G, Edu 214G, Photos 146G, old-bu 65G, docker, docker.bak, system — все смонтированы).
+> **`.ix-apps` датасет (docker storage, был 24G) НЕ перенесён** — rsync шёл из `/mnt/RED_2TB/*` и не включал монтируемый в `/mnt/.ix-apps` системный датасет. Образы = кеш → перекачаются из registry сами; конфиги целы в `/mnt/RED_2TB/docker/`.
+> **Контейнеры запускались через `docker-compose`, НЕ через TrueNAS Apps (TrueCharts/Custom App).** daemon.json `data-root:/mnt/.ix-apps/docker`. `.ix-apps` = просто data-root docker, не TrueNAS Apps.
+> **⚠️ ДРУГОЕ (проверено 2026-08-24):** пул `DEST` (IronWolf, источник спасения) на момент проверки `DEGRADED` в `zpool list` — стоит разобраться, почему (вероятно отвалился mirror-член). Также SSH с Mac к TrueNAS по 192.168.2.197 нестабилен (`Connection reset/reset by peer`, `kex_exchange_identification read`), возможен конфликт сессий при активном входе на консоль — использовать `mallexxx.duckdns.org` и ретраи.
+
+> ## ⚠️ СТАТУС на 2026-08-21: пул RED_2TB — данные СПАСЕНЫ, пул OFFLINE, пересоздаём
+> **Выгрузка успешно завершена** (подтверждено Alex): данные RED_2TB (4.56T) на IronWolf (пул `DEST`, `/mnt/IRONWOLF`). **Пул RED_2TB — статус OFFLINE** в БД TrueNAS, НЕ импортирован. Конфиги docker (caddy, transmission, HA, immich и т.д.), Obsidian vault и git-репо спасены на `/mnt/IRONWOLF` (`system/`, `docker.bak/`, `docker/`, `storage/obsidian`, `storage/git`).
+> **ПЛАН (следующий шаг):** пересоздать пул RED_2TB с новой топологией `mirror {sdc,sdf}` + `mirror {sde,sdd}` (включаем WD2TB#2 зеркалом к WD2TB#1). Команды `zpool labelclear` + `zpool create` — в `family/how-to/truenas-sata-ports-and-zfs-pools.md` (раздел «Пересоздание пула 2026-08-21»). Затем вернуть данные rsync с IronWolf и восстановить инфраструктуру.
+> **ПРОТОКОЛ ПОВРЕЖДЕНИЯ (история):** пул паниковал на rw-импорте (`adding existent segment to range tree`, повреждённая space map). Работал только `zpool import -o readonly=on`. In-place починки нет (mav/iXsystems) — только спасать данные и пересоздавать. Полный рецепт — в `family/how-to/truenas-sata-ports-and-zfs-pools.md`.
+
+## Доступ
+
+- **Host (external):** `mallexxx.duckdns.org` (DuckDNS) — **единственный способ** SSH/API из 192.168.1.x
+- **SSH:** `truenas_admin@mallexxx.duckdns.org -i ~/.ssh/id_rsa`
+- **Web UI:** http://truenas.mallexxx.duckdns.org
+- **Portainer:** https://portainer.mallexxx.duckdns.org
+- **Host (local network):** `192.168.2.197` — ⚠️ ИСПОЛЬЗОВАТЬ `ssh truenas_admin@mallexxx.duckdns.org`. НЕ ИСПОЛЬЗОВАТЬ локальный IP для SSH доступа!
+ - ⚠️ Eagle (Mac, 192.168.1.x) и Kraken (192.168.1.15) находятся в **другой подсети**
+ - ⚠️ Кра́кен и TrueNAS — **разные сети** (192.168.1.x vs 192.168.2.x). Доступ с Кракена на TrueNAS по локальному IP **не работает**
+
+## Пользователи и группы (ключевые)
+
+| uid | Имя | gid | Назначение |
+|-----|-----|-----|------------|
+| 950 | truenas_admin | 950 | SSH-пользователь, управление docker |
+| 911 | transdamon | 911 | Процесс Transmission внутри контейнера |
+| 921 | transmission | 921 | Старый пользователь (не используется контейнером) |
+| 3000 | nas_users | 3000 | Общая группа доступа к NAS |
+
+## Структура папок
+
+```
+/mnt/RED_2TB/
+├── docker/ ← конфиги docker-контейнеров (бэкапятся → mailru-crypt:)
+│ ├── caddy/
+│ ├── filebrowser/
+│ ├── ha/ ← Home Assistant
+│ ├── hermes/ ← Hermes-Taiga
+│ ├── homeassistant/
+│ ├── immich/
+│ ├── inpx-web/
+│ ├── inpxer/
+│ ├── mbusd/
+│ ├── modbus-bridge/
+│ ├── mosquitto/
+│ ├── nodered/
+│ ├── portainer/
+│ ├── python/
+│ ├── rclone/
+│ ├── ser2net/
+│ ├── transmission/ ← конфиг Transmission (settings.json, torrents, resume...)
+│ ├── vless-proxy/
+│ ├── watchtower/
+│ ├── webdav/
+│ └── zigbee2mqtt/
+├── storage/
+│ ├── Downloads/ ← данные торрентов (монтируется в контейнер как /mnt/storage)
+│ │ ├── transmission/ ← старый путь конфига (больше не используется)
+│ │ └── [медиафайлы]
+│ └── obsidian/ ← vault (read-only для hermes-taiga)
+├── backup/ ← ручные бэкапы (бэкапятся → mailru-crypt:)
+│ └── transmission-config/ ← снапшот конфига от 2026-04-30
+├── Photos/ ← фото (бэкапятся → mailru:Photos/Photos)
+├── old-bu/ ← старый архив (бэкапятся → mailru:Photos/old-bu)
+└── immich-photos-upload/ ← библиотека Immich (бэкапятся → mailru:Photos/immich)
+```
+
+## NFSv4 ACL — важно
+
+TrueNAS использует **NFSv4 ACL**, а не стандартный POSIX chmod/chown.
+- `ls -la` показывает `----------` даже если ACL есть → всегда проверять через `midclt call filesystem.getacl `
+- Добавить запись: `midclt call filesystem.setacl '{...}'`
+- `truenas_admin` не имеет passwordless sudo → root-операции только через midclt или TrueNAS UI
+
+## Docker-контейнеры
+
+| Контейнер | Image | Порт | Домен |
+|-----------|-------|------|-------|
+| transmission | linuxserver/transmission:latest | 9091, 51413 | transmission.mallexxx.duckdns.org |
+| hermes-taiga | hermes-taiga:latest | — | — |
+| vless-proxy | teddysun/xray:latest | — | — |
+| filebrowser | filebrowser/filebrowser:latest | — | — |
+| webdav | hacdias/webdav:latest | — | webdav.mallexxx.duckdns.org |
+| homeassistant | home-assistant:stable | 8123 | mallexxx.duckdns.org |
+| immich-server | immich-app/immich-server:release | 2283 | immich.mallexxx.duckdns.org |
+| immich-postgres | tensorchord/pgvecto-rs:pg14-v0.2.0 | — | — |
+| immich-redis | redis:7 | — | — |
+| nodered | nodered/node-red:latest | 1880 | nodered.mallexxx.duckdns.org |
+| mosquitto | eclipse-mosquitto:latest | — | — |
+| caddy | caddy:latest | 80, 443 | reverse proxy для всего |
+| rclone | rclone/rclone:latest | — | бэкап по cron |
+| portainer | portainer/portainer-ce:latest | 9000 | portainer.mallexxx.duckdns.org |
+| watchtower | containrrr/watchtower:latest | — | авто-обновление образов |
+| inpxer | ghcr.io/hedger/inpxer:latest | 18080 | books.mallexxx.duckdns.org |
+| nodered | node-red:latest | 1880 | nodered.mallexxx.duckdns.org |
+| zigbee2mqtt | koenkk/zigbee2mqtt:latest | — | — |
+| mbusd | 3cky/mbusd:latest | — | Modbus |
+| modbus-bridge | modbus-bridge | — | — |
+| cups-splix | cups-splix | — | принтер |
+| xray-admin | ghcr.io/mhsanaei/3x-ui:latest | 2053 (панель), 10095 (vless-ws), 443 (sub) | vpn-panel.mallexxx.duckdns.org, vpn.mallexxx.duckdns.org |
+| xray-reverse-portal | teddysun/xray:latest | 12345 (SOCKS), 12346 (VLESS-TCP REALITY interconn) | — (см. `personal/tech/xray-reverse-tunnel-kraken-truenas.md`) |
+
+### cups-splix — принтер Samsung CLX-216x (✅ поднят 2026-08-26; ✅ mDNS-фикс 2026-08-31 завершён)
+
+**Статус:** контейнер работает, принтер `Samsung_CLX-216x_Series` **idle / enabled / accepting**. CUPS слушает `0.0.0.0:631` (host-сеть). mDNS-анонс **включён** — штатная Android print service теперь видит принтер по mDNS (подробно: [[mac-print-shared-services]]). См. ниже раздел «✅ mDNS/AirPrint анонс принтера».
+
+Папка: `/mnt/RED_2TB/docker/cups/` → `Dockerfile`, `entrypoint.sh`, `docker-compose.yml`, `data/`→`/etc/cups`, `cache/`→`/var/cache/cups`, `spool/`→`/var/spool/cups`, `uld/`, бэкап `backup_20260831-003619.tar.gz`.
+
+- **Image:** `cups-splix` (локальная сборка из Dockerfile; старый образ сохранён как `cups-splix-old` для отката)
+- **Dockerfile** (debian:12-slim): `cups-daemon cups-client cups-common printer-driver-splix avahi-daemon avahi-utils dbus usbutils nano procps`; `cupsadmin:admin` (группа lpadmin); `COPY entrypoint.sh`; `EXPOSE 631`; `ENTRYPOINT ["/entrypoint.sh"]`
+- **entrypoint.sh:** `dbus-daemon --system --fork` → `avahi-daemon --no-drop-root --syslog` (фон) → `exec cupsd -f`
+- **compose:** `image: cups-splix`, `network_mode: host`, `privileged: true`, volume `/dev/bus/usb:/dev/bus/usb`, restart `unless-stopped` (содержит устаревший `command: [cupsd -f]`, но ENTRYPOINT переопределяет — правится только через root/UI, файл 600 root)
+- **Сборка/поднятие (⚠️ полное пересоздание, НЕ `docker restart`):**
+```bash
+cd /mnt/RED_2TB/docker/cups/
+docker build -t cups-splix-new .
+docker stop cups-splix && docker rm cups-splix
+docker tag cups-splix-new cups-splix && docker tag cups-splix cups-splix-old 2>/dev/null
+docker compose up -d
+```
+
+> Полный разбор и симптом «телефон не видит принтер»: [[mac-print-shared-services]]
+
+### Инвентарь compose-файлов по папкам (проверено 2026-08-24)
+
+Каждый контейнер = своя папка `/mnt/RED_2TB/docker//`. Модель — **не один общий compose, а per-service compose** (контейнеры поднимались `docker compose up -d` из своей папки / `docker run`).
+
+**✅ Есть `docker-compose.yml` (поднимаются `docker compose -f ... up -d`)** — 22 шт:
+arr, caddy, cups, filebrowser, gitea, hermes, immich, inpx-web, inpxer, library, mbusd, mosquitto, nodered, portainer-mcp, portainer, rclone, ser2net, syncthing, transmission, vless-proxy, watchtower, **xray-admin (3x-ui, добавлен 2026-09-01)**
+
+**⚠️ НЕТ compose-файла — только конфиг (восстанавливать вручную, параметры из доки ниже):**
+- **ha** — Home Assistant: `/mnt/RED_2TB/docker/ha/` (automations.yaml). Образ `ghcr.io/home-assistant/home-assistant:stable`, порт `8123`, volume `/mnt/RED_2TB/docker/ha` → `/config`.
+- **webdav** — `/mnt/RED_2TB/docker/webdav/` (config.yml). Образ `hacdias/webdav:latest`, домен webdav.mallexxx.duckdns.org.
+- **modbus-bridge** — `/mnt/RED_2TB/docker/modbus-bridge/` (config.yml + modbus_ha_bridge.py). Образ `modbus-bridge` (локальная сборка из репо `HA-ZONT-Modbus`). Volumes: config.yml → `/app/config.yml` (ro), modbus_ha_bridge.py → `/app/modbus_ha_bridge.py` (ro).
+- **zigbee2mqtt** — `/mnt/RED_2TB/docker/zigbee2mqtt/` (configuration.yaml). Образ `koenkk/zigbee2mqtt:latest`, работает через mosquitto.
+- **homeassistant** — в доке упомянут как отдельный контейнер (порт 8123, volume → /config); папка `docker/homeassistant/` есть, но название контейнера в таблице `homeassistant`, а папка конфига HA фактически `ha/`. При восстановлении сверить, какой реально используется.
+
+### Порядок восстановления docker-стека (зависимости)
+
+1. **docker engine:** `systemctl enable --now docker` (после создания data-root, см. шапку). Проверка: `docker info | grep -iE "Server Version|Docker Root Dir"`.
+2. **Инфраструктура/сеть:** mosquitto (MQTT) → zigbee2mqtt (нужен mosquitto) → nodered (MQTT) → caddy (прокси, тянет все домены) → vless-proxy (SOCKS5 для hermes).
+3. **Умный дом:** mbusd (Modbus TCP:502) → modbus-bridge (через mbusd) → ha (homeassistant, нужен caddy для домена).
+4. **Медиа/хранилище:** transmission (нужен caddy) → arr (radarr/sonarr/prowlarr) → inpxer (books), inpx-web, library → rclone, syncthing, filebrowser, webdav, gitea.
+5. **Сервисы/свои:** hermes-taiga (нужен vless-proxy), portainer, portainer-mcp, watchtower, cups, ser2net.
+6. **Проверка:** `docker ps`. HA: `docker exec homeassistant python -m homeassistant --script check_config --config /config`.
+
+### Transmission — детали
+- **Config:** `/mnt/RED_2TB/docker/transmission/` (монтируется как `/config`; внутри `/config/docker-compose.yml`)
+- **Данные:** `/mnt/RED_2TB/storage` (монтируется как `/mnt/storage`)
+- **Download dir:** `/mnt/storage/Downloads`
+- **UID/GID:** ⚠️ **по факту работает как ROOT (uid 0)**, НЕ 911/911. Причина: в `/mnt/RED_2TB/docker/transmission/docker-compose.yml` **НЕ задан `PUID`/`PGID`** → linuxserver `/init` (s6-overlay) оставляет контейнер root (подтверждено `docker exec transmission id` → root). Пользователь `transdamon`/911 (док) — это владелец конфига на хосте (`drwx------ 911 911`), но НЕ процесс внутри контейнера.
+ - **Зачем важно:** root-трансмишен пишет файлы как root и переживает права 0000 медиа → это причина, почему он "работает" на сломанных после restore папках. Но для pipeline с jellyfin/radarr (не-root) root-создаваемые файлы барьер.
+ - **План фикса (Вариант A, одобрен 2026-09-02):** добавить `PUID=950 PGID=950` и пересоздать контейнер → работает под `truenas_admin`. План: `family/documents/vault-sync/2026-09-02-restore-privilege-scope.md` §5.
+- **RPC whitelist:** `172.16.6.*`
+- **Web:** https://transmission.mallexxx.duckdns.org
+- **Порты:** 9091 (RPC/web), 51413 (TCP/UDP peers)
+
+### Caddy — домены
+| Домен | → |
+|-------|---|
+| mallexxx.duckdns.org | Home Assistant :8123 |
+| transmission.mallexxx.duckdns.org | Transmission :9091 |
+| immich.mallexxx.duckdns.org | Immich :2283 |
+| nodered.mallexxx.duckdns.org | Node-RED :1880 |
+| webdav.mallexxx.duckdns.org | WebDAV |
+| books.mallexxx.duckdns.org | Inpxer :18080 🔒 basicauth (user: books-admin) |
+| library.mallexxx.duckdns.org | library-app :8080 🔒 basicauth (user: books-admin) |
+| portainer.mallexxx.duckdns.org | Portainer :9000 |
+| truenas.mallexxx.duckdns.org | TrueNAS UI :80 |
+| cam.mallexxx.duckdns.org | Камера :8090 |
+| docs.mallexxx.duckdns.org | Docs :8000 |
+| **vpn-panel.mallexxx.duckdns.org** | **3x-ui панель :2053** (добавлен 2026-09-01) |
+| **vpn.mallexxx.duckdns.org** | **Xray VLESS-WS (путь /vless) → xray-admin:10095** (добавлен 2026-09-01) |
+
+### `xray-admin` — 3x-ui панель (Xray server, добавлена 2026-09-01)
+
+**Цель:** 3x-ui frontend для Xray-reverse туннеля Kraken↔TrueNAS (выход клиентов сети TrueNAS через Kraken). Подробно: [[personal/tech/xray-reverse-tunnel-kraken-truenas]].
+
+| Параметр | Значение |
+|----------|----------|
+| Папка | `/mnt/RED_2TB/docker/xray-admin/` |
+| Контейнер | `xray-admin` (имя важно — Caddyfile резолвит по нему) |
+| Образ | `ghcr.io/mhsanaei/3x-ui:latest` (3.7.0, Xray 26.7.28) |
+| Volume | `/mnt/RED_2TB/docker/xray-admin:/etc/x-ui` (там `x-ui.db`) |
+| Сеть | `caddy_default` (внешняя) |
+| Панель | `https://vpn-panel.mallexxx.duckdns.org/` (Caddy → xray-admin:2053) |
+| Inbound | `vless-ws` port `10095`, tag `in-10095-tcp`, path `/vless`, host `vpn.mallexxx.duckdns.org`, client id `ce320965-6956-4759-84bb-7cb71cfc6252` (user1) |
+| Sub-сервер | `[::]:443` (path /sub), панель `[::]:2053` |
+| Env | `TZ=Asia/Novosibirsk`, `PUID=950`, `PGID=950` |
+| Ports (host) | `54321:54321` (не используется панелью — внутри панель на 2053, можно убрать) |
+
+**Статус (2026-09-01):** контейнер **Up**, панель HTTP 200. Reverse **портал** развёрнут отдельным контейнером `xray-reverse-portal` (см. ниже). 3x-ui поддерживает reverse (`clientReverseTags`).
+
+**✅ ПРОВЕРЕНО РАБОТАЕТ (2026-09-02): `vpn.mallexxx.duckdns.org:443` — это ФУНКЦИОНАЛЬНЫЙ Xray-СЕРВЕР, НЕ только reverse-frontend.** Проверено end-to-end юзером с Mac. Ключевые факты с живой машины:
+- Контейнеры `xray-admin` (Up 21h) и `caddy` (Up 20h) оба живы. Панель `vpn-panel` → HTTP 200. TCP `vpn.mallexxx.duckdns.org:443` снаружи открыт.
+- **Inbound `in-10095-tcp`** (реальный конфиг из `bin/config.json`, Xray 26.7.28): VLESS-WS, `security: none`, WS path `/vless`, host `vpn.mallexxx.duckdns.org`.
+ - **client id:** `ce320965-6956-4759-84bb-7cb71cfc6252` (email `user1`)
+- **Outbound:** `freedom`/`direct` — сервер имеет **СОБСТВЕННЫЙ выход в интернет** через TrueNAS (не через Kraken!). routing: geoip:private + bittorrent → blocked.
+- **Тест с Mac** (временный xray-клиент в docker): VLESS+WS через `vpn.mallexxx.duckdns.org:443` → HTTP 200, выходной IP `90.189.160.148` (TrueNAS). Сервер полностью рабочий.
+- **⚠️ Так и твой клиент должен подключаться:** TLS терминирует Caddy на 443, inbound `security: none` → в конфиге КЛИЕНТА `network: ws`, TLS поверх на `vpn.mallexxx.duckdns.org` (**НЕ включать двойной TLS внутрь WS**).
+- **⚠️ Xray 26.7.28 удалил `allowInsecure`** в клиентских tlsSettings (мигрировано на `pinnedPeerCertSha256`/`verifyPeerCertByName`). Если в клиентском конфиге был `allowInsecure: true` — клиент падает. Это частая причина «не подключается».
+
+> ⚠️ База `x-ui.db` была **уже настроена** под эту Caddy-интеграцию (inbound vless-ws:10095, subDomain vpn-panel), поэтому панель заработала «из коробки». Бэкап базы/Caddyfile до изменений: `/mnt/RED_2TB/docker/backups/reverse-xray-3xui-20260901-113625/`.
+
+### `xray-reverse-portal` — Xray reverse portal (TrueNAS, добавлен 2026-09-01)
+
+**Цель:** portal-часть Xray-reverse туннеля: принимает исходящий трафик локальных клиентов сети TrueNAS (через SOCKS `:12345`) и пересылает по reverse-каналу на Kraken (bridge) → интернет через Kraken. Подробно: [[personal/tech/xray-reverse-tunnel-kraken-truenas]].
+
+| Параметр | Значение |
+|----------|----------|
+| Папка | `/mnt/RED_2TB/docker/reverse-portal/` |
+| Контейнер | `xray-reverse-portal` |
+| Образ | `teddysun/xray:latest` (Xray 26.7.28) |
+| Volume | `config.json:/etc/xray/config.json:ro` |
+| Сеть | `caddy_default` |
+| interconn | `:12346` VLESS (принимает reverse-канал от Kraken) — **сейчас на TCP+REALITY** (внутр. порт 12346, проброс `12346:12346`) |
+| local | `:12345` SOCKS (точка входа для клиентов сети TrueNAS), проброс `12345:12345` |
+| Env | `LOGLEVEL` |
+
+**✅ Reverse внедрён на TCP+REALITY (2026-09-01 выполнен) + ИСТИННЫЙ КОРЕНЬ НАЙДЕН 2026-09-02.** Portal пересоздан на TCP+REALITY (`12346:12346`), OpenWrt DNAT `внешний:12346 → 192.168.2.197:12346` добавлен, bridge на Kraken пересоздан. REALITY-ключи: server PrivateKey `0JTjeirfviDqCr63wSnisvU7DV6SpR9_9V2l_EUHmkk`, PublicKey `GhsphQLT_0fwOvK45MHeAgG3sBQsFtw7lQfUIbrLMQU`, shortId `1451ef281caf5905`, SNI `www.cloudflare.com`. **НЕ ВНЕДРЕНО (ждёт команды):** payload по-прежнему не проходит даже с фиксом #6612 → истинный корень [issue #6242](https://github.com/XTLS/Xray-core/issues/6242) (регрессия bridge в v26.5+, у нас 26.7.28). Решение: сдаунгрейд bridge до `teddysun/xray:26.4.25`. Детали: [[personal/tech/xray-reverse-tunnel-kraken-truenas]].
+
+### Home Assistant — детали
+
+- **Image:** `ghcr.io/home-assistant/home-assistant:stable`
+- **Порт:** `8123:8123`
+- **Volume:** `/mnt/RED_2TB/docker/ha` → `/config`
+- Конфиги редактируются **напрямую на NAS** — `docker cp` не нужен, изменения применяются после reload/restart HA.
+
+**Ключевые файлы конфига:**
+
+| Файл | Назначение |
+|------|------------|
+| `configuration.yaml` | Главный конфиг: интеграции, template sensors, http trusted_proxies |
+| `automations.yaml` | Все автоматизации (подключён через `!include`) |
+| `scripts.yaml` | Скрипты |
+| `.storage/lovelace.home_plan` | Dashboard с планом этажей (JSON, управляется HA UI) |
+| `www/floorplan/floor1_ha.svg` | SVG фон первого этажа |
+| `www/floorplan/floor2_ha.svg` | SVG фон второго этажа |
+
+**Перезапуск после редактирования конфига:**
+```bash
+ssh truenas_admin@mallexxx.duckdns.org "docker restart homeassistant"
+```
+
+**Проверка конфига перед перезапуском:**
+```bash
+ssh truenas_admin@mallexxx.duckdns.org "docker exec homeassistant python -m homeassistant --script check_config --config /config"
+```
+
+### mbusd — Modbus RTU → TCP gateway
+
+Мост Modbus RTU → TCP: пробрасывает серийный порт в TCP 502. Используется и для вентиляции (AT2), и для ZONT-шины.
+
+- **Image:** `3cky/mbusd`, compose в `/mnt/RED_2TB/docker/mbusd/`
+- **Порт:** `502:502` (TCP)
+- **Config:** `/mnt/RED_2TB/docker/mbusd/mbusd.conf` → `/etc/mbusd.conf` (`device=/dev/ttyUSB0 speed=9600 mode=8n1`, `port=502`)
+- **Device:** `devices: - /dev/ttyVent:/dev/ttyUSB0`
+- **Entrypoint:** `["/usr/bin/mbusd","-d","-L","-","-c","/etc/mbusd.conf"]`
+- **Pitfall udev-race:** см. ниже «Проблема modbus-bridge/mbusd после рестарта».
+
+### modbus-bridge — 485-датчики + виртуальные slaves для ZONT
+
+Кастомный Python-мост (`modbus_ha_bridge.py`, репо `HA-ZONT-Modbus`), контейнер `/mnt/RED_2TB/docker/modbus-bridge/`.
+
+- **Image:** `modbus-bridge` (локальная сборка, `--no-cache`). **НЕ имеет compose-файла** — создавался через `docker-compose`-подобный run; для восстановления использовать параметры ниже.
+- **Device:** `devices: - /dev/ttyZONT:/dev/ttyUSB0` (внутри контейнера слушает `/dev/ttyUSB0`)
+- **Volumes:** `config.yml` → `/app/config.yml` (ro), `modbus_ha_bridge.py` → `/app/modbus_ha_bridge.py` (ro)
+- **Env (из compose):** `HA_TOKEN`, `MQTT_USER=zont`, `MQTT_PASS=...`
+- **`network_mode: host`**; MQTT broker `localhost:1883` (mosquitto), HA `http://localhost:8123`.
+
+**Роль (важно — два режима работы):**
+1. **Sniff (чтение)** — сниффит реальные 485-датчики на шине ZONT: **Dining=slave 1, Kids=slave 2, Bedroom=slave 3** (CO₂/температура/влажность, регистры 2 и 100) и публикует в MQTT (`modbus/sensors//...`), а также пишет в HA.
+2. **Mappings (виртуальные slaves для ZONT)** — подставляет на **slave 101/102/103** (регистр 100) значения temperature от 485-датчиков: Dining→101, Kids→102, Bedroom→103. **ZONT (Modbus master) опрашивает 101/102/103 как свои внешние датчики температуры.** Есть также wifi-термостат как slave 100 (`sensor.0xa4c13862d39377e6_temperature`) и Socket 1 = slave 101 через switch (обратим внимание: 101 занят и Dining temp — переиспользуется на одном slave с разными функциями; сверить в config.yml).
+3. Также через mbusd может работать с AT2 вентиляции.
+
+**Если modbus-bridge не слушает `ttyZONT`** (упал/не запущен) → ZONT не получает ответ на запросы slave 101/102/103 → в интерфейсе ZONT 485-датчики отображаются **«недоступные»**.
+
+### Проблема modbus-bridge/mbusd после рестарта TrueNAS (гонка с udev)
+
+**Симптом:** после перезагрузки TrueNAS `/dev/ttyZONT` и `/dev/ttyVent` присутствуют (`ttyZONT`→ttyUSB1, `ttyVent`→ttyUSB0, создаются init script id=1), НО контейнеры `modbus-bridge`/`mbusd` упали на старте и не перезапустились; 485-датчики в ZONT «недоступные».
+
+**Причина:** docker стартует раньше udev → при `start` контейнера устройство ещё не существует → падение ДО запуска процесса:
+```
+docker inspect --format '{{.State.Error}}'
+error gathering device information while adding custom device "/dev/ttyZONT": no such file or directory
+# ExitCode 128 / 255, RestartCount=0
+```
+`restart: unless-stopped` такой отказ **не подхватывает** (RestartCount=0), и задержка внутри entrypoint не поможет (device mount происходит до старта процесса).
+
+**Ручной фикс:** `docker start modbus-bridge mbusd` (после того как симлинки созданы).
+
+**Защита от рецидива (план, НЕ внедрён, ждёт OK Alex):** `family/plans/zont-modbus-bridge-udev-race-protection.md` — POSTINIT init script `/mnt/RED_2TB/system/start-modbus.sh`, который ждёт появления `ttyZONT`/`ttyVent` (≤25с) и делает `docker start modbus-bridge mbusd`.
+
+### USB device aliases
+
+Файл правил: `/mnt/RED_2TB/system/99-tty-alias.rules`
+
+```
+SUBSYSTEM=="tty", KERNEL=="ttyUSB*", KERNELS=="?-1.6:1.0", SYMLINK+="ttyZONT"
+SUBSYSTEM=="tty", KERNEL=="ttyUSB*", KERNELS=="?-1.5:1.0", SYMLINK+="ttyVent"
+```
+
+`?` — wildcard на префикс USB-шины (`2`, `3` и т.д.): правила работают даже если хаб переопределяется под другой контроллер (например, после подключения USB3-устройства к тому же хабу).
+
+Применить после изменений:
+```bash
+cp /mnt/RED_2TB/system/99-tty-alias.rules /etc/udev/rules.d/ && udevadm control --reload-rules && udevadm trigger
+```
+
+> `/etc/udev/rules.d/` на TrueNAS — tmpfs, не переживает перезагрузку. Правила применяются автоматически через **TrueNAS Init/Shutdown Scripts** (POSTINIT).
+
+**Просмотреть/изменить:** TrueNAS UI → System → Advanced → Init/Shutdown Scripts, или:
+```bash
+midclt call initshutdownscript.query
+```
+
+Текущая запись (id 1, POSTINIT, comment: "Map ttyUSB"):
+```bash
+cp /mnt/RED_2TB/system/99-tty-alias.rules /etc/udev/rules.d/ && udevadm control --reload-rules && udevadm trigger
+```
+
+## Hermes-Taiga агент
+
+| Параметр | Значение |
+|----------|----------|
+| Контейнер | `hermes-taiga` |
+| Telegram | через общий токен, SOCKS5 прокси `vless-proxy:1080` |
+| Модель | **DeepSeek Chat** (`deepseek/deepseek-chat`) |
+| Auxiliary | OpenRouter (`openrouter/auto`) |
+| Vault (хост) | `/mnt/RED_2TB/storage/obsidian` |
+| Vault (контейнер) | `/vault:rw` |
+| obsidian-mcp | `/opt/data/.local/bin/mcpvault /vault` |
+| Scope | sparse: `personal/ + family/` |
+| Toolsets | hermes-cli, file, web, browser |
+| web_search | Tavily (`TAVILY_API_KEY` в .env) |
+| web_extract | ✅ HTTP-парсинг |
+| browser | ✅ Playwright/Chromium (headless, JS-heavy сайты) |
+| Прокси | SOCKS5 `vless-proxy:1080` (HTTP/HTTPS/Telegram — все через прокси) |
+
+### SOUL.md — identity & persona (обновлено 2026-05-13)
+
+Файл: `/opt/data/SOUL.md` (монтируется в контейнер, читается Hermes на каждый тёрн).
+
+**Ключевые изменения 2026-05-13:**
+- Добавлен блок `## Identity` — Тайга не ассистент, а лес: не извиняется, не суетится, говорит прямо
+- Добавлен uncertainty posture: при отсутствии данных говорит "не знаю" / "нет данных в vault", не строит истории
+- Тон исправлен: убрано "тёплая" (активировало female-helper архетип), оставлено "спокойная, уверенная, немногословная"
+- Добавлена обязанность читать и писать в Obsidian (RULE 2, Vault Access с правильными MCP-командами)
+- `display.personality` в config.yaml изменён с `helpful` на `neutral` — убирает Hermes-level "helpful" прайминг поверх soul
+
+**Почему важно:** `display: personality: helpful` в config.yaml инжектировался поверх soul.md и был основным источником извинений и гиперкомпенсации.
+
+### Починка root-проблемы (2026-05-13)
+Hermes обновился — появилась проверка на root. Контейнер падал с `Refusing to run as root`.
+Фикс: `HERMES_ALLOW_ROOT_GATEWAY=1` + `UV_CACHE_DIR=/tmp/uv-cache` в docker-compose.yml + пересборка с `--no-cache`.
+
+> ⚠️ При обновлении образа — всегда `docker build --no-cache`, иначе `.venv` остаётся от root-слоя и ломает permissions.
+
+## Obsidian Sync (Taiga)
+
+**Скрипт:** `~/sync-vault.sh` (запускается на **хосте**, не в контейнере)
+**Крон:** Hermes cron job `0 * * * *`
+**Bare repo:** `file:///mnt/RED_2TB/storage/git/obsidian-vault.git`
+**Лог:** `/tmp/vault-sync.log`
+
+```bash
+# Запустить sync вручную:
+bash ~/sync-vault.sh
+
+# Посмотреть лог:
+tail -20 /tmp/vault-sync.log
+
+# История коммитов:
+git -C /mnt/RED_2TB/storage/git/obsidian-vault.git log --oneline -10
+```
+
+> ⚠️ Скрипт запускается от `truenas_admin` — только этот пользователь имеет ZFS ACL доступ к bare repo и vault папке.
+
+Подробности: [[obsidian-sync]]
+
+## Home Assistant — что настроено
+
+### `configuration.yaml`
+
+- `http:` раздел: `use_x_forwarded_for: true`, `trusted_proxies: 172.16.0.0/12` — обязательно для работы через reverse proxy (Caddy)
+- Modbus интеграция для вентиляторов AT2 и заслонок
+- Template sensors (в блоке `template: - sensor:`):
+
+| Сенсор | Пример | Описание |
+|--------|--------|----------|
+| `dining_summary` | "24° 450ppm" | Темп и CO₂ в столовой |
+| `dining_air_summary` | "65tvoc 3pm" | TVOC и частицы в столовой |
+| `kids_summary` | "22° 600ppm" | Темп и CO₂ в детской |
+| `bedroom_summary` | "21° 500ppm" | Темп и CO₂ в спальне |
+| `at2_1_summary` | "Off" / "45%" | AT2-1: объединённые on/off + скорость |
+| `at2_2_summary` | "Off" / "45%" | AT2-2: объединённые on/off + скорость |
+
+### `automations.yaml`
+
+- ГВС циркуляция: вкл (09:30) / выкл (23:00)
+- Вентиляционный вентилятор вкл в 05:00
+- Проходной выключатель кабинета → toggle света в кабинете (`not_from: [unavailable, unknown]` — защита от ложных срабатываний при запуске HA)
+- Подсветка лестницы: вкл/выкл по датчику освещённости
+- Диммер спальни: toggle и цикл яркости
+- Ночной свет в душе: присутствие + освещённость
+- Уведомление: датчик протечки (котельная)
+- Уведомления: низкий заряд батареи (несколько устройств)
+
+### Floor Plan Dashboard (`lovelace.home_plan`)
+
+Два вида — Ground Floor (`floor1`) и Second Floor (`floor2`) — `picture-elements` поверх SVG фона.
+
+**Первый этаж (`floor1`):**
+- Приточные заслонки: столовая (левая/правая), кабинет
+- Вытяжные заслонки: кухня, туалет 1F
+- Вентилятор 3 (кухонная вытяжка)
+- Метки AT2-1 / AT2-2 (`sensor.at2_1_summary` / `sensor.at2_2_summary`)
+- Сауна, обогревательный кабель
+- Свет кабинет (левый/правый)
+- Метка столовой (`sensor.dining_summary`) и качество воздуха (`sensor.dining_air_summary`)
+
+**Второй этаж (`floor2`):**
+- Приточные заслонки: детская, спальня, север
+- Вытяжные заслонки: ванная, душ 2F
+- Свет спальни (диммер)
+- Метки: `sensor.kids_summary`, `sensor.bedroom_summary`
+
+**SVG dark mode** — встроенный CSS в SVG-файлах:
+```svg
+
+```
+
+> ЖJSON Lovelace зафиксирован в git по пути `floorplan/lovelace.home_plan.json` (справочный снимок, HA **не** подгружает его автоматически).
+
+---
+
+## Печать / cups-splix (2026-08-26, починено)
+
+**Принтер Samsung CLX-216x подключён по USB к TrueNAS** (не в сети!). Единственный путь печати — контейнер `cups-splix`, который раздаёт CUPS на `192.168.2.197:631`.
+
+**Почему телефон не видел принтер (2026-08-26):** после пересоздания пула контейнер `cups-splix` **не был поднят** — образ локальный (не registry), стёрлся вместе с `.ix-apps`; при восстановлении его не пересобирали (пометка «проверить при надобности»). Конфиг `/mnt/RED_2TB/docker/cups/data` (это `/etc/cups`) цел → принтер прописан и подцепился после рестарта сам.
+
+**Рецепт подъёма (при «не вижу принтер»):**
+```bash
+cd /mnt/RED_2TB/docker/cups
+docker build -t cups-splix . # образ локальный, собрать заново (~3.5 мин)
+docker compose up -d # поднять (privileged + /dev/bus/usb)
+docker exec cups-splix lpstat -p -d # проверить принтер
+nc -z 192.168.2.197 631 # проверить порт наружу
+```
+- Принтер: `usb://Samsung/CLX-216x%20Series?serial=9566BAGQ213134Z.&interface=1` (USB ID `04e8:3425` Samsung CLX-216x).
+- Порт 631: открыт наружу после подъёма.
+
+### ✅ mDNS/AirPrint анонс принтера — включён 2026-08-31 (Android print service видит принтер)
+
+Проблема: Android **штатная служба печати** (в отличие от Samsung Mobile Print, который ходит прямо по IP) ищет принтер **только через mDNS/Bonjour** (`_ipp._tcp.local`). CUPS не анонсировал: в контейнере не было `avahi-daemon`, а `printer-dns-sd-name` в IPP был `no-value` → Android помечал принтер «недоступен», даже добавленный вручную по IP.
+
+**Решение (выполнено):** пересобрали cups-splix — теперь запускает `dbus-daemon` + `avahi-daemon` рядом с cupsd через `entrypoint.sh`, и в `cupsd.conf` включено `Browsing On` + `BrowseLocalProtocols dnssd`. После этого CUPS регистрирует принтер в avahi → mDNS-анонс с **`mopria-certified=1.3`** на IPv4 `192.168.2.197` физического интерфейса `enp3s0`. Android (Mopria) теперь находит принтер сам в локальной сети.
+
+**Что изменилось в конфиге** (папка `/mnt/RED_2TB/docker/cups/`):
+- `Dockerfile`: добавлен `avahi-daemon` в apt, написан `entrypoint.sh`, `ENTRYPOINT` вместо `CMD` (`.old` образ сохранён как `cups-splix-old`).
+- `entrypoint.sh`: стартует `dbus-daemon --system`, затем `avahi-daemon --no-drop-root`, затем `exec cupsd -f`.
+- `data/cupsd.conf`: `Browsing Off` → `Browsing On` + добавлена строка `BrowseLocalProtocols dnssd` (бэкап `cupsd.conf.pre-avahi`).
+
+**⚠️ Важный питфолл:** после правки конфига НЕ использовать `docker restart cups-splix` — он убивает avahi-daemon (defunct), перед новым подъёмом обязателен **`docker stop cups-splix && docker rm cups-splix && docker compose up -d`** (полный пересоздание, чтобы entrypoint перевыполнился с нуля).
+
+**Проверка анонса:**
+```bash
+docker exec cups-splix sh -c "timeout 6 avahi-browse -rt -p _ipp._tcp | grep ';enp3s0;IPv4;'"
+# должно показать: ... Samsung\032CLX-216x... truenas.local;192.168.2.197;631; "mopria-certified=1.3" ...
+```
+
+**Бэкап конфига (2026-08-31):** `/mnt/RED_2TB/docker/cups/backup_20260831-003619.tar.gz` (md5 `0e303a6a57ae767d1e14cd72c8039fe4`) — tar из /etc/cups, /var/spool/cups, /var/cache/cups.
+
+> Диагностика и полное объяснение: [[mac-print-shared-services]]
+
+> ⚠️ **2026-08-31: топология изменена.** TrueNAS больше НЕ в локальной сети (только публичный DNS `mallexxx.duckdns.org`) — из других подсетей/внешки `192.168.2.197` недостижим, и **снаружи `mallexxx.duckdns.org:631` закрыт**. НО **из самой подсети `192.168.2.x` TrueNAS достижима** (телефон `192.168.2.141` успешно печатал по `192.168.2.197:631` — CUPS access_log это подтверждает). → Samsung Mobile Print (app) печатает (висит на локальном IPP внутри подсети), а штатная Android print service с `ipp://192.168.2.197:631/...` показывала «недоступен» из-за **отсутствия mDNS/AirPrint-анонса** (avahi-daemon не запущен; `printer-dns-sd-name = no-value`). ✅ **Исправлено** (см. раздел «✅ mDNS/AirPrint анонс принтера»): cups-splix пересобран с avahi-daemon, cupsd.conf получил `Browsing On` + `BrowseLocalProtocols dnssd` → принтер анонсируется по mDNS (`mopria-certified=1.3`, IPv4 `192.168.2.197`); Android-служба теперь находит принтер сама. Детали и откат: [[mac-print-shared-services]].
+
+## Связанные заметки
+- [[truenas-access]] — SSH-доступ
+- [[truenas-rclone-backup]] — система бэкапов
+- [[obsidian-sync]] — Obsidian sync Eagle ↔ Taiga ↔ Kraken
+- [[openmediavault-rpi5]] — Kraken NAS (Hermes агент, sync)
diff --git a/family/how-to/truenas-sata-ports-and-zfs-pools.md b/family/how-to/truenas-sata-ports-and-zfs-pools.md
index 9881b059..afaca945 100644
--- a/family/how-to/truenas-sata-ports-and-zfs-pools.md
+++ b/family/how-to/truenas-sata-ports-and-zfs-pools.md
@@ -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 ` под root). Данные при этом целы, пока все члены `ONLINE`.
+>>>>>>> origin/main
- Проверка пула после перетыкания: `/sbin/zpool status ` — убедиться что все члены `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 ` (идея зеркала на 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 `): валидна, но ТОЛЬКО после успешного импорта пула и его стабилизации. Не пытаться до восстановления.
+
+### ✅ ПЕРЕСОЗДАНИЕ ПУЛА (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/` — трогать не надо.
+3. **Пересоздать каждый контейнер** (WebUI Apps нативный/Custom App) с **bind-mount** `/mnt/RED_2TB/docker/` → внутрь контейнера. Образы перекачаются при старте, контейнер подхватит свой существующий конфиг.
+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`).
diff --git a/family/how-to/vault-git-sync.md b/family/how-to/vault-git-sync.md
index 340a7822..cdb89533 100644
--- a/family/how-to/vault-git-sync.md
+++ b/family/how-to/vault-git-sync.md
@@ -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 ... {stripacl:true}` (chmod/chown do NOT remove DENY ACEs). Tell-tale: POSIX file mode `40` (`r--------`) on loose objects vs normal `750`.
## History
diff --git a/family/how-to/vps-qentra.md b/family/how-to/vps-qentra.md
index 4bb2e18c..676b749b 100644
--- a/family/how-to/vps-qentra.md
+++ b/family/how-to/vps-qentra.md
@@ -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
diff --git a/family/how-to/wireguard-vpn.md b/family/how-to/wireguard-vpn.md
index 007417a7..a39a6493 100644
--- a/family/how-to/wireguard-vpn.md
+++ b/family/how-to/wireguard-vpn.md
@@ -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`.
---
diff --git a/family/how-to/zont-modbus-bridge-udev-race-protection.md b/family/how-to/zont-modbus-bridge-udev-race-protection.md
new file mode 100644
index 00000000..c6d128dc
--- /dev/null
+++ b/family/how-to/zont-modbus-bridge-udev-race-protection.md
@@ -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` монтирует устройство ДО запуска процесса** — если `` отсутствует на момент старта, контейнер вообще не стартует, и `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 ` + удалить скрипт с диска.
+
+## Связанные заметки
+- [[family/how-to/home-automation.md]] — карта slave ID, ZONT, датчики
+- [[family/how-to/truenas-infrastructure.md]] — docker, modbus-bridge, mbusd, udev rules, init scripts
diff --git a/family/plans/reverse-xray-3xui-kraken.md b/family/plans/reverse-xray-3xui-kraken.md
new file mode 100644
index 00000000..28105fb3
--- /dev/null
+++ b/family/plans/reverse-xray-3xui-kraken.md
@@ -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 — ДОБАВИТЬ после проверки связности панели.
diff --git a/personal/business/rf-tax-residency.md b/personal/business/rf-tax-residency.md
new file mode 100644
index 00000000..ec9983bd
--- /dev/null
+++ b/personal/business/rf-tax-residency.md
@@ -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 начинает расти
+- **Принцип:** следить за датами, особенно после длинного лета в РФ — запас резко сокращается
diff --git a/personal/plans/ohotnichy-bilety-interaktiv.md b/personal/plans/ohotnichy-bilety-interaktiv.md
new file mode 100644
index 00000000..62b5f691
--- /dev/null
+++ b/personal/plans/ohotnichy-bilety-interaktiv.md
@@ -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) из-за нестандартной обёртки `` и вопроса без ``. Восстановлены скриптами `~/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 · **вопросы из нескольких ``**
+- Итого ~180 вопросов.
+
+### Структура одного вопроса в DOM (проверено по сырым данным)
+Каждый блок — один большой div; внутри `childNodes`:
+- ` ` — разделители (шум)
+- `Вопрос` — текст вопроса; может занимать **несколько подряд** `` (напр. вопрос 58); внутри возможен вложенный `` (consultantplus)
+- шапка раздела — `
`: `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`.
diff --git a/personal/projects/personal-os/ai-agent-landscape-2026.md b/personal/projects/personal-os/ai-agent-landscape-2026.md
new file mode 100644
index 00000000..f4dad50c
--- /dev/null
+++ b/personal/projects/personal-os/ai-agent-landscape-2026.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 (статистика на дату обзора)
diff --git a/personal/projects/personal-os/eagle-dashboard.md b/personal/projects/personal-os/eagle-dashboard.md
index 2102dece..0cb62bbf 100644
--- a/personal/projects/personal-os/eagle-dashboard.md
+++ b/personal/projects/personal-os/eagle-dashboard.md
@@ -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/` (mount `app.mount("/local-pages", StaticFiles(...))`).
+
+Метаданные парсятся из HTML:
+| Поле дашборда | Источник |
+|---|---|
+| `title` | `...` |
+| `purpose` | ``, fallback — `` |
+| `contains` | `` |
+
+**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//