Когда я начинал писать Node.js-сервис, который должен был интегрироваться с LLM-моделью, я уже понимал, что доступ к некоторым зарубежным API из России может быть проблемой. Именно поэтому моим первоначальным выбором была модель от Yandex Cloud — Yandex GPT.
Но после того как я и мои товарищи немного пообщались с ней, стало ясно, что Yandex GPT нам не подходит. Её ответы были слишком неестественными, «нечеловеческими» — особенно это было заметно в нашем конкретном кейсе. Поэтому пришлось искать альтернативу среди зарубежных моделей. Вариант обучать собственную модель отпал сразу — опыта у меня в этом не было, а искать кого-то, кто сможет это сделать, не было времени, так как хотелось быстро запустить. Так выбор пал на Gemini API от Google, о котором было много позитивных отзывов.
Однако это означало, что нужно было как-то решить проблему доступа из России, ведь мой сервис размещён именно в Yandex Cloud.
Переносить всё на зарубежные серверы? Не хотелось совсем...
Было понятно сразу, что Gemini не даст доступ моему сервису из России, я слегка начал фрустрировать. У меня уже была работающая инфраструктура в Yandex Cloud, а времени до релиза оставалось совсем немного. Понимание того, что придётся переносить сервис или хотя бы разворачивать где-то дополнительный сервер, устанавливать окружение, настраивать деплой и разбираться с новой инфраструктурой, совсем не добавляло оптимизма.
Вдобавок я прекрасно осознавал, что любая миграция — это не просто перенос кода. Это еще и:
потенциальные ошибки при разворачивании,
необходимость перестраивать CI/CD,
дополнительный мониторинг нового сервера.
Чем больше я думал об этом, тем менее привлекательно это выглядело. И главное — на всё это просто не хватало времени, потому что сроки уже поджимали.
И вот, когда я уже почти начал мириться с неизбежностью миграции, мне в голову пришла совершенно другая мысль: а почему вообще нужно переносить инфраструктуру? Ведь проблема только в доступе к API, а значит, её можно решить и другим способом — например, через VPN-прокси прямо из Node.js-сервиса.
Node.js + VPN — а так можно было?
Вряд ли я первый, кто столкнулся с такой проблемой, поэтому я почти сразу начал искать подходящее решение в сторону VPN или прокси. И тут всё оказалось намного проще, чем я ожидал.
Моё приложение написано на Node.js, и первоначально я использовал стандартный встроенный fetch
, который появился в последних версиях Node.js и избавляет от необходимости устанавливать внешние пакеты. Я задался вопросом: а можно ли заставить этот стандартный fetch
отправлять запросы через VPN-прокси?
Он не позволял, но я нашел внешний пакет node-fetch
, который гарантированно умеет работать с пакетом socks-proxy-agent
.
Минимальный рабочий пример:
import fetch from 'node-fetch';
import { SocksProxyAgent } from 'socks-proxy-agent';
const proxy = 'socks5h://логин:пароль@адрес_вашего_прокси:порт';
const agent = new SocksProxyAgent(proxy);
const response = await fetch('https://generativelanguage.googleapis.com/v1beta/models/...', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ /* ваши данные */ }),
agent,
});
const data = await response.json();
console.log(data);
Это сработало сразу же и без каких-либо дополнительных настроек.
Как я быстро поднял свой VPN-прокси
Я не хотел тратить время на сложные конфигурации и нашел простое решение — Amnezia VPN. Это бесплатный и опенсорсный инструмент, который позволяет буквально за несколько команд развернуть свой собственный VPN-сервер (например, на виртуалке в Hetzner или DigitalOcean).
За полчаса я сделал следующее:
Взял минимальный VPS на зарубежном хостинге.
Развернул на нём сервер Amnezia одной командой.
Получил готовый SOCKS5-прокси с IP-адресом в «разрешённом» регионе.
Gemini начал отвечать сразу же, как только я подставил этот прокси в свой код.
Итого — вместо полной миграции инфраструктуры я получил полностью рабочее решение буквально за полчаса.
Но что, если VPN вдруг упадёт?
Решение получилось простое и элегантное, но возник следующий вопрос: а что если VPN-сервер упадёт? Или прокси будет заблокирован Google или самим Яндексом?
Ведь зависимость от одного единственного VPN-прокси делает всю систему ненадёжной.
Я быстро понял, что нужно добавить поддержку нескольких прокси с автоматическим переключением между ними при сбоях.
Именно так я и сделал.
Поддержка нескольких прокси и автоматическое переключение
Чтобы избежать зависимости от одного прокси и повысить отказоустойчивость, я решил реализовать простой механизм резервирования. Идея простая:
Сервис принимает список прокси.
Если основной прокси недоступен (возвращает ошибку или таймаут), сервис автоматически пробует следующий из списка.
И так до тех пор, пока не найдётся рабочий прокси или список не закончится.
Это позволило не беспокоиться о том, что VPN-сервер может внезапно упасть или попасть в бан.
NPM-пакет для всех желающих: fetch-retry-proxy
Когда я закончил с реализацией этого механизма, подумал, что наверняка не один я сталкивался с такой задачей. Чтобы другие разработчики могли быстро решить аналогичную проблему, я вынес весь этот функционал в отдельный npm-модуль:
? fetch-retry-proxy
? GitHub репозиторий с исходниками и тестами
Теперь каждый может подключить его буквально одной командой:
npm install fetch-retry-proxy
И использовать вот так:
import fetchRetryProxy from 'fetch-retry-proxy';
const proxies = [
'socks5h://proxy1:port',
'socks5h://proxy2:port',
'socks5h://proxy3:port',
];
const response = await fetchRetryProxy('https://generativelanguage.googleapis.com/...', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ /* данные */ }),
}, proxies);
const data = await response.json();
console.log(data);
Таким образом, всего за несколько минут можно получить надёжное решение с автоматическим переключением между несколькими прокси-серверами.
На GitHub я также выложил исходники и тесты, чтобы было легко разобраться, как это работает, или предложить улучшения.
Итог: Всё оказалось проще, чем казалось
В итоге вместо миграции всей инфраструктуры в другую страну я получил простое и удобное решение:
Сервис продолжает работать в Yandex Cloud.
Доступ к Gemini API стабилен и защищён от перебоев.
Другие разработчики могут воспользоваться готовым npm-пакетом и сэкономить время.
Надеюсь, мой опыт поможет вам сэкономить нервы и время. А вы сталкивались с подобными ситуациями? Делитесь в комментариях!
P.S.
Выкатив npm-модуль я воспользовался Codex и перевел Readme на английский.
Комментарии (12)
AnaSergeeva
11.07.2025 12:11а как-то обрабатывается ситуация, когда к примеру все прокси разом легли или список закончился? Есть какой-то фоллбэк или сервис упадет с ошибкой?
sssrgei Автор
11.07.2025 12:11Сервис не упадет, а у функции выскочит исключение, которое сервис должен обработать.
Jacov911
11.07.2025 12:11Был уверен что прочитаю, как вы написали "прослойку" для api и развернули на том же google cloud, куда стучитесь за gemini, это было бы логичнее, как мне кажется
sssrgei Автор
11.07.2025 12:11Я не очень знаком с инфраструктурой Google Cloud, был один пет проект давно и немного забыл все, за 30 минут не поднял бы точно, а сервера на амнезии у меня давно используются для других нужд, поэтому мне было просто по клику получить новые креды и подключиться. Если бы я мог использовать гугл клауд, мне бы и не надо было стучаться из яндекс клауда, но там все по другому, вплоть до бд (firebase vs ydb). Если гипотеза выстрелит, то можно будет подумать над более целевым решением, может и без gemini, альтернативы есть.
SabMakc
11.07.2025 12:11Вариант обучать собственную модель отпал сразу — опыта у меня в этом не было, а искать кого-то, кто сможет это сделать, не было времени, так как хотелось быстро запустить.
Создается впечатление, что "обучить свою модель" - дело на пять минут, максимум несколько часов.
P.S. рассматривали ли запуск открытой модели на своих ресурсах? В Yandex Cloud можно и GPU арендовать...
sssrgei Автор
11.07.2025 12:11Пока никаких вариантов не рассматривал, для теста гипотезы это не нужно. По результатам теста буду смотреть все варианты.
un1t
Vpn тут не нужен же, можно просто прокси развернуть.
Амнезия умеет работать как сокс прокси?
sssrgei Автор
Да, умеет
Kassiy_Pontiy_Pilat
Socks прокси тоже уже режут на известные адреса хостеров. На мтс сейчас ни socks ни shadowsocks и даже в последнее время vless толком не работает если адрес прокси не в россии
sssrgei Автор
Это же серверный код, вряд ли МТС как-то влияет на сервера яндекс, не через мобильную же дата центр подключен.
Kassiy_Pontiy_Pilat
Я просто пример привёл. У разных провайдеров даже в разных регионах все по-разному. Но вероятность , что гайки закрутят постепенно везде высокая. Поэтому амнезия хороший выбор
sssrgei Автор
Согласен, что стратегически это не годится, как продакшн решение, но чтобы по быстрому протестировать гипотезу, вполне.