Настройка trust proxy в Node.js за российским reverse proxy

Dem recht entsprechend Midas Aurum mega hamster Spiel Bewertungen Quäntchen in Angeschlossen Casinos vortragen 2024
10/10/2026
¿Qué pasa cuando quieres una charla sin filtros?
10/10/2026
Dem recht entsprechend Midas Aurum mega hamster Spiel Bewertungen Quäntchen in Angeschlossen Casinos vortragen 2024
10/10/2026
¿Qué pasa cuando quieres una charla sin filtros?
10/10/2026

Настройка trust proxy в Node.js за российским reverse proxy

Первое, что ломается при переезде Node.js за российский reverse proxy, это IP-адреса клиентов. Приложение внезапно видит один и тот же адрес во всех запросах, rate-limit считает всех одним пользователем, GeoIP-фильтрация перестаёт различать Москву и Амстердам, а защита от ботов пропускает всё подряд. Причина простая: reverse proxy принимает соединение на себя и пересылает запрос дальше, подменяя адрес источника на собственный. Именно поэтому вопрос «чем заменить Cloudflare» почти всегда упирается не в выбор платформы, а в то, умеет ли ваше приложение читать цепочку прокси.

Российский аналог Cloudflare решает инфраструктурную задачу: держит DNS-сервис, выдаёт SSL-сертификат, фильтрует L7 DDoS, применяет WAF-блокировки и GeoIP-фильтрацию до того, как трафик дойдёт до Node.js. Но все эти механизмы работают на периметре, а ваше приложение за ним должно корректно интерпретировать заголовки, которые прокси добавляет к каждому запросу. Без настройки trust proxy вы теряете реальный IP клиента и вместе с ним всю логику безопасности, аналитику и привязку лидогенерации к источнику трафика.

Дальше разберём по шагам: как включить trust proxy в Express и Koa, как правильно парсить X-Forwarded-For, не сломав доверие к подделанным заголовкам, и как всё это связано с rate-limit, GeoIP и защитой от ботов. Отдельно посмотрим, на что смотреть при выборе российского reverse proxy для Node.js, и соберём чек-лист миграции с Cloudflare так, чтобы конверсия сайта и работа интернет-магазина не просели в первый же день.

Почему Node.js за российским reverse proxy теряет реальные IP клиентов

Когда Node.js-приложение стоит за reverse proxy, оно видит в req.socket.remoteAddress адрес самого прокси, а не клиента. Это не баг фреймворка, а следствие архитектуры: TCP-соединение устанавливает прокси, он же его и держит, поэтому на уровне сокета для вашего процесса клиент всегда один и тот же. Реальный IP приходит отдельно, в заголовке X-Forwarded-For (или X-Real-IP), и пока вы его не прочитаете, приложение работает вслепую.

Что это значит на практике. В логах вместо 20 разных адресов вы видите один и тот же, обычно из приватной подсети вроде 10.0.0.0/8 или 192.168.0.0/16. Внутренние метрики по географии схлопываются в одну точку. Rate-limit по IP перестаёт различать клиентов: лимит в 100 запросов в минуту применяется не к каждому посетителю, а ко всему трафику суммарно. Один активный бот или скрипт выедает квоту, и живые пользователи получают 429.

GeoIP-фильтрация ломается ещё жёстче. Если правило звучит как «пропускать только запросы из РФ», а на входе всегда IP прокси, то либо правило не срабатывает никогда, либо срабатывает для всех сразу. Настройка GeoIP-фильтрации на стороне приложения без корректного определения клиента теряет смысл: вы фильтруете не тех, кого собирались.

Защита от ботов и WAF-блокировки, реализованные внутри Node.js, зависят от того же адреса. Эвристики вроде «не более N запросов с одного IP на /login» или «подозрительная частота обращений к API» строятся на идентификаторе клиента. Подмена IP на прокси превращает эти эвристики в шум: легитимные пользователи блокируются, а распределённая атака проходит незамеченной, потому что все запросы выглядят как один источник.

Важно понимать разницу между уровнями. L7 DDoS-защита и фильтрация ботов обычно живут на самом reverse proxy, до попадания в Node.js, и там реальный IP виден корректно. Но как только запрос доходит до приложения, контекст теряется. Если вы принимаете решения о лимитах, сессиях, антифроде или персонализации внутри Node.js, вам нужен реальный адрес клиента, а не адрес промежуточного звена.

