Files
obsidian-vault/personal/plans/flaresolverr-taiga-deploy.md
T

29 KiB
Executable File
Raw Blame History

FlareSolverr на Тайге + обход блокировок индексеров — план/отчёт

✅ СТАТУС 2026-09-29: ЗАДАЧА ЗАКРЫТА. Prowlarr логинится на RuTracker автоматически, поиск отдаёт CF-индексеры. Приёмка: search?query=radiohead&indexerIds=1 → 50 результатов. IndexerStatus → [], health → [], 6/6 индексеров enabled. 🔴 Истинная причина «не логинится»: в Prowlarr хранится пара mallexxx / m@n*w$uperP@$w0rD, а все диагностические тесты шли другим аккаунтом (keropjan_88). Капча RuTracker — симптом неверного пароля, а не блокер: с верной парой логин проходит автоматически и без капчи. Кука авторизации — bb_session (не bb_data). 🔴 Откат: эксперимент с образом flaresolverr-vnc + noVNC (порт 6080, роут vnc.mallexxx.duckdns.org, Caddy в media_net) снесён как ненужный — гипотеза «капчу решает человек» оказалась ложной. FS вернулся на штатный образ. ⚠️ Пункты 6 и 7 в разделе «Остаток» ниже — УСТАРЕЛИ. Логин RuTracker работает (проверено: search?indexerIds=1 → 50 результатов); капча-гипотеза снята. 🔧 Журнал отката (что снесено, питфоллы docker rm/bind-mount/root-каталог) — personal/tech/flaresolverr-taiga §«ЖУРНАЛ ОТКАТА». Полный разбор и питфоллы — personal/tech/flaresolverr-taiga. Связано: personal/plans/lidarr-taiga-and-indexer-unblock, family/projects/media-toolbox-taiga, family/how-to/arr-stack-kraken, personal/tech/prowlarr-flaresolverr-cloudflare, family/plans/lidarr-taiga-deploy.

🔴 Главный питфолл: FS-сессия prowlarr, созданная ДО появления PROXY_URL, навсегда остаётся без прокси → ERR_NAME_NOT_RESOLVED → Prowlarr пишет ложное «blocked by CloudFlare». Лечится sessions.destroy сессии prowlarr — пересоздаётся сама. 🔴 Второй питфолл: POST /indexer/test карантин НЕ снимает, а продлевает. Карантин живёт в таблице IndexerStatus и снимается только SQL (DELETE FROM IndexerStatus). 🔴 Порядок диагностики «Auth Failed»: сначала сверить пару логин/пароль из prowlarr.db (SELECT Settings FROM Indexers WHERE Id=1), и только потом всё остальное.

ФАКТИЧЕСКОЕ СОСТОЯНИЕ (2026-09-28, после деплоя)

Контейнер flaresolverr — ✅ работает

/mnt/RED_2TB/docker/arr/docker-compose.yml (122 строки), сервис flaresolverr:

  flaresolverr:
    image: ghcr.io/flaresolverr/flaresolverr:latest
    container_name: flaresolverr
    restart: unless-stopped
    environment:
      - LOG_LEVEL=warning
      - BROWSER_TIMEOUT=60000
      - TZ=Asia/Novosibirsk
      - PROXY_URL=socks5://vless-proxy:1080   # ← ключ: обход DNS-блока
    ports:
      - "8191:8191"
    networks:
      - media_net
    shm_size: 1gb                              # ← Кра́кен: 64 MB убивал Chrome
    sysctls:
      - net.ipv6.conf.all.disable_ipv6=1

Поднят: cd /mnt/RED_2TB/docker/arr && docker compose up -d flaresolverr → Up, рестартов 0. Логи пусты при LOG_LEVEL=warning — это норма (пароли трекеров не пишутся).

Swap НЕ трогали. Alex отклонил идею: «Назуя тебе свап? Памяти мало что-ли?» — и был прав: RAM 21 GB, FS держит 710 MB / 21 GB, CPU 0.68%. Swap на этом хосте не нужен.

🔑 ГЛАВНОЕ ОТКРЫТИЕ №1: FS нужен PROXY_URL, иначе он бесполезен на Тайге

На Кра́кене DNS-блока нет → FS ходит в трекер напрямую. На Тайге DNS-блок есть → FS сам должен ходить через vless-proxy. Решается глобальной env PROXY_URL (НЕ HTTPS_PROXY):

