Files
obsidian-vault/personal/tech/flaresolverr-taiga.md
T

315 lines
21 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.
# FlareSolverr на Тайге + обход блокировок индексеров
> ✅ **СОСТОЯНИЕ 2026-09-28: ГОТОВО. Все 6 индексеров рабочие, health чистый.**
> Контейнер `flaresolverr` (v3.5.2), порт `8191`, сеть `media_net`, `shm_size: 1gb`,
> `LOG_LEVEL=warning`, **`PROXY_URL=socks5://vless-proxy:1080`**.
> Compose — `/mnt/RED_2TB/docker/arr/docker-compose.yml` (6-й сервис).
> Бэкапы: `~truenas_admin/docker-compose.yml.bak-20260928-flaresolverr`,
> `~/backup-indexers-20260928-flaresolverr.json` (снимок 6 индексеров до правки тегов).
> Связка: [[personal/plans/flaresolverr-taiga-deploy]], [[personal/plans/lidarr-taiga-and-indexer-unblock]],
> [[family/projects/media-toolbox-taiga]], [[personal/tech/prowlarr-flaresolverr-cloudflare]],
> [[family/how-to/arr-stack-kraken]].
## ✅ РЕЗУЛЬТАТ (поиск «matrix» через `/api/v1/search`)
```
TOTAL 256
RuTor 100 ← был живой
RuTracker 50 ← ВПЕРВЫЕ с 2026-05-20
NoNaMe 50 ← ВПЕРВЫЕ
Kinozal 50 ← ВПЕРВЫЕ
Byrutor 6
```
`GET /api/v1/health` → `[]`, `GET /api/v1/indexerstatus` → `[]`. **Ни одной ошибки,
ни одного карантина.** Было 3/6, стало 6/6 (по выдаче — 5 трекеров; Kinozal (M) — зеркало
Kinozal с magnet-приоритетом, в общую выдачу дублируется).
## 🔑 ГЛАВНОЕ ОТКРЫТИЕ: FS-СЕССИЯ НЕ НАСЛЕДУЕТ `PROXY_URL`
Самый неочевидный пункт всей задачи. Симптом был **ложный**: Prowlarr писал
`blocked by CloudFlare Protection`, а лог FS — мгновенную ошибку за **7 секунд** (не таймаут!).
**Причина:** `PROXY_URL` (глобальный прокси) применяется к Chrome **в момент создания сессии**.
Сессия, созданная **до** появления `PROXY_URL`, остаётся **без прокси** навсегда —
в ней Chrome получает `net::ERR_NAME_NOT_RESOLVED` (DNS-блок!). Prowlarr шлёт запросы
с параметром `session`, и global-прокси её не перебивает.
Пруф — прямой вызов с сессией, созданной ДО прокси:
```
request.get kinozal + session:"prowlarr" (старая)
→ {"status":"error","message":"Error solving the challenge.
Message: unknown error: net::ERR_NAME_NOT_RESOLVED (chrome=152.0.7977.82)"}
```
Тот же запрос с сессией, созданной **ПОСЛЕ** `PROXY_URL` → `Challenge solved! 200`.
**Имя сессии Prowlarr — `prowlarr`** (обнаружено через `sessions.list`).
**Фикс:** удалить устаревшую сессию — `sessions.destroy`; Prowlarr пересоздаёт её сам
при следующем запросе, уже с рабочим `PROXY_URL`.
```bash
docker exec prowlarr sh -c 'curl -s -X POST http://flaresolverr:8191/v1 \
-H "Content-Type: application/json" \
-d "{\"cmd\":\"sessions.destroy\",\"session\":\"prowlarr\"}"'
```
> ⚠️ **Правило на будущее:** после ЛЮБОЙ правки `PROXY_URL` в compose **убить сессию
> `prowlarr`**, иначе старые сессии продолжат ходить без прокси и индексера будут
> «blocked by CloudFlare» при живом FS.
> ✅ При обычном перезапуске FS (watchtower/reboot) проблема НЕ повторится — сессия
> создастся заново уже с `PROXY_URL`.
## 🔑 ВТОРОЕ ОТКРЫТИЕ: FlareSolverr сам идёт через прокси (`PROXY_URL`)
На Кра́кене два механизма независимы: Cloudflare лечится FlareSolverr, DNS-блока нет.
**На Тайге блоков ДВА (DNS + Cloudflare), и FlareSolverr обязан ходить через `vless-proxy`** —
иначе он сам получит NXDOMAIN и не поможет.
**Решение:** глобальная env-переменная FlareSolverr **`PROXY_URL=socks5://vless-proxy:1080`**.
> ⚠️ Имя переменной — **`PROXY_URL`**, НЕ `HTTP_PROXY`/`HTTPS_PROXY` (проверено по DeepWiki
> FlareSolverr §4.2 «Proxy Configuration»). Формат **со схемой обязателен**
> (`socks5://host:port`); без схемы `urllib.parse` не разберёт.
> Приоритет: request > session > global. `PROXY_USERNAME`/`PROXY_PASSWORD` не нужны —
> `vless-proxy` без авторизации.
**Почему срабатывает именно global:** Prowlarr обращается к FS с параметром `session`,
а при наличии сессии request-прокси **игнорируется** → применяется global (`PROXY_URL`).
## ⚠️ ПИТФОЛЛ: `requestTimeout` = 60 с МАЛО, поднят до 180
Дефолтный `requestTimeout` прокси-элемента FlareSolverr в Prowlarr = **60 с**.
Решение CF-челленджа на `/forum/login.php` RuTracker и на kinozal занимает **80–100 с** →
`Error solving the challenge. Timeout after 60.0 seconds` в логе FS, Prowlarr отдаёт
`500 InternalServerError [POST] at http://flaresolverr:8191/v1`, в UI — «blocked by CloudFlare».
**Фикс:** `requestTimeout` = **180** (PUT `/api/v1/indexerproxy/2`).
Проверка: `docker logs flaresolverr` → `Challenge solved!`, а не `Timeout`.
> Замеры времени челленджа (kinozal.me/browse.php через FS): **78 с** холодный,
> **20 с** прогретый (CF-клэренс привязан к IP прокси), POST-логин — **97 с**.
## ⚠️ ПИТФОЛЛ: параллельный `testall` устраивает гонку за Chrome
Prowlarr тестирует все индексеры **одновременно**, а у FlareSolverr **один** Chrome.
При `testall` челленджи сыпятся таймаутами; если тестировать **по одному** (sequential) —
проходят. **Не верить результату параллельного `testall`** — гонять по одному.
Дополнительно: `curl` без `--max-time` виснет, если FS не отвечает — всегда ставить лимит.
## ⚠️ ПИТФОЛЛ: тег нужен И на прокси, И на индексере — и на ОБА прокси
Индексерам за DNS-блоком нужны **два** прокси-элемента и **два** тега:
| Прокси | id | Тег | Назначение |
|---|---|---|---|
| `vless-socks5` | 1 | `proxy` (id=1) | обход **DNS-блока** провайдера |
| `flaresolverr` | 2 | `flaresolverr` (id=2) | обход **Cloudflare** |
Значит на индексер вешаются **оба** тега: `tags=[1,2]`. Один прокси не закрывает оба блока.
Фактически навешено: id 1, 4, 5, 6 → `[1,2]`; id 2, 3 → `[1]` (RuTor/Byrutor живут на одном прокси).
## ⚠️ ПИТФОЛЛ: PUT `/api/v1/indexer/N` → 400, нужен `?forceSave=true`
Prowlarr при PUT **сразу тестирует** индексер. Если FS в этот момент не прошёл
(таймаут/гонка) — `HTTP 400` с `validationFailures`. Именно так «потерялись» теги
после первого PUT: они откатились к `[1]`.
**Рабочий путь:** `PUT /api/v1/indexer/N?forceSave=true` → **202** (сохраняет, тест пропускает).
Тест гонять отдельно, по одному. То же для `/indexerproxy/N`.
## Практические замечания
- **Логи FS пусты при `LOG_LEVEL=warning`** — это правильно: на `info` он пишет
`login_password` трекеров в plaintext. Не поднимать уровень ради «посмотреть».
- `sessions.create` → `ok`, `version 3.5.2` — быстрый smoke-тест живости FS.
- Прямая проверка FS из prowlarr:
```bash
docker exec prowlarr sh -c 'curl -s --max-time 150 -X POST http://flaresolverr:8191/v1 \
-H "Content-Type: application/json" \
-d "{\"cmd\":\"request.get\",\"url\":\"https://rutracker.org/forum/login.php\",\"maxTimeout\":130000}"'
# ожидается: {"status":"ok","message":"Challenge solved!", ...}
```
- `sleep 35` после старта контейнера — Chrome поднимается ~30 с; раньше этого `:8191` может не отвечать.
- `shm_size` и `sysctls` — **в блок сервиса** compose, не в `environment`.
- **`ERR_NAME_NOT_RESOLVED` в ответе FS = сессия без прокси** (см. открытие выше), а не «FS сломан».
- **Ключ API в `-H` ломается многоуровневым экранированием** (ssh → docker → sh).
Рабочий приём: `printf "X-Api-Key: <KEY>" > /tmp/h.txt` внутри контейнера, затем `curl -H @/tmp/h.txt`.
- **`python3` внутри контейнера prowlarr НЕТ** — разбирать JSON хостовым `python3`
(на Тайге есть `python3`, нет `curl` и `sqlite3`).
## Состояние индексеров после деплоя (2026-09-28, финал)
| id | Индексер | Теги | Статус |
|---|---|---|---|
| 1 | RuTracker | `[1,2]` | ✅ valid (был красный с 2026-05-20) |
| 2 | RuTor | `[1]` | ✅ valid |
| 3 | Byrutor | `[1]` | ✅ valid |
| 4 | NoNaMe Club | `[1,2]` | ✅ valid |
| 5 | Kinozal | `[1,2]` | ✅ valid |
| 6 | Kinozal (M) | `[1,2]` | ✅ valid |
## ✅ ЗАКРЫТО: Kinozal — «blocked by CloudFlare» при живом FS
Самая долгая часть задачи. Симптом маскировался под таймаут, причина оказалась другой.
**Что замерено (история диагностики):**
- Прямой socks5 к `kinozal.me/browse.php` → **403 Just a moment** за **0.9 с** (CF реален).
- FS `request.get` kinozal → `Challenge solved! 200`: **78 с** холодный, **20 с** прогретый.
- FS `request.post` kinozal/takelogin.php → `Challenge solved! 200`, **97 с**.
- Prowlarr: `blocked by CloudFlare Protection`, в логе FS — падение за **7 с** (не таймаут!).
**Ложный след:** `HTTP request failed: [500:InternalServerError] [POST] at http://flaresolverr:8191/v1`
и `Error solving the challenge. Timeout after 60/120/180 seconds` — выглядело как «челлендж
дольше таймаута». Поднятие `requestTimeout` 60→120→180 **не помогло**.
**Настоящая причина:** FS-сессия без прокси (см. главное открытие выше). Сессия `prowlarr`,
созданная до появления `PROXY_URL`, падала с `ERR_NAME_NOT_RESOLVED` за 7 с, Prowlarr
интерпретировал это как «CF блокирует» и уходил в retry → карантин.
**Фикс:** `sessions.destroy` сессии `prowlarr` → пересоздана с прокси →
Kinozal (5) и Kinozal (M) (6) прошли с первого раза (`{}`).
**Что исключено (не тратить время повторно):** ресурсы FS в норме (710 MB / 21 GB, shm 1 GB,
CPU 0.68%); канал прокси нормальный (kinozal через socks5 **0.6 с**, 908 KB/s); внутренний
таймаут Prowlarr в `config.xml` не настраивается.
## Compose-сервис (вставлен в `/mnt/RED_2TB/docker/arr/docker-compose.yml`)
```yaml
flaresolverr:
image: ghcr.io/flaresolverr/flaresolverr:latest
container_name: flaresolverr
restart: unless-stopped
environment:
- LOG_LEVEL=warning # НЕ info — info пишет пароли трекеров в plaintext
- BROWSER_TIMEOUT=60000
- TZ=Asia/Novosibirsk
- PROXY_URL=socks5://vless-proxy:1080
ports:
- "8191:8191"
networks:
- media_net
shm_size: 1gb # Кра́кен: 64 MB убивал Chrome
sysctls:
- net.ipv6.conf.all.disable_ipv6=1
```
Порядок деплоя: бэкап compose → правка **локально** (не sed на сервере) → `scp` → `cp` →
`cd /mnt/RED_2TB/docker/arr && docker compose up -d flaresolverr`.
⚠️ `docker compose up -d` **только из своего каталога**, иначе name-conflict (грабля Кра́кена).
> ⚠️ **Swap на Тайге = 0** (`/proc/swaps` пуст). На Кра́кене мёртвый swap + 64 MB `/dev/shm`
> убили Chrome в crash-loop. Здесь обошлось без swap: RAM 21 GB, доступно 5.6 GB, FS держит
> 710 MB, CPU 0.68%. **Swap не трогали** — не нужен при таком объёме памяти.
## История
- **2026-09-26** — разведка под Lidarr. Найдено: DNS-блок провайдера (NXDOMAIN на 4 трекера),
`vless-proxy` не в `media_net`. Прокси-маршрут для Prowlarr починен в тот же день (3/6 индексеров).
Остаток — Cloudflare на RuTracker/Kinozal. [[personal/plans/lidarr-taiga-and-indexer-unblock]]
- **2026-09-28** — **FlareSolverr развёрнут** по задаче Alex «ставь как на Кра́кене + прокси-контейнер».
Решено последовательно: (1) FS сам ходит через `vless-proxy` (`PROXY_URL`) — двойной обход DNS+CF;
(2) `requestTimeout` 60→180; (3) теги `[1,2]` на все CF-индексеры; (4) **`sessions.destroy`
сессии `prowlarr`** — последний блокер (сессия была создана до `PROXY_URL`).
Итог: **6/6 индексеров, health `[]`, поиск 256 результатов.**
RuTracker впервые `valid` за всё время существования стека (с 2026-05-20).
## ✅ ЗАКРЫТО: пароль RuTracker — рабочий (первый диагноз был НЕВЕРЕН)
**Итог 2026-09-28 (позже в тот же вечер):** сохранённая в Prowlarr пара
(`mallexxx` / 8 символов) **логинится успешно**. Проверено `request.post` через FlareSolverr
на `/forum/login.php`:
```
final_url = https://rutracker.org/forum/login.php ← НО форма не вернулась
len = 251 792 ← полная страница форума (~250 KB)
login_form_back = False ← форма логина НЕ переоткрылась
```
`login_form_back=False` + страница 251 KB = **сессия установлена**, это залогиненный форум.
Скрипт проверки: `/tmp/rt_login.py` (копия на Тайге; `python3 /tmp/rt_login.py "$U" "$P"`).
🔴 **Почему первый диагноз был ложным.** Ранее вывод «пароль неверен» сделан по признаку
`login_username` в HTML, но эта строка присутствует **и на залогиненной странице** (скрытая
форма быстрого входа / HTML-шаблон). Признак «форма вернулась» надо проверять по
**`final_url` + длине страницы**, а не по наличию подстроки `login_username` —
это дало ложное «Auth Failed».
> ⚠️ **Урок:** `Auth Failed` в `indexer/testall` Prowlarr **не означает неверный пароль**.
> Прежде чем требовать новый пароль у Alex — проверить логин отдельным `request.post`
> с `final_url` + `len` в ответе. Признак-подстрока ненадёжен.
⚠️ **Если Alex всё-таки сменил пароль на самом rutracker.org** — в Prowlarr лежит СТАРЫЙ
(проверено: `username len=8`, `password len=8` через `/api/v1/indexer/1`), его надо
обновить в `Indexers → RuTracker`, иначе после смены на трекере логин отвалится.
## ✅ ЗАКРЫТО: Radarr/Sonarr — каталоги категорий созданы
Radarr/Sonarr ждали `/storage/Downloads/radarr` и `/storage/Downloads/sonarr`
(Transmission пишет **плоско** в `/mnt/storage/Downloads`). Каталоги созданы:
```bash
mkdir -p /mnt/RED_2TB/storage/Downloads/radarr /mnt/RED_2TB/storage/Downloads/sonarr
```
В контейнерах видны как `/storage/Downloads/{radarr,sonarr}`, владелец `abc:abc`.
⚠️ `RemotePathMappingCheck` в health **кэшируется** — после создания каталогов ошибка
осталась, нужен `docker restart radarr sonarr` для перепроверки. См.
[[family/plans/lidarr-taiga-deploy]].
## Открытые пункты
- **Приёмка Alex в UI:** `https://prowlarr.mallexxx.duckdns.org` → Indexers → 6 зелёных без карантинов.
- ⏳ **`docker restart radarr sonarr`** — применить создание каталогов (апрув истёк 2026-09-28).
- ⏳ **`POST /api/v3/indexer/testall`** в Radarr/Sonarr — снять карантин с их собственных
копий индексеров (`RuTor`, `Kinozal`, `Kinozal M`). ⚠️ Отдаёт **400**, но это не ошибка:
парсить тело (массив с `isValid`), а не HTTP-код.
## ✅ Lidarr ↔ SkyHook: решено 2026-09-28 (встроенный прокси, НЕ env)
Смежная задача, решена в этой же сессии. Полный разбор — [[family/plans/lidarr-taiga-deploy]].
`api.lidarr.audio` (метаданные SkyHook) за Cloudflare:
- прямой запрос из контейнера → **403**;
- через `socks5h://vless-proxy:1080` → **200**;
- домен **резолвится** (`2606:4700:3031::ac43:df35`) — это **чисто CF, НЕ DNS-блок**.
⚠️ **FlareSolverr здесь бесполезен** — он обслуживает Prowlarr, а SkyHook зовёт сам Lidarr.
🔴 **ГЛАВНЫЙ ПИТФОЛЛ: env `HTTP_PROXY`/`HTTPS_PROXY` Lidarr НЕ ЧИТАЕТ.** Проверено:
compose-env + рестарт → всё тот же **403**. .NET-клиент SkyHook игнорирует env.
**Рабочее решение — встроенный прокси-конфиг Lidarr** (применяется без рестарта):
```bash
# GET /api/v1/config/host -> proxyEnabled:false
# PUT /api/v1/config/host/1 c полями:
# proxyEnabled: true
# proxyType: "http"
# proxyHostname: "vless-proxy"
# proxyPort: 1081 # ← HTTP-порт, НЕ 1080 (SOCKS5)
# proxyBypassFilter: "localhost,127.0.0.1,vless-proxy"
# proxyBypassLocalAddresses: true
```
Скрипт: `/tmp/lidarr_set_proxy.py` (на хосте Тайги; там `python3` **есть**, `curl` — нет).
**Результат:** `lookup?term=radiohead` → 10 результатов; артист добавлен; поиск релизов →
23 раздачи FLAC. Библиотека: 0 артистов → 1.
⚠️ **Ложный след при диагностике:** `api.lidarr.audio` отдаёт 403 **не всегда** — при
исчерпанном CF-лимите 403 бывает и у `curl`, что выглядит как «прокси не работает».
Различать: заголовок `x-rate-limit-remaining` присутствует только при живом ответе;
и сравнивать **прямой** vs **через прокси** запрос в одном ходе.
⚠️ Откат: env-вариант убран из compose (бэкап
`~truenas_admin/docker-compose.yml.bak-20260928-lidarr-proxy`).
## Общий вывод по прокси на Тайге (три разных механизма!)
На одном хосте понадобились **три независимых способа** прокинуть трафик через `vless-proxy`:
| Кто | Механизм | Ключ |
|---|---|---|
| Prowlarr (индексеры) | SOCKS5-прокси в Prowlarr + FlareSolverr | теги `[1,2]`, `PROXY_URL` у FS |
| FlareSolverr (Chrome) | глобальный прокси образа | env `PROXY_URL=socks5://...` (**НЕ** HTTP_PROXY) |
| Lidarr (SkyHook) | встроенный конфиг приложения | `config/host.proxyEnabled` (**env НЕ работает**) |
⚠️ **Не переносить рецепт одного сервиса на другой.** `arr`-сервисы внешне похожи, но
механизм прокси у каждого свой; проверять фактическим запросом, а не по аналогии.