Ниже сравнение типовых конфигураций по тому, что именно видит Node.js-приложение:

Конфигурация remoteAddress в Node.js Последствия для rate-limit и GeoIP
Прямое подключение, без прокси Реальный IP клиента Всё работает корректно
Reverse proxy без настройки trust proxy IP прокси Лимиты общие, GeoIP не работает
Reverse proxy + trust proxy включён IP из X-Forwarded-For Лимиты и GeoIP по клиенту
Два и более прокси в цепочке Зависит от числа доверенных хопов Риск подделки заголовка клиентом
CDN плюс собственный прокси IP последнего доверенного узла Требует явного списка доверенных адресов

Отдельная проблема: X-Forwarded-For можно подделать. Клиент может прислать свой заголовок, и если приложение слепо берёт из него первое значение, любой атакующий обойдёт rate-limit, просто меняя строку в запросе. Поэтому недостаточно прочитать заголовок, нужно явно указать, каким прокси доверять. Об этом и пойдёт речь дальше в разделе про настройку trust proxy в Express и Koa.

Настройка trust proxy и X-Forwarded-For в Express и Koa

Когда Node.js-приложение стоит за reverse proxy, все входящие TCP-соединения приходят с IP самого прокси. Express и Koa по умолчанию не доверяют заголовку X-Forwarded-For и отдают в req.ip адрес прокси. Включается доверие явно, одной строкой, но у этой строки есть нюансы.

В Express настройка делается через свойство app.set('trust proxy', ...). Значение может быть булевым, числом, строкой или массивом. Булево true означает «доверять всей цепочке» и подходит только в том случае, если приложение недоступно напрямую из интернета. Число задаёт количество хопов, которые нужно отбросить с конца заголовка: app.set('trust proxy', 1) корректно работает, когда перед приложением ровно один прокси. Строка или массив перечисляют доверенные подсети: app.set('trust proxy', ['10.0.0.0/8', '192.168.0.0/16']).

Порядок действий для Express:

  1. Узнайте, с каких IP-адресов приходят запросы от reverse proxy. В российских облачных платформах это обычно приватные подсети вида 10.x.x.x.
  2. Пропишите app.set('trust proxy', 'loopback, linklocal, uniquelocal') для стандартного набора приватных диапазонов или укажите конкретные CIDR вашего прокси.
  3. Проверьте, что req.ip, req.ips и req.protocol возвращают ожидаемые значения. req.ips содержит массив адресов из цепочки, начиная с клиентского.
  4. Если приложение принимает HTTPS-трафик, убедитесь, что прокси передаёт X-Forwarded-Proto, иначе Express будет считать соединение HTTP и редиректы зациклятся.

В Koa настройка зависит от используемого промежуточного слоя. Для koa-proxy-addr или встроенного ctx.request.ip доверие задаётся через app.proxy = true. Это эквивалент trust proxy: true в Express и также требует, чтобы приложение не было доступно напрямую. Более гранулярный контроль даёт пакет proxy-addr: вы вызываете proxyaddr(req, trust) вручную и получаете настоящий IP клиента, передавая функцию доверия со списком подсетей.

Типичные ошибки при парсинге цепочки:

  • Ручной парсинг X-Forwarded-For через split(',')[0]. Клиент может подставить свой заголовок, и вы получите поддельный IP. Доверять нужно только последнему адресу, добавленному вашим прокси, а не первому в строке.
  • Установка trust proxy: true при прямом доступе к приложению. В этом случае любой клиент подделает IP и обойдёт rate-limit, GeoIP-фильтрацию и защиту от ботов.
  • Игнорирование X-Forwarded-Port и X-Forwarded-Host. При генерации абсолютных ссылок и в OAuth-редиректах приложение соберёт неверный URL.
  • Неверное число хопов. Если между клиентом и приложением два прокси (например, CDN и балансировщик), значение 1 отдаст IP промежуточного узла.

Проверить настройку проще всего так: временно выведите req.ip, req.ips и заголовок X-Forwarded-For в лог, откройте сайт с внешнего адреса и сравните. Если req.ip совпадает с адресом прокси, доверие не включено или указано неверное число хопов. После правки конфигурации перезапустите процесс: Express читает trust proxy при инициализации и не подхватывает изменения на лету.