Что Значение
Переменная PROXY_URL (проверено по DeepWiki FlareSolverr §4.2)
Формат со схемой обязателен: socks5://vless-proxy:1080
Приоритет request > session > global
Авторизация не нужна (PROXY_USERNAME/PROXY_PASSWORD пусты)

⚠️ Prowlarr обращается к FS с параметром session; при наличии сессии request-прокси игнорируется → срабатывает именно global PROXY_URL. Схема A (env) — единственный рабочий вариант: у Prowlarr-прокси Socks5 только host/port/user/pass, поля «передать в FS» нет.

🔑 ГЛАВНОЕ ОТКРЫТИЕ №2: FS-сессия НЕ наследует PROXY_URL

Самая дорогая грабля задачи. PROXY_URL применяется к Chrome в момент создания сессии. Сессия, созданная до появления PROXY_URL, остаётся без прокси навсегда и падает с ERR_NAME_NOT_RESOLVED, а Prowlarr трактует это как «blocked by CloudFlare Protection».

Имя сессии Prowlarr — prowlarr. Фикс: sessions.destroy → пересоздастся сама.

⚠️ После ЛЮБОЙ правки PROXY_URL — убить сессию prowlarr. ✅ При обычном перезапуске FS (watchtower/reboot) проблема не повторится.

Prowlarr: прокси-элементы и теги

Элемент id Настройки tags
vless-socks5 (Socks5) 1 host vless-proxy, port 1080 [1]
flaresolverr (FlareSolverr) 2 host http://flaresolverr:8191/, requestTimeout 180 [2]

Теги: proxy = id 1, flaresolverr = id 2.

Индексерам нужны ОБА тега — proxy (DNS-обход через SOCKS5) и flaresolverr (CF-челлендж). Финальное состояние:

id Индексер tags Статус
1 RuTracker [1, 2] ✅ valid
4 NoNaMe Club [1, 2] ✅ valid
5 Kinozal [1, 2] ✅ valid
6 Kinozal (M) [1, 2] ✅ valid
2 RuTor [1] ✅ valid
3 Byrutor [1] ✅ valid

Пруф работы FS (не UI — прямой HTTP)

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!", "solution": {"status": 200, ...}}

Результаты прямых тестов:

URL Ответ FS
rutracker.org/forum/index.php ok / Challenge not detected / 200
rutracker.org/forum/login.php ok / Challenge solved! / 200
kinozal.me/browse.php ok / Challenge solved! / 200
nnmclub.to/forum/index.php ok / Challenge not detected / 200
sessions.create ok / Session created successfully / v3.5.2

🔴 ПИТФОЛЛ: PUT /api/v1/indexer/N падает 400 из-за теста FS

