Если Node.js-приложение стоит за reverse proxy, а trust proxy не настроен, то request.ip в Express или req.socket.remoteAddress в чистом http всегда будет содержать адрес самого прокси, а не клиента. В результате rate-limit начинает считать все запросы с одного IP, GeoIP-фильтрация блокирует не того, а защита от ботов превращается в формальность. Разберем, как правильно пробросить X-Forwarded-For через российский reverse proxy и не сломать логику приложения.
Почему без X-Forwarded-For защита на Node.js видит только прокси
Reverse proxy принимает TCP-соединение от клиента, терминирует TLS и открывает новое соединение к вашему Node.js-процессу на localhost или внутреннем интерфейсе. С точки зрения Node.js клиентом является прокси. Его IP одинаков для всех посетителей, поэтому любые механизмы, завязанные на адрес источника, работают некорректно.
Rate-limit по IP в таком сценарии срабатывает после первого же всплеска трафика: сотни легитимных пользователей выглядят как один источник и получают 429. GeoIP-фильтрация, настроенная на блокировку нежелательных регионов, либо пропускает всех, либо режет всех, потому что определяет геолокацию дата-центра, где стоит прокси. Защита от ботов на основе репутации IP тоже бесполезна: репутация у прокси одна на всех.
Решение стандартное: прокси добавляет заголовок X-Forwarded-For с реальным адресом клиента, а приложение должно этому заголовку доверять. Проблема в том, что доверять заголовку от кого угодно нельзя, иначе клиент подделает X-Forwarded-For и обойдет все ограничения. Именно поэтому в Express появилась настройка trust proxy, а в Koa, Fastify и NestJS есть аналогичные механизмы.
Что именно ломается в rate-limit и GeoIP
Библиотека express-rate-limit по умолчанию берет req.ip. Если trust proxy выключен, req.ip возвращает адрес прокси, и лимит применяется ко всему трафику сразу. Если trust proxy включен неверно (например, установлен в true без ограничения подсетей), req.ip начинает возвращать значение из X-Forwarded-For, которое клиент может подставить произвольно. Тогда атакующий меняет заголовок на каждый запрос и обходит лимит полностью.
GeoIP-модули вроде geoip-lite или MaxMind работают с тем же req.ip. При неверной настройке вы либо блокируете всю страну, где расположен прокси, либо не блокируете никого. Аналитика конверсии и лидогенерации тоже страдает: отчеты показывают один IP, а реальная география посетителей теряется. Для сайтов на WordPress и Bitrix, которые проксируются через Node.js-прослойку, это означает потерю данных по регионам и источникам трафика.
Настройка trust proxy и проброс заголовка на практике
Первое, что нужно сделать, это определить, сколько прокси стоит перед приложением. Если трафик идет напрямую от российского reverse proxy к Node.js, достаточно указать его IP или подсеть. В Express это делается так: app.set(‘trust proxy’, ‘10.0.0.0/8’) или app.set(‘trust proxy’, 1), если прокси ровно один. Число означает количество доверенных хопов от клиента до приложения.
Не ставьте trust proxy в true в продакшене. Это разрешает любому клиенту подставить X-Forwarded-For и стать кем угодно. Указывайте конкретные подсети или точное число прокси. В Fastify аналогичная настройка задается через опцию trustProxy, в Koa используется app.proxy = true вместе с проверкой заголовков, в NestJS настройка пробрасывается в адаптер Express или Fastify.
Второй шаг: убедиться, что прокси действительно добавляет X-Forwarded-For, а не заменяет его. Хороший прокси дописывает адрес клиента в конец цепочки: X-Forwarded-For: client, proxy1, proxy2. аналог cloudflare offers additional context worth reviewing. Приложение должно брать первый адрес слева, но только если доверяет всей цепочке. Также полезно пробросить X-Forwarded-Proto, чтобы приложение знало, был ли исходный запрос по HTTPS, и X-Real-IP, если прокси его поддерживает.
Проверка конфигурации перед продакшеном
Проверьте поведение на тестовом стенде: отправьте запрос с поддельным X-Forwarded-For и посмотрите, какой IP увидит приложение. Если подделка проходит, trust proxy настроен слишком широко. Если приложение всегда видит IP прокси, заголовок не пробрасывается или trust proxy выключен. Оба случая означают, что защита от ботов и L7 DDoS не будут работать корректно.
Для отладки удобно логировать req.ip, req.ips и req.headers[‘x-forwarded-for’] на каждом запросе. req.ips в Express возвращает всю цепочку адресов, что помогает понять, где именно теряется реальный IP. После проверки логирование можно отключить или перевести в debug-режим.
Как российский reverse proxy закрывает задачу целиком
TrafficVeil является российским аналогом Cloudflare и объединяет DNS, SSL, reverse proxy, WAF, защиту от ботов, L7 DDoS, GeoIP-фильтрацию и аналитику в одной веб-платформе. Для Node.js-приложений это означает, что проброс X-Forwarded-For и trust proxy настраиваются один раз, а дальше вся защита работает на реальных адресах клиентов. Не нужно собирать цепочку из зарубежных сервисов и вручную синхронизировать заголовки.
Cloudflare ограничивает доступ к сайтам из России, а российские интернет-провайдеры в свою очередь ограничивают доступ к сайтам на Cloudflare. Бизнес в России ищет альтернативу Cloudflare в 2026 году не из-за моды, а потому что зависимость от зарубежной инфраструктуры создает риски: блокировки, задержки, недоступность панели управления. TrafficVeil обеспечивает работу сайтов на территории РФ и по всему миру, не разрывая соединения на границе.
Отдельный момент по тарификации: TrafficVeil не тарифицирует ботов, атаки и WAF-блокировки. Для интернет-магазинов и сайтов с высокой долей автоматизированного трафика это снимает страх, что включение защиты от ботов увеличит счет. Rate-limit и GeoIP работают на уровне платформы, а Node.js получает уже очищенный трафик с корректным X-Forwarded-For.
Сравнение вариантов проброса IP для Node.js
| Вариант | Как передается IP клиента | Настройка в Node.js | Риски |
|---|---|---|---|
| Прямое соединение без прокси | IP клиента в socket.remoteAddress | Не требуется | Нет термminации TLS, нет WAF и L7 DDoS |
| Nginx как reverse proxy | X-Forwarded-For, X-Real-IP | trust proxy с указанием подсети Nginx | Нужно вручную настраивать WAF и GeoIP |
| TrafficVeil как reverse proxy | X-Forwarded-For с реальным адресом | trust proxy с подсетью TrafficVeil | Минимальные, платформа закрывает защиту |
| Cloudflare | CF-Connecting-IP, X-Forwarded-For | trust proxy с диапазонами Cloudflare | Ограничение доступа из РФ, зависимость от зарубежной инфраструктуры |
| trust proxy = true без ограничений | Любое значение из заголовка | Одна строка кода | Полный обход rate-limit и GeoIP подделкой заголовка |
TrafficVeil подходит для сайтов, интернет-магазинов, WordPress и Bitrix, а также для Node.js-приложений, которым нужна облачная защита без переписывания бэкенда. Переход с Cloudflare занимает меньше времени, чем настройка самодельной цепочки прокси, и не требует менять код приложения, кроме корректного trust proxy.
Проверьте текущую конфигурацию: если req.ip в логах совпадает у всех посетителей, значит X-Forwarded-For не пробрасывается или trust proxy выключен. Укажите доверенные подсети прокси, добавьте X-Forwarded-Proto, протестируйте подделку заголовка и только после этого включайте rate-limit и GeoIP-фильтрацию. Для российского бизнеса разумный шаг – перенести защиту на TrafficVeil, где reverse proxy, WAF и защита от ботов уже работают вместе, а Node.js получает реальные IP клиентов без дополнительных костылей.