The Daily Newsstand · Free, Always
Monday, October 26, 2026

Как я заставил бесплатные LLM работать из России и что узнал про Cloudflare

Translate

Недавно я потратил вечер на задачу, которая звучит просто: «хочу, чтобы бесплатные модели отвечали из России». Оказалось, что там три разные проблемы, которые легко перепутать, и одна ловушка, в которую я сам и попал.

Рассказываю по порядку, с командами и логами.

Проблема первая: 403 Access denied by security policy

Первое, что я увидел, запустив агент с бесплатными моделями:

AI_APICallError: Forbidden

Никаких деталей. Я решил, что дело в ключе — сгенерировал новый, вставил. Тот же результат.

Тогда я посмотрел на сырые заголовки ответа:

HTTP 403 Forbidden
Server: cloudflare
CF-RAY: a4d9c891184604fe-HKG
Set-Cookie: __cf_bm=...
{"success": false, "error": "Access denied by security policy."}

Вот оно. CF-RAY — значит, ответил Cloudflare, а не сам сервис. Access denied by security policy — это блокировка на входе, по репутации IP. Запрос не дошёл до OpenRouter вообще: ключ не проверялся.

Проверить это просто:

403 + Access denied by security policy  →  блок по IP
401 + Authentication Fails              →  ключ неверный или не от того сервиса
404 + Not found for account             →  модель недоступна аккаунту
429                                     →  лимит исчерпан

Смена ключа при 403 не помогает. Я проверил два разных ключа с одного IP — оба дали одинаковый 403.

Дальше интереснее. Я запускал проверку несколько раз и заметил, что меняется CF-RAY:

CF-RAY: ...-HKG   (Гонконг)
CF-RAY: ...-DME   (Москва)

Блок не привязан к конкретному датацентру. Он привязан к моему IP. Значит, лечится только сменой адреса.

Проблема вторая: WARP не работает, и это неочевидно

Первый совет, который дают в такой ситуации — «поставь Cloudflare WARP, он бесплатный».

У меня стоял клиент с готовым WARP-профилем. При попытке подключиться:

error patching outbound[m4 § 0][custom]:
netip.ParsePrefix("/24"): ParseAddr(""): unable to parse IP

Я полез в конфиг:

"warp": {
    "enable": false,
    "clean-ip": "auto",
    "account-id": "",
    "access-token": "",
    "wireguard-config": ""
}

Пусто. WARP-аккаунт не зарегистрирован, поэтому clean-ip: auto не может ничего разрешить и подставляет пустую строку — парсер падает.

Почему не зарегистрирован? Проверяю эндпоинты:

188.114.97.170:894      →  заблокирован
162.159.192.1:894       →  заблокирован
api.cloudflareclient.com →  timeout

Серверы регистрации WARP недоступны. Поэтому аккаунт не создаётся, поэтому профиль мёртвый.

И вот ирония, ради которой стоило всё это писать: WARP выдаёт вам адрес Cloudflare. А блокирует вас тоже Cloudflare. Даже если бы он подключился, результат непредсказуем — вы пришли бы к Cloudflare через Cloudflare.

Вывод: WARP в России для этой задачи не работает. Не «надо настроить», а именно не работает — эндпоинты режутся.

Что работает: локальный прокси вместо VPN

Полноценный VPN требует прав администратора — создание TUN-адаптера. У меня их не было, и это оказалось не проблемой.

Есть разница, которую многие путают:

VPN (TUN)

Локальный прокси

Заворачивает

весь компьютер

только указанные программы

Нужен админ

да

нет

Подходит для

браузер, игры, всё

конкретный инструмент

Мне нужно было, чтобы работал один агент. Хватило локального прокси: sing-box слушает 127.0.0.1:18888, и нужная программа ходит через него.

Ловушка, в которую я попал

Я сделал то, что кажется логичным — прописал прокси глобально:

[Environment]::SetEnvironmentVariable('HTTPS_PROXY','http://127.0.0.1:18888','User')

Агент заработал. А потом у меня перестал запускаться Roblox:

HttpError: ConnectFail
Critical failure fetching flags, terminating application.

Он пытался идти через мой прокси, а прокси в тот момент перезапускался. Соединение рвалось, клиент падал.