Prowlarr при PUT сразу тестирует индексер. Если FS в этот момент не прошёл — HTTP 400 с validationFailures (HTTP request failed: [500:InternalServerError] [POST] at [http://flaresolverr:8191/v1]). Теги при этом НЕ применяются (откатываются).

Обход — ?forceSave=true:

curl -X PUT -H @/tmp/h.txt -H "Content-Type: application/json" \
  -d @/tmp/ix1-new.json "http://localhost:9696/api/v1/indexer/1?forceSave=true"
# → 202 (сохранил, тест пропущен)

🔴 ПИТФОЛЛ: requestTimeout=60 у FS-прокси МАЛО

Дефолт прокси-элемента — 60 с. CF-челлендж на /forum/login.php и kinozal занимает 78–97 с → Error solving the challenge. Timeout after 60.0 seconds, индексер краснеет. Поднять до 180 (правка PUT-ом прокси-элемента /2). PUT → 202.

🔴 ПИТФОЛЛ: testall параллельный → Chrome захлёбывается

POST /api/v1/indexer/testall тестирует все 6 индексеров одновременно, а Chrome в FS — один. Часть челленджей отваливается по таймауту (ложный «blocked by CloudFlare Protection»). Правило диагностики: если testall показал Cloudflare-блок — перепроверять одиночным request.get с большим maxTimeout, а не верить testall. Это грабля, стоившая времени.

ПЛАН ВЫПОЛНЕН — по фазам

Фаза Что Статус
0 Внешняя блокировка / DNS-прокси ✅ была закрыта ранее (2026-09-26)
1 FlareSolverr контейнер + PROXY_URL ✅ выполнено
2 Прокси-элемент + теги [1,2] + карантин ✅ выполнено
3 Проверка поиска ✅ 256 результатов
4 sessions.destroy (не входила в план, найдена по ходу) ✅ выполнено

🔴 Что чуть не стало ложным выводом (методический урок)

Первые прогоны дали «4/6», и вывод «Kinozal упирается в скорость CF-челленджа, не в конфиг» был неверным. Спасло то, что замер падения показал 7 секунд — при 78–97 с у челленджа это физически не таймаут. Отсюда найден ERR_NAME_NOT_RESOLVED и корень. Урок: когда «таймаут» короче самого медленного шага — это не таймаут, а другая ошибка. Смотреть фактическое время, а не текст сообщения.

Бэкапы (перед изменениями)

Файл Путь
compose (до правки) ~truenas_admin/docker-compose.yml.bak-20260928-flaresolverr (2313 B)
индексеры (до тегов) ~/backup-indexers-20260928-flaresolverr.json (390701 B, на Mac)

Рабочая техника API-вызовов (повтор от грабель)

Ключ Prowlarr в файл внутри контейнера + -H @/tmp/h.txt — иначе кавычки ломаются на уровне ssh/sh, и API отвечает 401 даже с верным ключом:

docker exec prowlarr sh -c 'printf "X-Api-Key: 35c8b3f497114076a6150ea0d9504845" > /tmp/h.txt; \
  printf "Content-Type: application/json" > /tmp/ct.txt'
docker exec prowlarr sh -c 'curl -s -H @/tmp/h.txt http://localhost:9696/api/v1/indexer'

Разбор JSON — на хосте (python3 в контейнере Prowlarr НЕТ: sh: python3: not found). Долгие операции (testall) — через docker exec -d в фон + файл-маркер .done. curl без --max-time виснет, если FS не отвечает — всегда ставить лимит.

Разведка (2026-09-28, что было ДО работы)

Что УЖЕ было сделано (не переделывать!)

Прошлый план (2026-09-26) предполагал два блока. Блокер №2 (DNS) был закрыт, а с ним и большая часть Фазы 0:

Что Факт 2026-09-28
vless-proxy в media_net ✅ есть, IP 172.16.17.6, резолвится из prowlarr
Прокси в Prowlarr ✅ vless-socks5 (id=1), Socks5, host vless-proxy, port 1080
Тег ✅ proxy (id=1); навешен и на прокси, и на все 6 индексеров
Работоспособность прокси ✅ rutracker.org → 301, nnmclub.to → 200, kinozal.me → 200
URL индексеров ✅ Kinozal/Kinozal(M) уже на kinozal.me (не мёртвый .tv)
Поиск через Prowlarr ✅ RuTor 100 + Byrutor 6 на «matrix»

Что ОСТАВАЛОСЬ (суть задачи)

Остаточная проблема — не DNS, а Cloudflare. Прямой факт:

GET https://rutracker.org/forum/login.php  через socks5h://vless-proxy:1080
  → <title>Just a moment...</title> + challenges.cloudflare.com   ← JS-челлендж

IndexerStatus (без снятия): карантин у id 1 (RuTracker), 5 (Kinozal), 6 (Kinozal M). initialFailure = 2026-05-20 (день деплоя). FlareSolverr на Тайге отсутствовал (docker ps -a | grep flare → пусто).

Риски (грабли Кра́кена — что проверяли заранее)

Из personal/tech/prowlarr-flaresolverr-cloudflare §2026-09-24 — там FlareSolverr ушёл в crash-loop, Chrome не поднимался под chromedriver.

Условие Кра́кен (сломано) Тайга Итог
/dev/shm 64 MB → Chrome падал 64 MB ✅ задали shm_size: 1gb
swap пуст → пик старта убивал пуст, Swap=0 ✅ не нужен — RAM 21 GB
RAM мало 21 GB, 5.6 GB free ✅ хватает
IPv6 ::1 localhost — добавили disable_ipv6=1 (безвредно)

История

  • 2026-09-26 — разведка под Lidarr. Найдено: DNS-блок провайдера (NXDOMAIN на 4 трекера), vless-proxy не в media_net. Прокси-маршрут для Prowlarr починен в тот же день (3/6 индексеров). Остаток — Cloudflare. Первоначальный план — personal/plans/lidarr-taiga-and-indexer-unblock.
  • 2026-09-28 — разведка: DNS-блокер уже закрыт, остаток — Cloudflare, FS отсутствует. Составлен план, ждал «go». Ничего не изменено.
  • 2026-09-28 (тот же день, после «Го») — ВЫПОЛНЕНО. FlareSolverr развёрнут, 6/6 индексеров, health [], поиск 256. Питфоллы: requestTimeout 60→180, ?forceSave=true, гонка testall, и главный — смена PROXY_URL не обновляет существующую FS-сессию.
  • 2026-09-28 (вечер, тот же день) — Lidarr дозакрыт до прод-уровня. SkyHook-блокер снят: api.lidarr.audio → 403 прямым, 200 через прокси; env HTTP_PROXY Lidarr НЕ читает, рабочий фикс — встроенный config/host.proxyEnabled → vless-proxy:1081. Проверено end-to-end: lookup → артист → 23 раздачи. Попутно: созданы каталоги Downloads/{radarr,sonarr} (Radarr/Sonarr их ждали), выявлен неверный пароль RuTracker. Детали — family/plans/lidarr-taiga-deploy, personal/tech/flaresolverr-taiga.

🔴 2026-09-28 (ночь): НАЙДЕНА ИСТИННАЯ ПРИЧИНА ЗАЛИПА — таблица IndexerStatus

Итог долгой петли: «снять карантин тестом → warning возвращается → тест падает заново». Петля не сходилась, потому что причина лежит в БД Prowlarr, а не в прокси/FlareSolverr.

Пруф — прямой дамп таблицы (хост Тайги, sqlite3 в контейнере НЕТ, на хосте ЕСТЬ):

DB=/mnt/RED_2TB/docker/arr/prowlarr/prowlarr.db
sqlite3 "file:$DB?mode=ro" \
  "SELECT Id, ProviderId, InitialFailure, MostRecentFailure, EscalationLevel, DisabledTill FROM IndexerStatus;"
Id  ProviderId  InitialFailure            EscalationLevel  DisabledTill
1   5 Kinozal      2026-09-28 09:43:24    2                2026-09-28 10:08
2   6 Kinozal M    2026-09-28 09:32:45    2                —
3   4 NoNaMe       2026-09-28 07:57:42    0                —
4   2 RuTor        2026-05-20 05:45:18    0                —
5   1 RuTracker    2026-09-28 09:04:28    9                2026-09-29 09:46   ← СУТКИ
6   3 Byrutor      —                      0                —

🔴 RuTracker: EscalationLevel = 9 (максимум), DisabledTill = +24 ч. Prowlarr сам выключил индексер на сутки. Пока запись держится, caps отдаёт 429, Prowlarr не делает новых попыток, фоновый health-чек Radarr/Sonarr/Lidarr бьёт по 429 → warning каскадом во все четыре сервиса. Отсюда «Radarr health чист, а warning живёт» — он живёт не у Radarr.

⚠️ Тест индексера карантин НЕ снимает, а ПРОДЛЕВАЕТ. Наблюдалось вживую: DisabledTill 15:44 → 21:45 после одного POST /indexer/test. То есть каждая попытка «починить тестом» удлиняла блокировку. Это и была петля.

✅ РАБОЧИЙ ПЛАН СНЯТИЯ (согласован, 2 команды + бэкап)

На Кра́кене применялся тот же приём — см. family/how-to/arr-stack-kraken §«(3) Блокировки индексера в БД — рестарт их НЕ сбрасывает».

1. Бэкап через .backup, НЕ cp (БД в WAL-режиме):

DB=/mnt/RED_2TB/docker/arr/prowlarr/prowlarr.db
TS=$(date +%Y%m%d-%H%M%S)
sqlite3 "file:$DB?mode=ro" ".backup /home/truenas_admin/prowlarr.db.bak-$TS"
shasum -a 256 "$DB" "$OUT"        # сверить, что копия снята

✅ Сделано: ~/prowlarr.db.bak-20260928-032611 — 581 632 байт, sha256 исходника d792777c3545969dba57339d1b956f11aef40da91596b266839068a1a1af7845.

2. Стоп → очистка → старт (⚠️ docker stop требует апрува Alex — истёк дважды):

docker stop prowlarr
sqlite3 "$DB" "DELETE FROM IndexerStatus WHERE ProviderId IN (1,5,6);"
docker start prowlarr

3. Проверка:

PK=$(cat /home/truenas_admin/pk.txt)
curl -s -H "X-Api-Key: $PK" http://localhost:9696/api/v1/indexerstatus   # → пусто
for I in 1 5 6; do curl -s -o /dev/null -w "idx$I=%{http_code}\n" \
  "http://localhost:9696/$I/api?t=caps&apikey=$PK"; done               # → 200

Таблицы в prowlarr.db (для справки): Indexers, IndexerStatus, IndexerProxies, ApplicationIndexerMapping, IndexerDefinitionVersions.

⚠️ Урок: health-эндпоинты arr-сервисов не являются источником истины о блокировках. На Кра́кене это записано отдельно: «GET /api/v1/health и /api/v1/indexerstatus НЕ показывают причины блокировки» — авторитет за prowlarr.debug.txt и таблицей IndexerStatus. На Тайге indexerstatus причины показывал, но снятие через API не срабатывало — только SQL.

Остаток после сессии 2026-09-28 (не блокирует Prowlarr/FlareSolverr)

  1. ✅ СНЯТО через SQL 2026-09-29. docker stop prowlarr → DELETE FROM IndexerStatus; → docker start prowlarr. Результат: rows=0, quick_check=ok, 6 определений на месте, health → [], indexerstatus → [], все 6 caps → 200. 🔴 НО поиск не починился: через минуты CF-индексеры снова в карантине, поиск даёт total=79 (только NoNaMe 47 + RuTor 32). Причина — отсутствие bb_data, см. п. 6. Скрипт: /tmp/clear_indexerstatus.sh. Бэкап: ~/prowlarr.db.bak-20260928-032611.
  2. ✅ Пароль RuTracker — вопрос закрыт: пароль ВЕРНЫЙ. Проверено request.post через FS: len=251 792, форма логина не вернулась. Первый диагноз «пароль неверен» был ложным — признак «форма вернулась» проверять по final_url + длине HTML, а не по подстроке login_username (она есть и на залогиненной странице). Подтверждено и через сессию prowlarr: логин 254 410, поиск 254 745, Auth Failed в HTML отсутствует. Auth Failed в Prowlarr при живом логине = следствие IndexerStatus, а не пароля.
  3. ✅ Radarr/Sonarr: docker restart radarr sonarr lidarr выполнен → RemotePathMappingCheck ушла, health пуст у обоих.
  4. ⚠️ RuTor: no results in the configured categories — не блокировка. На Кра́кене тот же дефект, лечение известно: RuTor не фильтрует по категориям, ему нужна 8000(Other), не 5000. На Тайге не применено.
  5. Приёмка Alex в UI: https://prowlarr.mallexxx.duckdns.org → 6 зелёных; https://lidarr.mallexxx.duckdns.org → поиск артиста работает. Alex подтвердил: «все зеленое, логин починен». Открытый вопрос по swap закрыт Alex (не нужен — RAM 21 GB).
  6. 🔴 ГЛАВНЫЙ НЕЗАКРЫТЫЙ ПУНКТ (2026-09-29): логин RuTracker не выполняется. В cookies сессии нет bb_data (кука авторизации) — только cf_clearance + bb_guid. Лог Prowlarr: FlareSolverrException: "Empty cookies returned by FlareSolverr" (FlareSolverr.cs:68). Форма индексера принимает только username/password — поля для cookie нет, подставить живую сессию из браузера нельзя. Нужен Alex: зайти на rutracker.org браузером с того же IP (vless-proxy), пройти капчу один раз, либо отключить капчу в профиле. Полный разбор — personal/tech/flaresolverr-taiga §«ИТОГОВЫЙ КОРЕНЬ» и §«СВЕРКА С КРА́КЕНОМ».
  7. 🔴 «Как на Кра́кене» — НЕ рецепт (2026-09-29). Проверено на живом Кра́кене: капча-солвера там нет (только FlareSolverr, requestTimeout: 60), а карантин идентичен Тайге — RuTracker/Kinozal/Kinozal(M) EscalationLevel=9, DisabledTill=2026-09-27. Обе площадки красные по одной и той же причине. Не строить план на посылке «на Кра́кене работает». Детали — personal/tech/flaresolverr-taiga §«СВЕРКА С КРА́КЕНОМ», family/how-to/arr-stack-kraken.

🔴 СЕССИЯ 2026-09-29 (вечер): разбор идеи Alex + свой образ flaresolverr-vnc

Задача Alex: «ароматизировать процесс насколько возможно — уведомление в ТГ от hermes-taiga, соединение моего браузера через 3x-ui через тот же туннель, выдача и установка куки обратно».

Результат — три из четырёх идей отвергнуты фактами:

Идея Вердикт Причина
Свой браузер через 3x-ui по тому же туннелю ❌ vless-proxy — клиент xray, не сервер. cf_clearance привязан к IP + UA + TLS-fingerprint
Впихнуть куки обратно в Prowlarr ❌ Индексер RuTracker принимает только username/password — поля для cookie нет
Капча-солвер FS (CAPTCHA_SOLVER) ❌ Официально non-functional (DeepWiki FS; issue #1452 закрыт без решения)
Ручной вход в Chrome внутри FS + persistent профиль ✅ Единственный рабочий путь

Сделано (шаг 1 из 3) ✅:

  • Собран образ flaresolverr-vnc:latest — база FS + Xvfb + fluxbox + x11vnc + novnc
    • supervisor, 5 процессов. Файлы: /mnt/RED_2TB/docker/arr/fs-vnc/{Dockerfile,supervisord.conf,entrypoint-vnc.sh}.
  • Compose: образ подменён, добавлены порт 6080:6080 (noVNC) и volume /mnt/RED_2TB/docker/arr/flaresolverr-config:/config (persistent профиль Chromium).
  • Профиль вынесен через XDG_CONFIG_HOME=/config/chromium-profile, FS запущен с HEADLESS=false.
  • Проверено: docker compose config -q OK, сборка ~215 с, контейнер Up, API → {"status":"ok","version":"3.5.2"}, http://localhost:6080/vnc.html → 200.
  • Бэкап: /mnt/RED_2TB/docker/arr/docker-compose.yml.bak-20260928-profvol (2723 B).

🔴 ОТКАТ: эксперимент flaresolverr-vnc снесён (2026-09-29)

Раздел ниже — история неудачного эксперимента, оставлен чтобы не повторять. Итог: гипотеза «капчу решает человек» была ложной → всё построенное снесено.

Что было построено и что с ним стало:

Артефакт Статус
Образ flaresolverr-vnc:latest (Xvfb+fluxbox+x11vnc+noVNC) ❌ снесён, FS вернулся на ghcr.io/flaresolverr/flaresolverr:latest
Порт 6080:6080 в compose ❌ убран
Volume /mnt/RED_2TB/docker/arr/flaresolverr-config:/config ❌ убран
Каталог сборки /mnt/RED_2TB/docker/arr/fs-vnc/ ❌ удалён
Роут vnc.mallexxx.duckdns.org в Caddyfile ❌ убран, config валиден, reload сделан
docker network connect media_net caddy ❌ откачен (network disconnect), Caddy снова в caddy_default + transmission_default

Почему это было лишним: Prowlarr логинится на RuTracker сам, без VNC и без человека. Капча в ответе трекера была реакцией на неверный пароль (тесты шли аккаунтом keropjan_88 вместо хранящегося в Prowlarr mallexxx), а не требованием трекера к живому человеку.

⚠️ Правильный порядок при «Auth Failed» — начинать с данных, а не со сборки инфраструктуры:

DB=/mnt/RED_2TB/docker/arr/prowlarr/prowlarr.db
sqlite3 "file:$DB?mode=ro" "SELECT Settings FROM Indexers WHERE Id=1;"
# сверить username/password с тем, чем тестируешь — ЭТО ПЕРВЫЙ ШАГ

⚠️ Уточнение методики: Alex работает по схеме коммит → правка → заливка → проверка Alex. Но это не значит, что под каждую гипотезу нужно строить инфраструктуру: сначала проверять исходные данные (пара логин/пароль в БД), и только потом — строить.