Когда я начинал писать 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 на английский.
Комментарии (10)
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, альтернативы есть.
un1t
Vpn тут не нужен же, можно просто прокси развернуть.
Амнезия умеет работать как сокс прокси?
sssrgei Автор
Да, умеет
Kassiy_Pontiy_Pilat
Socks прокси тоже уже режут на известные адреса хостеров. На мтс сейчас ни socks ни shadowsocks и даже в последнее время vless толком не работает если адрес прокси не в россии
sssrgei Автор
Это же серверный код, вряд ли МТС как-то влияет на сервера яндекс, не через мобильную же дата центр подключен.
Kassiy_Pontiy_Pilat
Я просто пример привёл. У разных провайдеров даже в разных регионах все по-разному. Но вероятность , что гайки закрутят постепенно везде высокая. Поэтому амнезия хороший выбор
sssrgei Автор
Согласен, что стратегически это не годится, как продакшн решение, но чтобы по быстрому протестировать гипотезу, вполне.