--- title: skill — truenas-administration namespace: personal type: tech created: '2026-09-26' updated: '2026-09-27' tags: - truenas - skill - docker - acl - nfc - navidrome - ndignore related: - '[[personal/plans/tagwriter-container]]' - '[[personal/tech/music-tags-repair-truenas]]' - '[[family/how-to/navidrome-truenas-android]]' --- # Зеркало навыка `truenas-administration` Навык: `~/.hermes/hermes-whale/skills/devops/truenas-administration/SKILL.md` (umbrella: ACL/PUID, ZFS panic recovery, tree comparison, named-volumes→bind-mount). Ниже — дельта. **2026-09-26:** волна 38 + сборка `tagwriter`. **2026-09-27:** добавился RULE 0 (Area 3) про `.ndignore`. ## 0. 🔴 RULE 0 (2026-09-27): любой новый `backup*` → в `.ndignore` В ТОМ ЖЕ ПРОГОНЕ Область: `/mnt/RED_2TB/storage/Music/` — корень библиотеки Navidrome (монтируется как `/music`). Navidrome игнорирует **только то, что перечислено в `.ndignore`**. Бэкап, которого там нет, **сканируется как обычная музыка** и пачкает КАЖДЫЙ запрос к БД: расхождения счётчиков, фантомные находки («альбом со скобками до сих пор в базе», хотя правка отработала), дифф, который выглядит сломанным, хотя он верный. **Проверенный провал 2026-09-27:** `.ndignore` создан **03:49** и содержал 4 папки (`backup`, `backup_conv40`, `backup_fix`, `backup_raw`). Бэкапы, созданные **позже**, в файл не попали: `backup_before_306` (**05:17**), `backup_album_root_20260927-album-root-229` (**06:19**). Итог: БД **8167** против плана **7861**, разница **306** = неотфильтрованный бэкап. Альбомы `(zvezda)`, `(Авария)`, `(Несчастный Случай)` «остались в базе» — они существовали **только внутри бэкапа**. **Фикс (боевой конфиг → порядок: бэкап ДО → правка → проверка → коммит ПОСЛЕ):** ```bash # 1. бэкап файла ssh truenas_admin@mallexxx.duckdns.org \ "cp /mnt/RED_2TB/storage/Music/.ndignore /mnt/RED_2TB/storage/Music/.ndignore.bak-\$(date +%Y%m%d-%H%M%S)" # 2. перечислить ВСЕ бэкап-папки и сверить со списком ssh truenas_admin@mallexxx.duckdns.org "cd /mnt/RED_2TB/storage/Music && ls -d */ | grep -i backup" # 3. полный файл собрать ЛОКАЛЬНО (write_file) → scp → cp НА МЕСТО (НЕ sed на NAS!) scp /tmp/ndignore-new truenas_admin@mallexxx.duckdns.org:/tmp/ndignore-new ssh truenas_admin@mallexxx.duckdns.org "cp /tmp/ndignore-new /mnt/RED_2TB/storage/Music/.ndignore" ``` Затем **`docker restart navidrome`** (в контейнере `curl /api/scanner/status` → `404`, эндпоинта нет; подхват идёт по рестарту + watcher). После скана проверить, что игнор сработал — игнорируемые получают **`missing=1`, их НЕ удаляют**: ```bash sqlite3 /mnt/RED_2TB/docker/navidrome/data/navidrome.db \ "SELECT COUNT(*) FROM media_file; -- всего SELECT COUNT(*) FROM media_file WHERE missing=1; -- игнор/отсутствуют SELECT COUNT(*) FROM media_file WHERE missing=0 AND path NOT LIKE 'backup%';" -- живая музыка ``` **Контрольное число:** живая музыка = числу строк плана (**7861** на 2026-09-27). Факт после фикса: всего **8396**, `missing=1` **535**, живая **7861** ✅ (до фикса было 8167/306). > 🔴 **ОБЯЗАТЕЛЬНЫЙ ФИЛЬТР в ЛЮБОМ запросе к `media_file`:** > `missing=0 AND path NOT LIKE 'backup%'` > Без него читаешь бэкап-копии и делаешь ЛОЖНЫЕ выводы. Эта ошибка дала неверный отчёт > «скобки не исправлены» — бэкап был выдан за живое дерево. > 🔑 **Правило на будущее (Alex: «Да»):** любой новый `backup*` под библиотекой — в `.ndignore` > **в том же прогоне, что его создал**. Файл создан 03:49, бэкапы — 05:17 и 06:19; список > просто не обновили. Скрипты бэкапа обязаны дописывать себя сами. ## 1. Создание НОВОГО каталога под `/mnt//docker/` — из контейнера `/mnt/RED_2TB/docker/` = `root:root`. `truenas_admin` (uid 950) **не пишет** туда; `sudo` требует пароль (`sudo -n` → password required). Но `docker` доступен (юзер в группе `docker`). ```bash docker run --rm -u 0 -v /mnt/RED_2TB/docker:/docker alpine:latest sh -c \ 'mkdir -p /docker/tagwriter/data && chown -R 950:950 /docker/tagwriter && chmod 755 /docker/tagwriter' ``` Затем `scp` проекта обычным путём (владелец 950). **Правило: любой новый каталог под `docker/` создавать ИЗ КОНТЕЙНЕРА (`-u 0`), не через ssh под 950.** ## 2. 🔴 Права файлов при `scp` → `COPY` в Dockerfile `scp` кладёт файлы как `-rw-------` (600). `COPY` **сохраняет режим** → внутри образа `/app/