19 KiB
tags: [truenas, restore, incident, git, media, arr, permission] created: 2026-09-02 updated: 2026-09-02 status: in-progress (Этап 1 done — оба compose на PUID=950 правлены; Этап 2 заблокирован: transmission без compose-лейблов, нужен rm -f — ждёт ок Alex)
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. RPCtransmission-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-файла на пути нет. Не связано с поломкой прав; ручной фикс только по запросу.
Общий план (ИСПРАВЛЕН — НЕ выполнен, требует подтверждения)
⚠️ 2026-09-02 УТОЧНЕНО:
/mnt/RED_2TB/storage— единый ZFS datasetRED_2TB/storageсacltype=nfsv4. НЕ ПОСIX. Ранее планировалосьchown -R/chmod -R— это НЕВЕРНО для TrueNAS SCALE с NFSv4 ACL. Права управляются только черезmidclt call filesystem.setacl(эквивалент TrueNAS UI → Datasets →RED_2TB/storage→ Edit ACL → Apply recursively).truenas_admin= FULL_ADMIN в midclt → root/sudo для setacl НЕ нужен (проверено:midclt call auth.me→ rolesFULL_ADMIN).
Диагноз по NFS4 ACL (что именно сломано)
Реальные ACL через midclt call filesystem.getacl у storage, git, Downloads, Movies, Cartoons структурно ИДЕНТИЧНЫ рабочему obsidian, но:
- владелец uid/gid = 921 (
transmission) вместо правильного 950 (truenas_admin); - у записи
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
# 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:
# скопировать на 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'
Внутри:
- Бэкап ACL каждой папки →
/mnt/RED_2TB/backup/facl_fix_<дата>/<name>.acl.json(откат — применить сохранённые черезfilesystem.setacl). - Применение к каждой папке списка (
Cartoons Downloads Edu Movies Music ada3s1 art books cartoons-series documentaries documentaries-series git nas photo_dedup_test seafile series shared singularity sonarr work):midclt call filesystem.setacl <path> \ '{"uid":950,"gid":950,"dacl":[<эталон-ACE obsidian>],"options":{"recursive":true,"traverse":true,"stripacl":false}}' - Verify: все каталоги → uid 950; тест
git --git-dir=<base>/git/obsidian-vault.git log.
obsidian/obsidian-syncthingв список НЕ включены — уже рабочие 950:950.
После фикса прав
- На маке:
bash ~/scripts/sync-vault.sh→ 55 коммитов уедут в bare repo (launchd возобновит нормальную работу; см. раздел 1). - Arr-стек:
cd /mnt/RED_2TB/docker/arr && docker compose up -d→ проверитьdocker compose ps.
Открытые вопросы перед запуском (подтверждение Alex)
- Transmission-контейнер работает как root (
docker exec transmission id→ uid 0), поэтому права медиа для него некритичны; но данные Transmission (downloadDir/mnt/storage/Downloads) док описывал подtransdamon/911. Решено ставить единообразно 950 (нужно для git/arr/serving). Если нужен и доступ transdamon/911 — добавить явный ACEGROUPна 911. - Альтернатива владельцу 950 — общая группа
nas_users(3000, члены: truenas_admin, transmission, nas и др.). Эталон obsidian = 950.
5. ⭐ РЕШЕНИЕ от 2026-09-02: ВАРИАНТ А — единый PUID/PGID=950 + рекурсивный фикс прав
Контекст: вопрос «будут ли файлы, созданные transmission, читаться jellyfin?» вскрыл, что простой смены владельца верхних папок на 950 НЕДОСТАТОЧНО — нужно согласовать межсервисную читаемость контента + фикс вглубь файлов. Выбран Вариант A (одобрен Alex, стоп-правило: root-команды выполняет Alex, обязательный бэкап перед изменениями).
Факты, на которых строится решение
- Все linuxserver-образы загружены локально на TrueNAS (проверено
docker images):radarr,sonarr,jellyfin,transmission,prowlarr. Контейнеры (кроме transmission) ещё не созданы из них. - Проверен механизм PUID/PGID в linuxserver: Entrypoint=
[/init], есть/etc/s6-overlay(s6-based). →PUID/PGIDобрабатываются штатно s6-stage2-hook. Нативный механизм. - Дефолт без PUID: у текущего transmission
PUIDне задан → контейнер работает root (подтвержденоdocker exec transmission id→ root). Медиа-образы без явного PUID разъехались бы по разным uid → не видят файлы друг друга. - Масштаб поломки вглубь (подсчёт через transmission-root,
find -printf '%u'):Movies: 257 908 файлов, из них 257 751 → uid 921 (+157 → 950).Downloads: mix 518→911, 380→921, 7→1001.series: 94 → 921;Music: 8484;git(bare): 3430;work: 26180;Cartoons: 1009.- Глубокие
.mkv/.avi/.isoтоже921:921 mode 0000— поломка НЕ только каталоги, а каждый inode.
Целевая модель Варианта А
Все медиа/arr/jellyfin контейнеры работают под единым uid 950:950 (truenas_admin, как obsidian-эталон), тогда transmission→(radarr→jellyfin) взаимно читают:
- transmission (станет 950) качает → файлы 950
- radarr/sonarr (950) импортируют → 950
- jellyfin (950) читает → ✅
Этапы (рабочий статус на 2026-09-02)
- ✅ Этап 0 — БЭКАП выполнен →
/home/truenas_admin/variantA_bk/:transmission.docker-compose.yml(оригинал),arr.docker-compose.yml(оригинал),transmission_settings.json(2982 б), ACL топ-папок (Cartoons Downloads Movies Music git work series books shared) + README.txt.⚠️ Питфолл бэкапа:
/mnt/RED_2TB/backup— root-owned (drwxrwxr-x root root),truenas_adminтуда писать не может → бэкап сделан в домашку~truenas_admin. Файлdocker/transmission/docker-compose.ymlна хосте владеет uid 911 (drwx------ 911 911) → прочитан/скопирован через root-контейнерdocker exec transmission cat /config/docker-compose.yml. - ✅ Этап 1 — правка compose на PUID/PGID=950 ВЫПОЛНЕНА (2026-09-02):
- transmission compose:
/config/docker-compose.ymlперезаписан черезdocker cp /tmp/transmission-new-compose.yml transmission:/config/docker-compose.yml. ДобавленоPUID=950+PGID=950. Оригинал вvariantA_bk. (Скрипт-источник на маке:~/transmission-new-compose.yml.) - arr compose:
/mnt/RED_2TB/docker/arr/docker-compose.ymlперезаписан (владелец truenas_admin → запись прошла без root): во всех 4 сервисах (prowlarr/radarr/sonarr/jellyfin) добавленоPUID=950+PGID=950(у всех уже былTZ). Провереноdocker compose config --quiet→COMPOSE_VALID. Источник:~/arr-new-compose.yml. Оригинал вvariantA_bk.- Arr compose НЕ имеет секции
networksу сервисов → при подъёме будет дефолт-сеть<project>_default. Consciously оставлено (оригинал не задавал networks у radarr/sonarr/jellyfin явно, только глобальноmedia_net/caddy_default; НЕ переопределено чтобы не менять поведение без надобности).
- Arr compose НЕ имеет секции
- transmission compose:
- ⚠️ Этап 2 — ПЕРЕСОЗДАНИЕ transmission — ЗАБЛОКИРОВАНО (ключевой технический питфолл, 2026-09-02):
cd /mnt/RED_2TB/docker/transmission→permission denied(каталогdrwx------ 911 911— владелец transdamon/911, truenas_admin нет доступа).- Попытка
docker compose -f /tmp/transmission-new-compose.yml up -d→ создал сетьtmp_defaultи упал: name conflict (container "transmission" already in use). - Полный рабочий контейнер пересоздать из compose невозможно по двум причинам:
- Контейнер создан без compose-лейблов (
com.docker.compose.project = <no value>) → compose его не распознаёт как свой → не может мигрировать/пересоздать, только name-conflict. - Композ-файл в каталоге 911 недоступен для работы оттуда.
- Контейнер создан без compose-лейблов (
- Найденное решение: удалить старый контейнер и поднять заново с корректным проектом (сохранит сеть
transmission_default):docker rm -f transmission # данные в /config и /mnt/storage НЕ теряются (bind-mount на диск) docker compose -f /tmp/transmission-new-compose.yml -p transmission up -d docker exec transmission id # ожидаем uid=950 - Почему PUID нельзя применить к работающему контейнеру? env зашивается при
docker run(создании).docker updateменяет ТОЛЬКО ресурсы (CPU/RAM/restart), НЕ переменные окружения — ограничение Docker. Пересоздание — единственный способ. - Альтернатива без пересоздания (если не хотим трогать transmission root): оставить root; НО тогда новые скачанные файлы будут
root:root, и radarr/jellyfin (под 950) их не прочитают. → PUID=950 у transmission всё же нужен для цепочки. (Обход с setgid-битом на dir + group 950 возможен как fallback, не выбран.) - Статус: ждёт ок Alex на
docker rm -f transmission.
- ⬜ Этап 3 — рекурсивный фикс прав вглубь (root → выполняет Alex, масштаб ~257k+ файлов): рекурсивно вернуть владельца 950:950 + снять 0000 на файлах/папках (
find ... -exec chown -R 950:950 {} +,chmod u+rw,g+rдля файлов,u+rwX,g+rwXдля каталогов). Или через UIApply recursively.
Точное содержание transmission compose (оригинал, важно для пересоздания)
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
- arr-stack-kraken — serving-стек (Kraken)
- vault-git-sync — git-sync алгоритм и скрипты
- obsidian-sync — общая схема Eagle↔Taiga↔Kraken
- syncthing-truenas-android — syncthing схема (требует обновления volumes →
obsidian-syncthing)