From 33fc830532904f2bcb8b2e5a7567888572e4069d Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Wed, 2 Sep 2026 12:05:30 +0600 Subject: [PATCH] [2026-09-02] eagle: family/documents/vault-sync/2026-09-02-restore-privilege-scope.md family/how-to/arr-stack-taiga.md family/how-to/obsidian-sync.md family/how-to/truenas-infrastructure.md family/how-to/vault-git-sync.md --- .../2026-09-02-restore-privilege-scope.md | 59 ++++++++++++++++++- family/how-to/arr-stack-taiga.md | 4 ++ family/how-to/obsidian-sync.md | 2 +- family/how-to/truenas-infrastructure.md | 6 +- family/how-to/vault-git-sync.md | 8 ++- 5 files changed, 74 insertions(+), 5 deletions(-) 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 index 79f9b2de..e3ca1e97 100644 --- a/family/documents/vault-sync/2026-09-02-restore-privilege-scope.md +++ b/family/documents/vault-sync/2026-09-02-restore-privilege-scope.md @@ -1,7 +1,8 @@ --- tags: [truenas, restore, incident, git, media, arr, permission] created: 2026-09-02 -status: diagnosed +updated: 2026-09-02 +status: in-progress (бэкап сделан; правка transmission compose на PUID=950 ждёт подтверждения Alex) --- # Incident 2026-09-02: Поломка прав uid 921/0000 после restore — масштаб и влияния @@ -129,6 +130,62 @@ ssh truenas_admin@mallexxx.duckdns.org 'bash /tmp/fix-storage-nfs4-acl.sh' - 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.** Новая версия transmission compose подготовлена (`~/transmission-new-compose.yml` на маке = `/tmp/transmission-new-compose.yml` на хосте), добавлено `PUID=950` + `PGID=950`. Шаг `docker cp` в `/config/docker-compose.yml` **заблокирован ожиданием подтверждения Alex** (правка живого контейнера) — НЕ выполнен, файл НЕ перезаписан. Лежит в `/tmp/transmission-new-compose.yml`. +- ⬜ **Этап 2 — пересоздать transmission под 950** (root/влияние на рабочий сервис → выполняет Alex): + ```bash + cd /mnt/RED_2TB/docker/transmission && docker compose up -d # пересоздаст с PUID=950 + docker exec transmission id # ожидаем uid=950 + ``` +- ⬜ **Этап 3 — рекурсивный фикс прав вглубь** (root → выполняет Alex, масштаб ~257k+ файлов): рекурсивно вернуть владельца 950:950 + снять 0000 на файлах/папках (`find ... -exec chown -R 950:950 {} +`, `chmod u+rw,g+r` для файлов, `u+rwX,g+rwX` для каталогов). Или через UI `Apply recursively`. + +### Точное содержание 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`) + ## Связанные заметки - [[2026-08-31-syncthing-truenas-incident]] — вызвавший инцидент + фикс syncthing - [[arr-stack-taiga]] — acquisition-стек на TrueNAS diff --git a/family/how-to/arr-stack-taiga.md b/family/how-to/arr-stack-taiga.md index 959165d0..ad4a3b04 100644 --- a/family/how-to/arr-stack-taiga.md +++ b/family/how-to/arr-stack-taiga.md @@ -17,6 +17,10 @@ Secondary arr stack on Taiga (TrueNAS), added 2026-05-20. > > **Почему не запускается просто так — медиа-права сломаны** (тот же 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` — со сломанными правами не прочитают библиотеку. Фикс + запуск: см. `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`. Only **transmission** container exists (running). **jellyfin/radarr/sonarr/prowlarr containers are NOT yet created** — they never get launched until perms fixed. +> **Transmission runs as ROOT** (not 911/950): its compose `/mnt/RED_2TB/docker/transmission/docker-compose.yml` has **no `PUID`/`PGID`**, so linuxserver `/init` (s6-overlay) leaves it root (`docker exec transmission id` → uid 0). This is why it works on the 0000 media dirs. 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. + ## Notes from Setup (2026-05-20) - Config and pitfalls recorded during initial Taiga arr stack deployment 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/truenas-infrastructure.md b/family/how-to/truenas-infrastructure.md index df5b76e5..3e2ea34c 100644 --- a/family/how-to/truenas-infrastructure.md +++ b/family/how-to/truenas-infrastructure.md @@ -169,10 +169,12 @@ arr, caddy, cups, filebrowser, gitea, hermes, immich, inpx-web, inpxer, library, 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) diff --git a/family/how-to/vault-git-sync.md b/family/how-to/vault-git-sync.md index 20af0bfe..12fc7419 100644 --- a/family/how-to/vault-git-sync.md +++ b/family/how-to/vault-git-sync.md @@ -54,10 +54,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.