Files
obsidian-vault/personal/tech/prowlarr-flaresolverr-cloudflare.md
T
Taiga b53dd70a15 [2026-09-26 09:10:28] syncthing: personal/tech/archive-org-collection-harvest.md personal/tech/balda-go-fx-pitfalls.md personal/tech/bilety-oxota-interaktiv.md personal/tech/cloudflare-tunnel-ssh-published-route.md personal/tech/deepseek-language-drift.md personal/tech/docker-data-root-mount-race.md personal/tech/docker-mac-disk-issues.md personal/tech/docker_colima_setup.md personal/tech/eagle-dashboard-launchd.md personal/tech/hermes-agent-improvements.md personal/tech/hermes-browser-toolsets.md personal/tech/hermes-fork-vs-upstream.md personal/tech/hermes-git-repo.md personal/tech/hermes-memory-architecture.md personal/tech/hermes-secret-redaction-bypass.md personal/tech/hermes-self-improvement-review.md personal/tech/home-network-config.md personal/tech/inter-site-throughput-taiga-to-mac.md personal/tech/inter-site-throughput-taiga-to-mac.md.bak-nedstab2 personal/tech/jellyfin-db-schema-mismatch.md personal/tech/karabiner-keyboard-config.md personal/tech/kraken-media-inventory-facts.md personal/tech/kraken-truenas-media-copies.md personal/tech/lampa-jellyfin-plugin.md personal/tech/lampac-deployment.md personal/tech/lampac-torrserver.md personal/tech/llm-model-selection-2026.md personal/tech/mac-print-shared-services.md personal/tech/modbus-rtu-sniffer-debugging.md personal/tech/multistream-single-flow-limit.md personal/tech/multistream-single-flow-limit.md.bak-nedstab2 personal/tech/music-tags-repair-truenas.md personal/tech/obsidian-mcp-ecosystem.md personal/tech/original-xbox-2025-guide.md personal/tech/prowlarr-flaresolverr-cloudflare.md personal/tech/radarr-sonarr-phantom-records.md personal/tech/roundtrip-key-verification.md personal/tech/ryujinx-mac-setup.md personal/tech/skill-arr-media-stack-setup-additions.md personal/tech/skill-docker-data-root-mount-race.md personal/tech/skill-lampac-kraken-deploy.md personal/tech/tirith-trust.md personal/tech/truenas-local-tree-comparison.md personal/tech/truenas-nfs4-acl-and-arrmultiuser.md personal/tech/truenas-zfs-panic-recovery.md personal/tech/vault-doc-pruning.md personal/tech/vless-space-subscription-egress.md personal/tech/watchlist-sync-feed.md personal/tech/watchtower-docker-updates.md personal/tech/xray-outbound-subscription-3xui.md personal/tech/xray-reverse-limits-private-network.md personal/tech/xray-reverse-tunnel-kraken-truenas.md personal/tech/xray-reverse-tunnel-kraken-truenas.md.bak-nedstab2 personal/tech/yandex-music-api.md
2026-09-26 09:10:28 +00:00

18 KiB
Executable File
Raw Blame History

title, created, updated, type, namespace, tags, related
title created updated type namespace tags related
Prowlarr FlareSolverr — Cloudflare-обход и починка индексеров 2026-09-20 2026-09-24 tech personal
prowlarr
flaresolverr
cloudflare
rutracker
kinozal
torrent
arr
kraken
infra
family/how-to/arr-stack-kraken
personal/projects/media-pipeline-pitfalls

Prowlarr + FlareSolverr — обход Cloudflare

Зеркало ключевых питфоллов скилла torrent-agent-pipeline (§ Питфоллы). Контекст: 2026-09-20, Kraken. RuTracker / Kinozal / Kinozal (M) были «красными» в Prowlarr.

Схема

Prowlarr (Kraken:9696) → FlareSolverr (Kraken:8191) → Cloudflare-защищённый трекер
     ⚠️ прокси применяется ТОЛЬКО при одинаковом tag на прокси И на индексере

Все контейнеры — в общей внешней сети media_net: radarr, sonarr, prowlarr, transmission, flaresolverr. Проверять фактическую сеть, а не compose-файл:

ssh kraken 'sudo docker inspect -f "{{range $k,$v := .NetworkSettings.Networks}}{{$k}} {{end}}" radarr sonarr prowlarr transmission flaresolverr'

🔴 Главная засада: прокси без tag молча не применяется

Созданный прокси (POST /api/v1/indexerproxy) с tags: [] не используется вообще — в UI и логе Prowlarr об этом ни слова, запросы продолжают идти напрямую в Cloudflare. Прокси применяется к индексерам только когда у прокси И у каждого индексера стоит один и тот же tag id.