Глобальные переменные прокси наследуют все программы. Игры, лаунчеры, обновляторы — всё, что не должно идти через прокси, идёт через него и ломается.

Правильно — задавать прокси только внутри процесса:

$env:HTTPS_PROXY = 'http://127.0.0.1:18888'
& myapp.exe

Тогда он виден одной программе и никому больше.

Проблема третья: где брать серверы

Публичные vless:// конфиги лежат в открытых репозиториях. Я скачал список:

2196 reality-конфигов, 1053 уникальных хоста

Дальше — самое интересное. Проверять их через ping или Test-NetConnection бесполезно. У Reality TCP-порт может быть открыт, а рукопожатие — не проходить. Порт открыт, сервер принимает соединение, но TLS-сессия не поднимается.

Правильная проверка — реальный HTTP-запрос через прокси, и сравнение выходного IP с вашим:

Invoke-RestMethod https://api.ipify.org -Proxy http://127.0.0.1:18888

Если вернулся ваш IP — трафик шёл напрямую, прокси не сработал.

Замер: из 5681 конфига живыми оказались 2.

И тут я поймал сам себя

Я написал скрипт проверки на Python. Запустил — он бодро отрапортовал:

[1] OK  77.110.105.122      exit IP 94.245.148.251
[2] OK  158.160.160.21      exit IP 94.245.148.251
...
working: 6 / 6

Шесть из шести! Отличный результат. Кроме одной детали: все шесть вернули один и тот же IP — мой собственный. То есть urllib молча шёл напрямую, а скрипт засчитывал это как успех.

Я добавил сравнение с собственным IP — и результат стал честным:

[1] fail  77.110.105.122
[2] fail  158.160.160.21
working: 0 / 8

Мораль: проверка, которая не отличает «сработало» от «не сработало, но запрос всё равно прошёл», хуже отсутствия проверки. Она даёт ложную уверенность.

Что делать с этим дальше

Схема, которая у меня в итоге заработала:

  1. Скачать публичный список vless:// конфигов

  2. Отфильтровать по реальному запросу, а не по открытому порту

  3. Поднять локальный прокси на выживших

  4. Задавать переменные прокси внутри процесса, а не глобально

Пункты 2 и 4 — те самые грабли, на которые я наступил. Если делать это вручную, на шаге 2 легко получить ложный результат, а на шаге 4 — сломать себе полсистемы.

Поэтому оба шага я закрыл скриптами. Они лежат в открытом репозитории вместе с таблицей провайдеров (какие требуют карту, какие VPN, какие лимиты):

github.com/n1lokaDeep/free-llm-russia

Файл

Что делает

check-configs.py

отбирает кандидатов из публичного списка конфигов

verify-live.py

проверяет каждый реальным запросом (с защитой от ложных срабатываний)

start-proxy.ps1

поднимает локальный прокси на 127.0.0.1:18888

proxy.ps1

управление: start / stop / restart / status

Порядок:

python scripts/check-configs.py --top 80
python scripts/verify-live.py
powershell -File scripts/start-proxy.ps1
powershell -File scripts/proxy.ps1 status

Короткие выводы

  1. 403 Access denied by security policy — это блок по IP, а не проблема с ключом. Смотрите CF-RAY в заголовках: если он есть, ответил Cloudflare, а не сервис.

  2. WARP в России не работает — серверы регистрации заблокированы. И даже если бы работал, вы пришли бы к Cloudflare через Cloudflare.

  3. Прокси не прописывайте глобально. Это ломает игры и лаунчеры с ConnectFail. Только внутри процесса.

  4. Проверяйте прокси реальным запросом и сравнением IP. Открытый TCP-порт ничего не значит. Скрипт, который этого не делает, покажет «6 из 6 работает», когда не работает ничего.

  5. Публичные конфиги быстро умирают. Из 5681 живых было 2. Нужен автоматический отбор, а не ручной перебор.

Если вы наступали на похожие грабли — расскажите в комментариях, интересно сравнить. И если найдёте неточность в разборе заголовков или в поведении WARP, поправьте: провайдеры меняют политику без предупреждения, и то, что работало в октябре, к декабрю может устареть.

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.

Как я заставил бесплатные LLM работать из России и что узнал про Cloudflare — KioskNews