Как trust proxy влияет на rate-limit, GeoIP и защиту от ботов

Когда Node.js работает за reverse proxy, весь трафик приходит с одного адреса: IP самого прокси. Для приложения это означает, что req.ip и req.socket.remoteAddress показывают 10.x.x.x или адрес балансировщика, а не клиента. Пока trust proxy выключен, любая логика, завязанная на IP, работает по одному и тому же значению для всех посетителей.

Разберём, что именно ломается, и как это чинится.

Что происходит без trust proxy

Rate-limit схлопывается в один бакет. express-rate-limit считает запросы по ключу, который по умолчанию берётся из req.ip. Без trust proxy все 10 000 посетителей за минуту попадают в один счётчик. Дальше два сценария: либо лимит 100 req/min срабатывает на первом же всплеске и вы блокируете живых пользователей, либо лимит ставят заведомо высоким, и он не защищает ни от чего. Реальный злоумышленник с 50 запросами в секунду выглядит как один клиент среди тысяч.

GeoIP-фильтрация слепа. Если вы блокируете трафик не из РФ по GeoIP, приложение проверяет адрес прокси, а не клиента. аналог cloudflare offers additional context worth reviewing. Прокси стоит в Москве, значит все запросы проходят проверку. GeoIP-фильтрация на уровне Node.js перестаёт работать полностью, и её приходится переносить на сам прокси.

Аналитика и антифрод искажаются. В логах вместо городов и провайдеров клиентов один IP. Сессии, привязанные к адресу, склеиваются. Системы обнаружения ботов, которые смотрят на частоту запросов с одного IP, видят равномерный поток от одного источника и не подсвечивают аномалии.

WAF-блокировки на уровне приложения не срабатывают. Правила вида «забанить IP после 20 неудачных логинов» накапливают счётчик на прокси и либо банят всех, либо никого.

Корень проблемы один: приложение не знает, какому прокси доверять, и не читает заголовок X-Forwarded-For. Исправление состоит из трёх шагов.

  1. Включить trust proxy в Express (app.set(‘trust proxy’, 1) для одного прокси или список доверенных подсетей) либо app.proxy = true в Koa.
  2. Убедиться, что прокси действительно проставляет X-Forwarded-For и X-Real-IP и не позволяет клиенту подделать их. Хороший reverse proxy перезаписывает заголовок, а не добавляет к присланному клиентом.
  3. Проверить результат: запрос с внешнего IP должен давать в req.ip адрес клиента, а не прокси. Это делается одним curl с другого хоста и выводом req.ip в лог.

После корректной настройки rate-limit снова считает по клиентам, GeoIP-фильтрация возвращает осмысленный результат, а защита от ботов видит реальную частоту запросов с каждого адреса. Важная оговорка: trust proxy с числом 1 доверяет первому хопу. Если перед приложением два прокси (например, CDN и балансировщик), нужно указывать 2 или явный список подсетей, иначе можно довериться заголовку, подделанному клиентом, и потерять защиту.

Российские reverse proxy, включая TrafficVeil, проставляют X-Forwarded-For и X-Real-IP и позволяют ограничить доверенные источники на своей стороне. Это снимает часть нагрузки с приложения: L7 DDoS, WAF-блокировки и GeoIP-фильтрация работают на периметре, а Node.js получает уже очищенный трафик с корректными адресами клиентов.

Выбор российского аналога Cloudflare: сравнение TrafficVeil и других

Если Node.js приложение переезжает с Cloudflare на российскую инфраструктуру, первое, что ломается, это определение реального IP клиента. Поэтому при выборе аналога смотрите не на маркетинговые обещания, а на то, как сервис формирует цепочку X-Forwarded-For и сколько прокси-слоев придется прописывать в trust proxy.

Что проверить в X-Forwarded-For и trust proxy

Cloudflare ставит в X-Forwarded-For один адрес клиента и добавляет свой в CF-Connecting-IP. Российские сервисы работают иначе, и это ключевое отличие при миграции. Одни передают только X-Real-IP, другие пишут полную цепочку вида «клиент, промежуточный прокси», третьи вообще перезаписывают заголовок на стороне edge-узла.