KEY=$(grep -oP "(?<=<ApiKey>)[^<]+" /srv/.../docker/prowlarr/config/config.xml)

# 1. создать тег → получить id (обычно 1)
curl -X POST -H "X-Api-Key: $KEY" -H "Content-Type: application/json" \
  -d '{"label":"flaresolverr"}' http://localhost:9696/prowlarr/api/v1/tag

# 2. повесить tag на ПРОКСИ: GET целиком → jq .tags=[1] → PUT
curl -s -H "X-Api-Key: $KEY" http://localhost:9696/prowlarr/api/v1/indexerproxy/1 | jq ".tags=[1]" > /tmp/p.json
curl -X PUT -H "X-Api-Key: $KEY" -H "Content-Type: application/json" -d @/tmp/p.json \
  http://localhost:9696/prowlarr/api/v1/indexerproxy/1

# 3. повесить ТОТ ЖЕ tag на индексера (RuTracker=1, Kinozal=5, Kinozal M=6)
curl -s -H "X-Api-Key: $KEY" http://localhost:9696/prowlarr/api/v1/indexer/1 | jq ".tags=[1]" > /tmp/i.json
curl -X PUT -H "X-Api-Key: $KEY" -H "Content-Type: application/json" -d @/tmp/i.json \
  http://localhost:9696/prowlarr/api/v1/indexer/1

Пруф работы — только лог FlareSolverr, не лог и не UI Prowlarr:

ssh kraken 'sudo docker logs --tail 30 flaresolverr'
#   → Challenge detected. Title found: Just a moment...
#   → Challenge solved!

Непустой GET /api/v1/indexerproxy не означает, что прокси работает. Требуется Prowlarr ≥ 2.6 (в 2.5.2 прокси-модель только вводилась).

🔴 Блокировка индексера в SQLite — рестарт НЕ снимает

Prowlarr сам выключает упавший индексер на 24ч (Temporarily ignoring indexer X till +24h), состояние в таблице IndexerStatus в prowlarr.db. docker restart prowlarr его не сбрасывает — запрос продолжает отдавать 429 Indexer is disabled till ....

# бэкап перед правкой БД
cp /srv/.../docker/prowlarr/config/prowlarr.db <backup>/
ssh kraken 'sudo docker stop prowlarr'
sqlite3 /srv/.../docker/prowlarr/config/prowlarr.db "DELETE FROM IndexerStatus WHERE ProviderId IN (1,5,6);"
ssh kraken 'sudo docker start prowlarr'

ProviderId = id индексера. В контейнерах sqlite3 НЕТ — на хосте Kraken /usr/bin/sqlite3 ЕСТЬ.

⚠️ Безопасность: FlareSolverr логирует пароли в plaintext

На LOG_LEVEL=info его лог печатает postData запроса, т.е. login_username=...&login_password=... открытым текстом. Ставить LOG_LEVEL=warning в compose. Проверка после понижения: docker logs --since 5m flaresolverr | grep -c login_password → 0.

  flaresolverr:
    image: ghcr.io/flaresolverr/flaresolverr:latest
    environment:
      - LOG_LEVEL=warning        # ← не info: info пишет пароли трекеров
      - BROWSER_TIMEOUT=60000
    ports:
      - 8191:8191
    networks:
      - media_net

RuTor не фильтрует по категориям

В caps заявлены 2000(Movies)/5000(TV)/8000(Other), но с cat=5000 отдаёт 0 результатов, без cat — 100. Prowlarr сам пишет в полях индексера: «RuTor does not return categories in its search results. To sync to your apps, include 8000(Other)». В Sonarr/Radarr ставить категорию RuTor = 8000, не 5000.

429 в Sonarr/Radarr от упавшего индексера

