Files
obsidian-vault/family/plans/lidarr-taiga-deploy.md
T

323 lines
23 KiB
Markdown
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Lidarr на Taiga — деплой + прокси для индексеров
**Дата:** 2026-09-26
**Статус:** 🟡 Фаза 0 частично выполнена (3/6 индексеров зелёные), ждём решение Alex по FlareSolverr
**Namespace:** family
## Задача
Поставить Lidarr на TrueNAS/Taiga в дополнение к Prowlarr/Radarr/Sonarr/Transmission/Jellyfin,
настроить на музыку, обеспечить синк с Jellyfin, провести проверку живости всего стека.
## Решения Alex (2026-09-26)
| # | Вопрос | Решение |
|---|---|---|
| 1 | Куда Lidarr складывает музыку | **`/storage/Music`** — существующая папка как root folder |
| 2 | Как обходить блокировку индексеров | **Через прокси** (`vless-proxy`) |
| 3 | Jellyfin Music-библиотека | **НЕ ТРОГАТЬ** — отдельная задача, заблокирована до ремонта тегов |
## 🔴 Результат разведки (факты с живой машины, 2026-09-26)
### Что работает
| Компонент | Состояние |
|---|---|
| prowlarr, radarr, sonarr, jellyfin, transmission | ✅ Up, все под uid 950, PUID/PGID=950 |
| `media_net` (external) | ✅ существует; в ней prowlarr, radarr, sonarr, transmission |
| `caddy_default` | ✅ prowlarr, radarr, sonarr, jellyfin |
| Caddy subdomains | ✅ radarr/sonarr/prowlarr/jellyfin.mallexxx.duckdns.org |
| Radarr root folder | `/storage/radarr` — accessible ✅ |
| Sonarr root folder | `/storage/sonarr` — accessible ✅ |
| Radarr/Sonarr download client | Transmission (id=1, enable=true) ✅ |
| Prowlarr → Radarr/Sonarr apps | оба `syncLevel=fullSync` ✅ |
| Radarr/Sonarr indexers | 5 шт. у Radarr, baseUrl `http://prowlarr:9696/<id>/` ✅ формат верный |
| Диск | 960 ГБ свободно из 976 (2% used) |
| Music | 7890 аудиофайлов, `Music/backup` НЕ существует |
### 🔴 Что НЕ работает — корень проблемы
**Все 6 индексеров Prowlarr отключены: `disabledTill` = 2026-09-27T08:07:26Z** (более 6 часов недоступны).
**Корневая причина — DNS-блокировка у интернет-провайдера TrueNAS (Ростелеком):**
```
nslookup rutracker.org 8.8.8.8 → NXDOMAIN
nslookup rutracker.org 192.168.2.2 → NXDOMAIN (роутер, = провайдерский DNS)
nslookup rutor.info 8.8.8.8 → NXDOMAIN
nslookup kinozal.tv 8.8.8.8 → NXDOMAIN
nslookup nnmclub.to 8.8.8.8 → NXDOMAIN
nslookup byrutgame.org 192.168.2.2 → 185.200.198.230 ✅ (единственный рабочий)
nslookup google.com 192.168.2.2 → ✅
```
**Это НЕ поломка роутера и НЕ поломка стека.** Блокировка на стороне провайдера: провайдерский DNS
отдаёт NXDOMAIN даже для внешнего резолвера, потому что сам DNS-трафик проходит через провайдера.
**Следствие:** `dns: [8.8.8.8, 8.8.4.4]` в compose **НЕ помогает** — проверено, NXDOMAIN с 8.8.8.8 тоже.
Единственный рабочий путь — прокси, где DNS резолвится на выходной стороне.
### ⚠️ `vless-proxy` не виден из media_net
```
vless-proxy networks: hermes_taiga_net (172.16.15.2)
docker exec prowlarr getent hosts vless-proxy → FAIL
docker exec prowlarr getent hosts xray-admin → 172.16.1.9 ✅
```
Понадобится подключить `vless-proxy` к `media_net` (runtime + персистентно в его compose).
### ⚠️ Прочие находки (не блокеры)
- **Radarr/Sonarr health error RemotePathMappingCheck:** Transmission кладёт в `/storage/Downloads/radarr`
и `/storage/Downloads/sonarr`, а внутри контейнеров этих подпапок нет. Проверить remote path mapping.
- **Transmission:** download-dir `/mnt/storage/Downloads`, incomplete `/mnt/storage/Downloads/transmission/incomplete`,
`rpc-whitelist 172.16.*.*`, `script-torrent-done = false` (хука автопостинга нет).
- **Radarr `indexerstatus` вернул 404** — эндпоинт в этой версии иначе; `disabledTill` в `/api/v3/indexer` пустой `{}`.
Реальный статус отключения виден только в Prowlarr `/api/v1/indexerstatus`.
- Лишние файлы в `/mnt/RED_2TB/storage/`: `cmp-remote.sh`, `cmp-remote-v2.sh`, `edu_acl_fix.py`,
`edu_chgrp_fix.py`, `acl-edu-before-20260922-234617.json`, `shares-before-20260914-070242.json` — мусор от прошлых сессий, не трогать без команды.
## API-ключи (полные, сняты с живой машины)
| Сервис | Ключ |
|---|---|
| Prowlarr | `35c8b3f497114076a6150ea0d9504845` |
| Radarr | `51e201f2d61b4fe2a0c322d5e99349fe` |
| Sonarr | `b1eb9cdd5c804e6c956dc9c8bd305dc8` |
| Jellyfin | `eaglesetup2026taiga` |
### ✅ СДЕЛАНО в Фазе 0 (2026-09-26, end-of-session)
| # | Действие | Факт |
|---|---|---|
| 1 | `vless-proxy` подключён к `media_net` | `172.16.17.6`; проверено `docker exec prowlarr getent hosts vless-proxy` → резолвится |
| 2 | Персистентность в compose | `/mnt/RED_2TB/docker/vless-proxy/docker-compose.yml` — добавлена `media_net` в `networks:` + `external: true`. Бэкап: `~/vless-proxy-compose.bak-20260926-012529` и `.bak-<ts>` рядом с файлом. Контейнер пересоздан `docker compose up -d --force-recreate`. MD5 файла: `4449e2b55a75362904438d4792abed90` |
| 3 | Тег `proxy` создан в Prowlarr | `POST /api/v1/tag {"label":"proxy"}` → `id=1`. До этого таблица `Tags` была **ПУСТА**, а `Indexers.Tags` у RuTracker ссылался на висячий id `[1]` — прокси физически не был привязан |
| 4 | Прокси `vless-socks5` (id=1) привязан к тегу | `PUT /api/v1/indexerproxy/1` c `"tags":[1]`. Socks5, host `vless-proxy`, port `1080` |
| 5 | **Все 6 индексеров** тегированы `[1]` | Подтверждено из БД `prowlarr.db`: `SELECT Id, Name, Tags FROM Indexers` → все `[1]` |
| 6 | `testall` прогнан | **3 из 6 зелёные** (было 0 из 6). NXDOMAIN ушёл ПОЛНОСТЬЮ |
**Результат `POST /api/v1/indexer/testall` (фактические данные):**
| id | Индексер | Результат | Сообщение |
|---|---|---|---|
| 1 | RuTracker | ❌ | `[403:Forbidden] [POST] at https://rutracker.org/forum/login.php` |
| 2 | RuTor | ✅ | OK |
| 3 | Byrutor | ✅ | OK |
| 4 | NoNaMe Club | ✅ | OK |
| 5 | Kinozal | ❌ | `Unable to access kinozal.me, blocked by CloudFlare Protection` |
| 6 | Kinozal (M) | ❌ | `Unable to access kinozal.me, blocked by CloudFlare Protection` |
### 🔬 Точный диагноз по RuTracker (проверено curl'ом через прокси, из контейнера prowlarr)
```
GET https://rutracker.org/forum/index.php → HTTP 200 ✅ (сайт доступен через прокси!)
POST https://rutracker.org/forum/login.php → HTTP 403 ❌ "Just a moment..."
(Cloudflare JS-challenge)
```
Тело ответа содержит `challenge` ×8, `cloudflare` ×5 — это **страница Cloudflare-челленджа**, а не отказ
сайта. **Логин/пароль проверить невозможно** — челлендж режет запрос до отправки формы.
**Вывод:** прокси полностью решил DNS-блокировку. Остаточная проблема — **другого класса**:
Cloudflare-защита, для которой нужен headless-браузер. Прокси тут бессилен.
### 🔴 FlareSolverr НЕ УСТАНОВЛЕН (блокер для оставшихся 3 индексеров)
```
docker ps -a | grep -i flare → NOT FOUND
docker images | grep -i flare → NO IMAGE
docker exec prowlarr printenv | grep -i flare → NOT SET
docker exec prowlarr cat /config/config.xml | grep -i flare → NOT IN CONFIG
```
**Варианты, предложенные Alex (ждём решения):**
| # | Вариант | Оценка |
|---|---|---|
| 1 | **Задеплоить FlareSolverr** — `ghcr.io/flaresolverr/flaresolverr:latest` в `media_net`+`caddy_default`, затем `PROWLARR__FLARESOLVERR_URL=http://flaresolverr:8191` в compose Prowlarr | ~10 мин; закроет RuTracker + Kinozal |
| 2 | Пропустить RuTracker/Kinozal — 3 рабочих индексера (RuTor, Byrutor, NoNaMe) уже дают музыку, идти к Lidarr сразу | 0 мин, но теряем Kinozal (помечен как MUSIC-трекер) |
| 3 | Только Kinozal — у него нет логина-формы, FlareSolverr может хватить для одного | компромисс |
**Рекомендация агента — вариант 1:** Kinozal в описании значится как `MOVIES / TV / MUSIC`,
то есть именно музыкальный трекер; без него смысл задачи (Lidarr на музыку) падает.
### Что уже сделано в коде/конфиге (для воспроизведения)
```bash
# 1. Подключение vless-proxy к media_net (persistent, через alpine — каталог root-owned 0:0 755)
cat /tmp/vless-proxy-compose.yml | ssh truenas_admin@mallexxx.duckdns.org \
"docker run --rm -i -v /:/host:rw alpine:latest sh -c \
'cp .../docker-compose.yml .../docker-compose.yml.bak-\$(date +%Y%m%d-%H%M%S) && \
cat > .../docker-compose.yml && md5sum .../docker-compose.yml'"
ssh truenas_admin@mallexxx.duckdns.org "cd /mnt/RED_2TB/docker/vless-proxy && docker compose up -d --force-recreate"
# 2. Создание тега proxy
curl -s -X POST -H "X-Api-Key: $PW_KEY" -H "Content-Type: application/json" \
-d '{"label":"proxy"}' http://localhost:9696/api/v1/tag # → {"label":"proxy","id":1}
# 3. Привязка прокси к тегу proxy
curl -s -X PUT -H "X-Api-Key: $PW_KEY" -H "Content-Type: application/json" \
-d '{"id":1,"name":"vless-socks5","implementation":"Socks5","configContract":"Socks5Settings",
"tags":[1],"fields":[{"name":"host","value":"vless-proxy"},{"name":"port","value":1080},
{"name":"username","value":""},{"name":"password","value":""}]}' \
http://localhost:9696/api/v1/indexerproxy/1
# 4. Тегирование индексеров (Kinozal требует forceSave=true — иначе 400 на Cloudflare-проверке)
# RuTracker уже имел tags=[1]; RuTor/Byrutor/NoNaMe — обычный PUT 202
# Kinozal (5) и Kinozal (M) (6): PUT /api/v1/indexer/<id>?forceSave=true → 202
# ⚠️ ПОСЛЕ PUT обязателен docker restart prowlarr — иначе API отдаёт 202, но БД хранит []
# 5. Проверка
curl -s -X POST -H "X-Api-Key: $PW_KEY" -H "Content-Type: application/json" -d '{}' \
--max-time 240 http://localhost:9696/api/v1/indexer/testall
```
### 🔴 Пойманные питфоллы Фазы 0 (дорогие, записать обязательно)
1. **`Indexers.Tags` ссылался на несуществующий тег.** В `prowlarr.db` таблица `Tags` была **пустой**,
а у RuTracker стоял `Tags=[1]`. Прокси существовал (`IndexerProxies` id=1 `vless-socks5`), но
`IndexerProxies.Tags=[]` — привязки не было. Симптом: `Test All` даёт NXDOMAIN, хотя прокси настроен.
**Диагностика: скопировать `prowlarr.db` на Mac (`sqlite3` на хосте TrueNAS НЕТ) и посмотреть
`SELECT Id,Name,Tags FROM Indexers; SELECT Id,Name,Tags FROM IndexerProxies; SELECT * FROM Tags;`**
2. **`docker exec prowlarr wget` — BusyBox, НЕ умеет PUT и `-e`.** Ошибки
`unrecognized option: method=PUT` и `unrecognized option: e`. **Но в контейнере prowlarr есть
`/usr/bin/curl`** — использовать `curl`, не `wget`. (Linuxserver-образы содержат curl.)
3. **Kinozal PUT → HTTP 400 `CloudFlare Protection`.** Prowlarr при PUT валидирует доступ к сайту.
Обход: добавить `?forceSave=true` в query string → HTTP 202.
4. **PUT вернул 202, но БД осталась `Tags=[]`.** Prowlarr держит кеш. **`docker restart prowlarr`
обязателен** — после рестарта все 6 тегов на месте.
5. **`aws`-подобная правка JSON через `awk`/`sed` ломается, если `tags` — ПОСЛЕДНЕЕ поле объекта.**
Строка `"tags": []` в конце (перед `}`) — awk, режущий блок, съедал закрывающую `}` →
`HTTP 400 Expected start of a property name... LineNumber: 583`.
**Надёжный приём:** `awk '/"tags":/ { exit } { print }' file > body.json` — обрезать ВСЁ от `tags`
до конца, затем дописать хвост вручную: `printf ' "tags": [1],\n "id": %s\n}\n' "$ID" >> body.json`.
6. **`jq` с `\\(...)` внутри inline SSH-строки через `terminal` ломается** (`unexpected INVALID_CHARACTER`).
**Писать jq-выражение в файл-скрипт** (`/tmp/parse.sh`) и запускать `bash /tmp/parse.sh` — тогда работает.
7. **`execute_code` требует апрува Alex и был отклонён** (таймаут без ответа). Для разбора JSON —
файл-скрипт + `terminal`, не `execute_code`. Это подтверждает правило из профиля Alex.
8. **`vless-proxy` содержит ДВА инбаунда:** SOCKS5 на `1080` и HTTP на `1081` (обе `0.0.0.0`).
Оба проверены, оба обходят блокировку. Prowlarr настроен на SOCKS5/1080.
9. **Мёртвый домен `kinozal.tv` — использовать `kinozal.me`.** `kinozal.tv` не резолвится
даже на выходной стороне прокси (мёртв). `kinozal.me` через прокси → **HTTP 200**.
`kinozal.me/login.php` → 403 (нормальная защита страницы логина от curl, не блокировка).
10. **`byrutgame.org` — единственный, работавший напрямую** (без прокси). Через прокси даёт 404
на `/` (норм — у сайта нет корневой страницы).
### Проверка обхода блокировки — сырые данные (воспроизводимо)
```
# БЕЗ прокси (из контейнера radarr)
rutracker.org → NXDOMAIN rutor.info → NXDOMAIN
kinozal.tv → NXDOMAIN nnmclub.to → NXDOMAIN
# ЧЕРЕЗ прокси (HTTP 1081 и SOCKS5 1080 — одинаково)
https://rutracker.org/forum/index.php → 200
https://rutor.info/ → 200
https://nnmclub.to/ → 200
https://kinozal.me/ → 200
https://kinozal.tv/ → 000
```
## План
### Фаза 0 — обход DNS-блокировки через прокси — 🟡 ЧАСТИЧНО ВЫПОЛНЕНА
✅ **шаги 1–4 сделаны** (см. «СДЕЛАНО» выше). Осталось: **решение Alex по FlareSolverr** и
шаг 5 (приёмка Alex в UI).
Текст шагов (для истории):
1. ✅ **Подключить `vless-proxy` к `media_net`** — СДЕЛАНО (runtime + персистентно в compose).
2. ✅ **Проверить прокси из контейнера arr-стека** — СДЕЛАНО: 3/4 сайта дают 200 через прокси.
3. ✅ **Прописать прокси в Prowlarr** — СДЕЛАНО: тег `proxy` создан, прокси привязан, все 6 тегированы.
4. ✅ **Сбросить `indexerstatus`** — СДЕЛАНО через `testall` (`DELETE /indexerstatus` → 405, метод не поддерживается).
5. ⏳ **ПРИЁМКА ALEX:** `https://prowlarr.mallexxx.duckdns.org` → Indexers → Test All → 3 зелёных минимум.
6. ⏳ **РЕШЕНИЕ ALEX по FlareSolverr** — блокирует RuTracker + Kinozal (MUSIC-трекер).
### Фаза 1 — деплой Lidarr
1. **Бэкап** `/mnt/RED_2TB/docker/arr/docker-compose.yml` в `~truenas_admin/`.
2. **Добавить сервис `lidarr`** в compose по образцу radarr:
- образ `lscr.io/linuxserver/lidarr:latest`
- PUID=950, PGID=950, TZ=Asia/Novosibirsk, dns 8.8.8.8/8.8.4.4
- порты `8686:8686`
- volumes: `/mnt/RED_2TB/docker/arr/lidarr:/config`, `/mnt/RED_2TB/storage:/storage`
- networks: `media_net`, `caddy_default`
3. **Поднять** из правильной папки: `cd /mnt/RED_2TB/docker/arr && docker compose up -d lidarr`.
4. **Caddy:** блок `lidarr.mallexxx.duckdns.org { reverse_proxy lidarr:8686 }`
(правка Caddyfile — только через alpine-контейнер, файл root-owned).
5. **ПРИЁМКА ALEX:** `https://lidarr.mallexxx.duckdns.org` открывается.
### Фаза 2 — Lidarr на музыку
1. **Root folder `/storage/Music`** (решение Alex).
2. **Download client** — Transmission: host `transmission`, port 9091, urlBase `/transmission/`,
category `lidarr`, без логина/пароля.
3. **Application в Prowlarr** — добавить Lidarr (implementation `Lidarr`), syncCategories 3000-й серии:
`[3000,3010,3020,3030,3040,3050,3060]`.
4. **Прокси-тег** для заблокированных индексеров (наследуется из фазы 0).
5. **Качество/маска переименования** — решить при настройке (Lidarr переименовывает файлы по маске).
6. **ПРИЁМКА ALEX:** тестовый поиск → торрент появился в Transmission.
### Фаза 3 — синк с Jellyfin
🔴 **По решению Alex (2026-09-26) НЕ ТРОГАТЬ.** Музыкальная библиотека Jellyfin остаётся как есть:
её нет, и она не создаётся в рамках этой задачи. Причина — 7890 файлов с массово битыми тегами
(см. `[[personal/tech/music-tags-repair-truenas]]`), ремонт на апруве Alex.
Что нужно знать для будущей работы (не действие сейчас):
- `/storage/Music` **уже смонтирован** в Jellyfin (ro) — доп. монтирование не требуется.
- Создание библиотеки возможно одной командой, но **до ремонта тегов бессмысленно**.
- Порядок из прошлого плана: ремонт тегов → валидация Alex → удаление `Music/backup/` → библиотека.
### Фаза 4 — приёмка живости стека
1. `docker ps` — 6 сервисов arr-стека Up.
2. Radarr/Sonarr/Prowlarr health — без ошибок (сейчас есть IndexerLongTermStatusCheck и RemotePathMappingCheck).
3. Разобрать RemotePathMappingCheck.
4. **ПРИЁМКА ALEX:** панели по HTTPS, плейбек в Jellyfin, поиск в Radarr/Sonarr.
## Питфоллы (Taiga-специфика, проверено)
- **`dns: [8.8.8.8]` в compose НЕ обходит блокировку** — проверено, NXDOMAIN с 8.8.8.8 тоже.
Провайдерский DNS отдаёт NXDOMAIN и для внешнего резолвера, т.к. DNS-трафик идёт через провайдера.
- **На хосте TrueNAS нет `curl` и `python3`** в PATH (zsh). `wget` есть внутри контейнеров.
BusyBox `wget` **не поддерживает `-e`** и **`--method=PUT`**.
**В контейнерах linuxserver есть `/usr/bin/curl`** — использовать его для API-вызовов.
- **`sqlite3` на хосте НЕ установлен** (вопреки старой доке). Копировать `.db` на Mac через
`ssh ... "cat /path/db" > /tmp/db` и читать локальным `sqlite3`.
- **Caddyfile root-owned** — правка только через `docker run --rm -v /:/host alpine` (см. skill `truenas-caddy-service-deploy`).
Тот же приём работает для любого root-owned каталога (подтверждено на `/mnt/RED_2TB/docker/vless-proxy/` — `0:0 755`;
`cd` туда работает, запись — нет).
- **`docker network connect` теряется при пересоздании** — прописывать сети в compose.
- **Prowlarr API PUT возвращает 202, но кеш не сброшен** — `docker restart prowlarr` обязателен,
иначе `GET` покажет старое значение и БД останется прежней.
- **Prowlarr `?forceSave=true`** — обход валидации доступа к сайту при PUT индексеров
(`400 CloudFlare Protection` → `202`).
- **`DELETE /api/v1/indexerstatus` → HTTP 405.** Сброс статуса делать через `POST /api/v1/indexer/testall`
(он сбрасывает `disabledTill` сам).
- **`jq` с интерполяцией `\(...)` в inline SSH-строке ломается** — писать в файл-скрипт.
- **JSON-правка `awk`/`sed` ломается при `tags` последним полем** — обрезать `awk '/"tags":/ { exit }'`
и дописывать хвост через `printf`.
- `ls -la` на TrueNAS показывает `d---------` — норма для NFSv4 ACL; реальные права через `midclt call filesystem.getacl`.
- Папки медиа: uid 950 `drwxrwx---`, root `/mnt/RED_2TB/storage` — `drwxr-x--x` (traverse работает).
## Связанные заметки
- [[family/projects/media-toolbox-taiga]] — *arr стек
- [[family/how-to/jellyfin-config]] — Jellyfin Taiga + план Music-библиотеки
- [[personal/tech/music-tags-repair-truenas]] — ремонт тегов (7890 файлов)
- [[personal/tech/truenas-nfs4-acl-and-arrmultiuser]] — NFS4 ACL и PUID
- [[family/how-to/arr-stack-taiga]] — предыдущий опыт деплоя