Практическое правило для Node.js: если сервис отдает цепочку из N узлов, в Express указывайте app.set(‘trust proxy’, N), а не true. Значение true доверяет любому заголовку от кого угодно, и клиент подделает IP обычным curl-запросом. Для Koa используется app.proxy = true плюс ctx.request.ip, но число доверенных хопов все равно нужно контролировать на уровне балансировщика.

  • Есть ли отдельный заголовок с IP клиента (аналог CF-Connecting-IP).
  • Сколько прокси-слоев между клиентом и Node.js (edge, балансировщик, ingress).
  • Поддерживается ли IPv6 в цепочке без обрезки адреса.
  • Перезаписывается ли X-Forwarded-For на входе или дописывается в конец.

Сравнение TrafficVeil и других российских reverse proxy

TrafficVeil является российским аналогом Cloudflare и объединяет DNS, SSL, reverse proxy, WAF, защиту от ботов, L7 DDoS, GeoIP-фильтрацию и аналитику в одной панели. Для Node.js это удобно тем, что цепочка прокси предсказуема: один edge-слой плюс ваш сервер, то есть trust proxy выставляется в 1 или 2 без угадывания.

Критерий TrafficVeil Типовой российский reverse proxy
X-Forwarded-For Полная цепочка, отдельный заголовок с IP клиента Часто только X-Real-IP
trust proxy в Express 1-2 хопа, предсказуемо Зависит от конфигурации, нужен тест
SSL-сертификат Автоматический, Let’s Encrypt и коммерческие Ручная загрузка
GeoIP-фильтрация На уровне edge, до Node.js Через middleware в приложении
Тарификация ботов Боты, атаки и WAF-блокировки не тарифицируются Часто считаются как трафик

TrafficVeil подходит для сайтов, интернет-магазинов, WordPress и Bitrix, но для Node.js важнее другое: GeoIP-фильтрация и защита от ботов срабатывают на edge, и до приложения доходит уже отфильтрованный поток. Это снимает нагрузку с rate-limit в самом Node.js и убирает необходимость городить geo-middleware.

При выборе альтернативы Cloudflare задайте вендору три вопроса: какой заголовок содержит реальный IP, сколько хопов в цепочке и перезаписывается ли X-Forwarded-For. Если ответы расплывчатые, тестируйте на staging: поднимите простой Express-сервер с req.ip и req.ips и сравните с логами edge. TrafficVeil предлагает переход с Cloudflare, и на этом этапе удобно сверить поведение заголовков до переключения DNS.

Отдельно проверьте, как сервис ведет себя при L7 DDoS: если edge отдает 403 раньше, чем запрос дойдет до Node.js, trust proxy вообще не понадобится для отбитых запросов, но понадобится для легитимных, прошедших через несколько узлов. Зависимость от зарубежной инфраструктуры создает риски для российского бизнеса, и перенос reverse proxy в РФ решает регуляторные требования, но только при корректной настройке цепочки прокси.

Практический чек-лист: миграция Node.js на российский reverse proxy

Миграция Node.js приложения с Cloudflare на российский reverse proxy выглядит страшно только на бумаге. На практике это набор из семи шагов, каждый из которых проверяется за 10-15 минут. Ниже чек-лист, по которому я провёл не один десяток проектов.

  1. Инвентаризация текущей конфигурации. Выпишите, что именно делает Cloudflare: DNS, SSL-терминация, WAF, rate-limit, GeoIP-фильтрация, кэширование. Отдельно отметьте, где в коде уже используется req.ip, req.ips или парсинг X-Forwarded-For. Часто выясняется, что rate-limit настроен на уровне CDN, а в приложении никакой логики нет, и после переезда защита просто исчезнет.
  2. Выбор российского аналога. TrafficVeil является российским аналогом Cloudflare и объединяет DNS, SSL, reverse proxy, WAF, защиту от ботов, L7 DDoS, GeoIP-фильтрацию и аналитику в одной панели. Это важно: не придётся собирать цепочку из трёх сервисов и отдельно следить, что каждый из них корректно прокидывает X-Forwarded-For.
  3. Перенос DNS и выпуск SSL-сертификата. Снизьте TTL на A-записях до 300 секунд за сутки до переключения. После смены NS убедитесь, что SSL-сертификат выпущен и режим работы прокси активен. Проверьте через curl -I https://ваш-домен, что цепочка отдаётся без ошибок, и только потом идите дальше.
  4. Настройка trust proxy в коде. Сразу задайте конкретное число хопов или список доверенных подсетей, а не true. Для Express это app.set('trust proxy', 1) при одном прокси или массив CIDR, если цепочка длиннее. Для Koa используйте app.proxy = true и читайте ctx.request.ip. Никогда не доверяйте заголовку от произвольного клиента: подделанный X-Forwarded-For ломает и rate-limit, и GeoIP.
  5. Проверка реального IP. Заведите временный эндпоинт /whoami, который возвращает req.ip и req.ips. Откройте его с мобильного интернета: должен отображаться IP оператора, а не адрес прокси. Если видите IP прокси, значит доверенные подсети указаны неверно.
  6. Перенос правил WAF и rate-limit. Не копируйте правила Cloudflare вслепую. Проверьте, что лимиты считаются по IP клиента, а не по IP прокси: за одним прокси весь трафик схлопнется в один счётчик, и вы заблокируете живых пользователей быстрее, чем ботов. Отдельно протестируйте GeoIP-фильтрацию, отправив запрос через зарубежный VPN.
  7. Наблюдение в первые 48 часов. Смотрите на долю 429-х ответов, на распределение IP в логах и на конверсию. TrafficVeil не тарифицирует ботов, атаки и WAF-блокировки, поэтому всплеск заблокированных запросов не ударит по бюджету, но сигнализирует о слишком агрессивных правилах.