HTTP request failed: [429:TooManyRequests] [GET] at [http://prowlarr:9696/prowlarr/N/api?t=caps...] — это не rate-limit трекера, а самоисключение Prowlarr. Не «ждать и повторять» — снимать IndexerStatus.

Диагностические грабли

  • POST /api/v3/indexer/test с {"indexerId": N} не работает (Radarr v6.1.1, Sonarr, Prowlarr v2.5.2) → HTTP 400 с validationFailures ('Name' must not be empty, … 'Priority' must be between 1 and 50). Эндпоинт валидирует тело как новый индексер. Ответ — массив, поэтому jq '.validationFailures' падает с Cannot index array with string. Рабочая альтернатива — testall:
    curl -s -X POST -H "X-Api-Key: $KEY" "http://localhost:7878/radarr/api/v3/indexer/testall" \
      | jq -r '.[] | "\(.id)\t\(.isValid)\t\(.validationFailures[0].errorMessage // "")"'
    # Sonarr: порт 8989, UrlBase /sonarr
    
  • Prowlarr маскирует упавшие индексеры — GET /api/v1/health и /api/v1/indexerstatus могут быть пустыми, пока индексер красный. Диагноз снимать из лога <config>/logs/prowlarr.debug.txt (НЕ logs/prowlarr.txt). Искать: grep -iE "rutracker|kinozal|Cloudflare|429".
  • «Кто живой» быстрее всего — поиском, не caps-тестом:
    curl -s -H "X-Api-Key: $KEY" "http://localhost:9696/prowlarr/api/v1/search?query=matrix&type=search" \
      | jq -r 'group_by(.indexer)[] | "\(.[0].indexer): \(length)"'
    
    По умолчанию до 100 результатов на индексер — «156 всего» ≠ «по 26 на каждый».

🔴 2026-09-24: FlareSolverr в crash-loop — Chrome не поднимается под chromedriver

Повод: Alex — «Мастерская сатаны: в торрентах ничего не нашлось, по каким трекерам ищет и можно ли влиять через Prowlarr?» Симптом оказался двухслойным: сверху пустая выдача PidTor, под ней — мёртвый FlareSolverr.

Слой 1 (верхний): PidTor отдаёт 503 из кэша, jac.red — 0 результатов

GET /lite/pidtor?title=Мастерская сатаны&year=2025
  → HTTP 503, Content-Length: 0, X-Invoke-Cache: HIT, t=0.007s   ← кэш

GET http://jac.red/api/v2.0/indexers/all/results?title=Мастерская сатаны&year=2025
  → HTTP 200, {"Results":[],"jacred":true}                        ← ЧЕСТНЫЙ ноль
GET …/results?title=Матрица&year=1999
  → HTTP 200, 132 раздачи                                        ← контроль: живой

jac.red знает 25 индексеров: anibelka anidub anifilm aniliberty animelayer anistar baibako bitru kinozal korsars leproduction lostfilm mazepa megapeer nnmclub rudub rutor rutracker selezen subsplease toloka torrentby ultradox viruseproject.

🔴 Список индексеров jac.red: GET http://jac.red/api/v2.0/indexers?configured=true → 200, ~4 КБ, массив с name. Рабочий способ посмотреть, по каким трекерам реально идёт поиск — не догадываться.

🔴 jac.red отдаёт 429 при частых запросах (nginx): пауза sleep 2-3 между вызовами обязательна. Формулировка ответа: nginx-страница 429 Too Many Requests, НЕ JSON.

🔴 title= должен быть URL-кодирован целиком. %20 в значении даёт HTTP 400 — использовать curl -G --data-urlencode "title=Мастерская сатаны". Ручная сборка query-строки с %20 в середине ломается.

Вывод по «Мастерская сатаны»: у фильма реально нет раздач на 25 трекерах jac.red. Механизм PidTor исправен (контроль на «Матрице» — 132 раздачи). Диагноз «сломан поиск» был бы неверным.

⚠️ Одноимённый фильм 2022 года лежит там как «Мастерская дьявола / Devil's Workshop» (Devils Workshop → 2 раздачи, bitru + kinozal, sid 0-1). Латиница в выдаче — не тот фильм, следить за годом.

Слой 2 (первопричина): FlareSolverr crash-loop ⇒ 3 индексера Prowlarr мертвы

RuTracker      (id=1)  disabledTill = 2026-09-25T10:17:51Z
Kinozal        (id=5)  disabledTill = 2026-09-25T10:17:50Z
Kinozal (M)    (id=6)  disabledTill = 2026-09-25T10:17:48Z
EscalationLevel = 9  (максимум — блокировка на 24 ч)

Проверка: GET /prowlarr/1/api?t=search&q=… → 429 Indexer is disabled till …. Прямой результат несмотря на то, что таблица IndexerStatus начиналась 20-го (начальные падения) и докатилась до EscalationLevel=9 именно 24-го в 10:17.

В логе FlareSolverr:

Error starting Chrome: Message: session not created: cannot connect to chrome at
  127.0.0.1:48249 from chrome not reachable
Exception: Error getting browser User-Agent. …
  File "/app/flaresolverr.py", line 136, in <module>
    flaresolverr_service.test_browser_installation()

Контейнер flaresolverr уходит в crash-loop (Restarting (1)), HTTP :8191 не отвечает (Connection reset by peer). Успешных решений челленджа в логе (Challenge solved) нет — считать их число: sudo docker logs flaresolverr 2>&1 | grep -c "Challenge solved".

Что проверено и исключено (не тратить время повторно)

Гипотеза Проверка Итог
Образ обновлён watchtower'ом и сломан image inspect → v3.5.2, Created=2026-09-12; в логах watchtower нет строк про flaresolverr ❌ не при чём
Нехватка RAM free, суммарный RSS всех процессов = 1.9 GB при MemAvailable ~1.8 GB ⚠️ фон, не корень
swap мёртв /proc/swaps пуст при живом /var/swap (512 MB); SwapFree падал до 240 kB ✅ реальный баг хоста, починен
IPv6: /etc/hosts отдаёт ::1 localhost первым, Chrome на IPv6-петле в контейнере /etc/hosts → ::1 localhost первый; добавлен net.ipv6.conf.all.disable_ipv6=1 (как у prowlarr) → disable_ipv6=1, hosts стал 127.0.0.1 localhost ❌ НЕ помогло, ошибка дословно та же
/dev/shm мал (64 MB) docker inspect → ShmSize=67108864; в контейнере df -h /dev/shm → 64M ⚠️ подозреваемый №1 из оставшихся

🔴 Chrome запускается вручную, но не под chromedriver. Проверено: docker exec flaresolverr sh -c '/usr/lib/chromium/chromium --headless=new --no-sandbox --disable-dev-shm-usage --disable-gpu --dump-dom about:blank' → работает, отдаёт verbose-лог компонентов; под управлением selenium — cannot connect to chrome at 127.0.0.1:<port>. В образе chromedriver не в PATH (which chromedriver → not found) — selenium ≥ 4 использует собственный Selenium Manager.

🔴 Вывод не делать по одной гипотезе. IPv6 выглядел убедительно (симптом «не видит chrome на 127.0.0.1» идеально ложится), но после применения ошибка воспроизвелась дословно — то есть причина не в резолве адреса.

✅ Починено в этой сессии

1. swap был мёртв — восстановлен. /proc/swaps пуст, а /var/swap (512 MB) на диске есть, ядро держало SwapFree=256 kB при нулевом активном swap. Без swap Chrome не получает память при пике старта.

sudo swapon /var/swap          # → /proc/swaps: /var/swap file 524272 -2
cat /proc/swaps                # проверка
grep -E "^(SwapTotal|SwapFree)" /proc/meminfo

⚠️ swapoff -a && swapon -a НЕ восстанавливает — даёт SwapFree: 0 kB. Помогает только явный sudo swapon /var/swap. В /etc/fstab строки для swap НЕТ (комментарий dphys-swapfile), systemd swap-unit не поднят (systemctl list-units --type=swap --all → 0 units). Автоподъём swap на этом хосте не настроен — после ребута swap снова может пропасть.

2. disable_ipv6 добавлен сервису flaresolverr (в docker/prowlarr/docker-compose.yml, бэкап docker-compose.yml.bak-20260924-193632). Эффекта не дало — оставлено как проверенная-неудачная попытка; при откате вернуть файл из бэкапа.

  flaresolverr:
    image: ghcr.io/flaresolverr/flaresolverr:latest
    environment:
      - LOG_LEVEL=warning        # ← не info: info пишет пароли трекеров
      - BROWSER_TIMEOUT=60000
    ports:
      - 8191:8191
    networks:
      - media_net
    sysctls:
      - net.ipv6.conf.all.disable_ipv6=1   # 2026-09-24: не помогло, см. выше
    shm_size: 1gb                            # ⏳ НЕ ПРИМЕНЕНО — кандидат на фикс

⏳ Незавершённое: добавить shm_size: 1gb и пересоздать (docker compose up -d --force-recreate flaresolverr), затем снять блокировки IndexerStatus для id 1/5/6 (см. секцию выше) и проверить POST http://localhost:8191/v1 {"cmd":"request.get","url":"https://kinozal.me/browse.php?c=0"} → ожидается status: ok. После этого — поиск «Мастерская сатаны» по всем 6 трекерам.

Дополнительные питфоллы сессии

  1. 🔴 escape из контейнера в crash-loop: docker exec отдаёт OCI runtime exec failed: exec failed: unable to start container process / cannot exec in a stopped container. Это признак рестарт-петли, а не «неверный exec» — сначала docker ps -a --filter name=<c> --format "{{.Status}} R={{.RestartCount}}".
  2. 🔴 sudo docker stats показывает 0B / 0B у всех контейнеров. Метрика врёт (недоступна на этом хосте) — считать память по контейнерам через /sys/fs/cgroup/system.slice/docker-<id>.scope/memory.current, а по процессам — ps -eo rss.
  3. 🔴 ps aux --sort=-rss | awk с %4/$6 даёт мусор — формат ps aux на этом хосте отдаёт 11 полей, %MEM и RSS нужно читать через ps -eo user,pid,rss,comm,args.
  4. 🔴 Долгие ssh-команды в crash-loop контейнера вешают терминал на 400+ с — резать диагностику на короткие скрипты и не ждать готовности контейнера дольше 240 с.
  5. ⚠️ sudo на Кра́кене требует TTY — ssh -t kraken '…'. Без -t: sudo: a password is required.

Источники