199 lines
13 KiB
Markdown
Executable File
199 lines
13 KiB
Markdown
Executable File
---
|
||
title: FlareSolverr на TrueNAS Taiga
|
||
created: '2026-09-20'
|
||
updated: '2026-09-29'
|
||
type: tech
|
||
namespace: personal
|
||
tags: [flaresolverr, prowlarr, rutracker, taiga, truenas]
|
||
related:
|
||
- "[[family/how-to/arr-stack-taiga]]"
|
||
---
|
||
|
||
# FlareSolverr на TrueNAS Taiga
|
||
|
||
Рабочая документация FlareSolverr для arr-стека Taiga. Общая эксплуатация стека находится в [[family/how-to/arr-stack-taiga]]. Kraken здесь не описывается.
|
||
|
||
## Рабочая схема
|
||
|
||
```text
|
||
Prowlarr
|
||
└─ tags [proxy, flaresolverr]
|
||
└─ FlareSolverr :8191
|
||
└─ Chrome session prowlarr
|
||
└─ socks5://vless-proxy:1080
|
||
└─ RuTracker
|
||
```
|
||
|
||
Внешний egress для arr закреплён на маршруте 3x-ui:
|
||
|
||
```text
|
||
vless-space
|
||
└─ space-master: sub1-sweden
|
||
└─ space-failover: sub1-poland-yt
|
||
└─ space-auto: текущий leastLoad по подписке
|
||
```
|
||
|
||
Это важно для Cloudflare: FlareSolverr и последующий запрос Prowlarr должны выходить через один IP. Общий `leastLoad` по всем профилям без pinned master ломает cookie handoff.
|
||
|
||
Файлы на TrueNAS:
|
||
|
||
```text
|
||
/mnt/RED_2TB/docker/arr/docker-compose.yml
|
||
/mnt/RED_2TB/docker/arr/flaresolverr-entrypoint.sh
|
||
/mnt/RED_2TB/docker/arr/prowlarr/
|
||
```
|
||
|
||
## Почему нужен entrypoint
|
||
|
||
Одного `PROXY_URL` недостаточно. FlareSolverr применяет proxy при создании browser session. Если session создана до настройки proxy, последующие `request.get` с той же session продолжают работать без proxy.
|
||
|
||
Entrypoint при каждом старте:
|
||
|
||
1. ждёт FlareSolverr `/health`;
|
||
2. удаляет старую session `prowlarr`, если она есть;
|
||
3. создаёт `prowlarr` с `socks5://vless-proxy:1080`;
|
||
4. читает credentials RuTracker из `prowlarr.db` через SQLite URI `mode=ro&immutable=1`;
|
||
5. делает pre-login через FlareSolverr;
|
||
6. оставляет основной процесс FlareSolverr работать;
|
||
7. проверяет egress-IP раз в минуту и login-состояние RuTracker раз в пять минут;
|
||
8. при смене IP или потере login-состояния пересоздаёт session `prowlarr` и выполняет login заново.
|
||
|
||
SQLite монтируется read-only. Обычный `sqlite3.connect('/prowlarr.db')` на read-only mount может упасть с `unable to open database file`; нужен именно `immutable=1`.
|
||
|
||
## Compose-настройки
|
||
|
||
Минимально необходимые параметры:
|
||
|
||
```yaml
|
||
environment:
|
||
- LOG_LEVEL=warning
|
||
- BROWSER_TIMEOUT=180000
|
||
- PROXY_URL=socks5://vless-proxy:1080
|
||
- TZ=Asia/Novosibirsk
|
||
shm_size: 1gb
|
||
restart: unless-stopped
|
||
```
|
||
|
||
Entrypoint и Prowlarr config directory подключаются read-only. Не хранить credentials или API keys в compose и Obsidian.
|
||
|
||
В Prowlarr для RuTracker:
|
||
|
||
```text
|
||
proxy tag = [1]
|
||
flaresolverr tag = [2]
|
||
RuTracker tags = [1,2]
|
||
FlareSolverr requestTimeout = 180 seconds
|
||
```
|
||
|
||
## 3x-ui: master и failover
|
||
|
||
Шаблон находится в базе 3x-ui:
|
||
|
||
```text
|
||
/mnt/RED_2TB/docker/xray-admin/x-ui.db
|
||
```
|
||
|
||
Текущая цепочка:
|
||
|
||
```text
|
||
space-master selector=[sub1-sweden] fallback=space-failover
|
||
space-failover selector=[sub1-poland-yt] fallback=space-auto
|
||
space-auto selector=[sub1-] strategy=leastLoad
|
||
```
|
||
|
||
Актуально после исправления 2026-11-02: `sub1-sweden` — prefix selector; `fallbackTag` ссылаются на одноимённые **outbound типа loopback**, которые через отдельные inboundTag/routing-правила передают трафик следующему balancer. Ссылка `fallbackTag` прямо на balancer не работает. Подробности и проверка обеих резервных ступеней — [[family/how-to/arr-stack-taiga]].
|
||
|
||
Не использовать общий `leastLoad` как первый уровень для RuTracker/Kinozal: он может менять egress между соединениями. `maxRTT` и `tolerance` фильтруют кандидатов, но не делают выбор sticky.
|
||
|
||
Перед изменением базы сохранять backup. После изменения проверить сгенерированный `/app/bin/config.json` и выполнить `xray -test`; не редактировать сгенерированный файл напрямую.
|
||
|
||
Один tag `[2]` не решает DNS-блок Taiga. Один tag `[1]` не решает browser challenge.
|
||
|
||
## Правильная проверка
|
||
|
||
Проверка session:
|
||
|
||
```bash
|
||
curl -fsS -H 'Content-Type: application/json' \
|
||
-d '{"cmd":"sessions.list"}' http://127.0.0.1:8191/v1
|
||
```
|
||
|
||
Должны быть `status=ok` и `prowlarr`.
|
||
|
||
Проверка login должна смотреть cookies, а не размер HTML:
|
||
|
||
```text
|
||
solution.cookies содержит bb_session
|
||
```
|
||
|
||
Большая HTML-страница может быть страницей ошибки Chromium и не означает login.
|
||
|
||
Функциональная приёмка — реальный search Prowlarr:
|
||
|
||
```bash
|
||
curl -H "X-Api-Key: $PROWLARR_KEY" \
|
||
'http://127.0.0.1:9696/api/v1/search?query=radiohead&type=search&indexerIds=1'
|
||
```
|
||
|
||
`POST /api/v1/indexer/test` не использовать как единственное доказательство: при передаче объекта из API password может быть `********`, что даёт ложный `Auth Failed`.
|
||
|
||
## Диагностика
|
||
|
||
1. `docker compose ps` — контейнеры живы.
|
||
2. `curl /health` — FlareSolverr отвечает.
|
||
3. `sessions.list` — session существует.
|
||
4. Проверить `bb_session` в `solution.cookies`.
|
||
5. Проверить логи `vless-proxy` на `rutracker.org:443`.
|
||
6. Выполнить одиночный реальный search, не `testall`.
|
||
|
||
Параллельный `testall` перегружает один Chrome и создаёт ложные timeout. Challenge может занимать больше минуты, поэтому timeout 60 секунд недостаточен.
|
||
|
||
## Перезапуск
|
||
|
||
```bash
|
||
ssh truenas_admin@mallexxx.duckdns.org \
|
||
'cd /mnt/RED_2TB/docker/arr && docker compose config -q && docker compose up -d --force-recreate flaresolverr'
|
||
```
|
||
|
||
После restart session должна восстановиться автоматически. Если она не появилась, смотреть `docker logs flaresolverr`; credentials не выводить в лог.
|
||
|
||
Автовосстановление можно проверить безопасно: удалить только session `prowlarr` через `sessions.destroy`, дождаться watcher и проверить `request.get` страницы RuTracker с признаком `id="logged-in-username"`.
|
||
|
||
## Восстановление quarantine
|
||
|
||
При старом предупреждении сначала подтвердить реальный search, выполнить одиночный штатный тест соответствующего индексатора и обновить health. Для Lidarr этот путь проверен 2026-10-26: RuTracker test + `CheckHealth` сняли предупреждение без редактирования БД. При API-тестировании использовать действующие секреты, а не маскированные значения из GET. Ручная очистка `IndexerStatus` — резервный способ только при неработающем штатном восстановлении: backup SQLite, остановка только затронутого сервиса, изменение только нужного статуса, `PRAGMA quick_check`, запуск и реальный search. Не удалять всю БД и не считать health единственным тестом.
|
||
|
||
## Повторный сбой 2026-10-26 UTC / 2026-10-27 Бишкек
|
||
|
||
Проверено на Taiga; различать два независимых дефекта.
|
||
|
||
1. **Фактические отказы поиска:** Prowlarr писал `SQLiteException Busy (5): database is locked`. У RuTracker ошибки зафиксированы в 16:08:13 UTC и 17:20:59 UTC, в том числе в `GetCookies → ProviderStatusRepository.FindByProviderId`, до обращения к трекеру. Аналогичные ошибки были у Kinozal, NoNaMeClub и RuTor. Позже такие же блокировки продолжались в Lidarr. Это не доказательство потери авторизации RuTracker.
|
||
2. **Ошибка watchdog:** старый скрипт искал `id="logged-in-username"` через grep в сыром JSON FlareSolverr. Кавычки HTML в JSON экранированы, поэтому рабочая авторизация ошибочно считалась потерянной и session пересоздавалась каждые пять минут. На одной живой сессии подтверждено: parsed HTML logged-in=true, старый grep=false.
|
||
|
||
Исправлен `/mnt/RED_2TB/docker/arr/flaresolverr-entrypoint.sh`: сначала разбирается JSON, затем проверяется HTML. Повторный login выполняется при явно обнаруженной форме входа; ошибки транспорта, challenge и некорректный ответ считаются неопределённым состоянием и не уничтожают действующую сессию. Таймаут проверки согласован с `BROWSER_TIMEOUT=180000`: 180 секунд внутри FlareSolverr и 240 секунд у curl. Смена egress-IP по-прежнему вызывает восстановление.
|
||
|
||
Backup исходного скрипта:
|
||
`/mnt/RED_2TB/docker/arr/flaresolverr-entrypoint.sh.before-json-auth-fix-20261026T175021Z`.
|
||
Перезапущен только FlareSolverr; SQLite вручную не редактировалась.
|
||
|
||
Приёмка:
|
||
- синтаксис shell и пять проверок классификатора ответа прошли;
|
||
- после перезапуска и очередного пятиминутного цикла вход сохранился, HTTP 200, ложных refresh в логах нет;
|
||
- реальный поиск Prowlarr по RuTracker: HTTP 200, 50 результатов за 17 секунд;
|
||
- одиночный штатный тест RuTracker в Lidarr прошёл;
|
||
- после `CheckHealth` предупреждение о недоступных индексаторах исчезло; осталось только уведомление об обновлении Lidarr;
|
||
- поисковые проверки не запускали новые скачивания.
|
||
|
||
Ограничение: причина локальных блокировок SQLite не устранена этим изменением. На NAS измерено `/proc/pressure/io`: some около 66–70%, full около 50–54%; ZFS pool ONLINE без ошибок, первый mirror заполнен почти полностью (1.79 TiB занято, 27 GiB свободно), новый mirror почти пуст. Это подтверждает высокое ожидание I/O и неравномерное размещение данных, но не доказывает единственную причину блокировки. Настройки ZFS, маршрутизация и мониторинг музыкальной библиотеки не менялись.
|
||
|
||
## Итоговый рабочий результат
|
||
|
||
На 2026-09-29 после полного рестарта Taiga:
|
||
|
||
- FlareSolverr session `prowlarr` создаётся с proxy и pre-login.
|
||
- Прямой запрос через session получает `bb_session`.
|
||
- После полного restart: RuTracker — 50 результатов без ошибок; Kinozal — 14 результатов без ошибок.
|
||
- Три последовательных proxy-запроса получают один egress-IP.
|
||
- Искусственно удалённая FlareSolverr session автоматически восстановлена и снова logged-in.
|
||
- Ошибки Lidarr/SkyHook не относятся к FlareSolverr; их routing описан в [[family/how-to/arr-stack-taiga]].
|