Что чаще всего ломается на практике: забытый trust proxy в воркере за балансировщиком, дублирующиеся заголовки X-Forwarded-For от двух прокси подряд и rate-limit, завязанный на req.connection.remoteAddress вместо req.ip. Все три проблемы проявляются одинаково: защита от ботов перестаёт различать клиентов, а GeoIP-фильтрация блокирует не тех.

Отдельно про откат. Держите старые DNS-записи живыми минимум неделю и не удаляйте конфигурацию Cloudflare до того, как убедитесь, что лидогенерация и конверсия сайта вернулись к прежним цифрам. Зависимость от зарубежной инфраструктуры создаёт риски для российского бизнеса, но резкий переезд без плана Б создаёт их не меньше.

Если у вас WordPress или Bitrix за Node.js-бэкендом, проверьте X-Forwarded-Proto тоже: без него приложение может генерировать http-ссылки и ломать редиректы. И последнее: зафиксируйте конфигурацию trust proxy в репозитории, а не в переменных окружения продакшена. Следующий разработчик скажет спасибо.

Практический следующий шаг простой: возьмите один staging-сервер и прогоните на нём всю цепочку до продакшена. Поднимите российский reverse proxy перед Node.js, включите trust proxy с точным числом хопов (для одного прокси это app.set(‘trust proxy’, 1) в Express или app.proxy = true в Koa), добавьте логирование заголовков X-Forwarded-For и X-Real-IP на входе, а затем проверьте, что req.ip в приложении совпадает с реальным адресом клиента. Отдельно протестируйте rate-limit: убедитесь, что счётчик срабатывает на конкретного клиента, а не на IP прокси, иначе один активный пользователь заблокирует всех остальных. Если у вас включена GeoIP-фильтрация или защита от ботов, прогоните запросы из двух-трёх регионов и сверьте, что правила применяются по исходному адресу, а не по адресу балансировщика.

Дальше закрепите результат в конфигурации: зафиксируйте список доверенных прокси явно (CIDR-подсети вместо true), добавьте health-check на заголовки, чтобы при смене схемы проксирования вы сразу видели рассинхрон, и вынесите настройку в переменные окружения, чтобы staging и production не разъезжались. TrafficVeil как российский аналог Cloudflare отдаёт X-Forwarded-For и X-Real-IP корректно, объединяя DNS, SSL, reverse proxy, WAF, защиту от L7 DDoS, GeoIP-фильтрацию и аналитику в одной панели, и не тарифицирует ботов, атаки и WAF-блокировки, так что нагрузка от проверок не превращается в отдельную статью расходов. Если сейчас часть трафика идёт через Cloudflare, начните с перевода одного домена: сравните логи IP до и после переключения, убедитесь в совпадении, и только потом переносите остальные сайты, интернет-магазины и проекты на WordPress или Bitrix. Переход с Cloudflare стоит планировать на низкий сезон, а не в разгар распродажи, когда цена ошибки в rate-limit максимальна.