К содержимому
DDoS·Protect
База знаний

Как передать реальный IP посетителя в nginx за фильтром или CDN

Когда сайт работает за фильтром или CDN, все запросы приходят на сервер с адресов узлов фильтрации. Если не передать настоящий адрес посетителя, журналы станут бесполезными, а баны и лимиты начнут блокировать всех сразу.

Проверьте, что модуль есть

Модуль ngx_http_realip_module не входит в сборку по умолчанию при компиляции из исходников, но включён в пакеты nginx из официального репозитория и большинства дистрибутивов. Проверить можно так:

nginx -V 2>&1 | grep -o with-http_realip_module
Пустой вывод — модуля нет, нужна другая сборка

Настройка

# http { ... } или server { ... }
# Доверяем заголовку ТОЛЬКО от адресов узлов фильтрации
set_real_ip_from 203.0.113.0/24;   # адреса из личного кабинета (условные)
set_real_ip_from 198.51.100.0/24;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

Что делает каждая директива

  • set_real_ip_from — список доверенных адресов. Только для запросов с этих адресов nginx заменит адрес клиента значением из заголовка. Директив может быть несколько.
  • real_ip_header — из какого заголовка брать адрес: X-Forwarded-For, X-Real-IP или другой, который передаёт ваш фильтр или CDN. Можно указать и proxy_protocol, если адрес передаётся через PROXY protocol.
  • real_ip_recursive — при значении on nginx идёт по цепочке X-Forwarded-For справа налево и берёт первый адрес, который не входит в доверенные. При off берётся последний адрес цепочки. Значение on нужно, когда перед сервером несколько прокси, например фильтр и балансировщик.

После замены адрес клиента попадает в переменную $remote_addr, а значит — в access.log, в limit_req, в allow/deny и в заголовки, которые nginx передаёт приложению. Исходный адрес узла фильтрации остаётся доступен в $realip_remote_addr — его удобно писать в журнал для разбора проблем.

Передача адреса приложению

location / {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://backend;
}

# Для PHP-FPM адрес уходит в REMOTE_ADDR автоматически
# через fastcgi_params (fastcgi_param REMOTE_ADDR $remote_addr)

Почему только от доверенных адресов

Заголовок X-Forwarded-For может прислать кто угодно. Если доверять ему от всех источников, атакующий подставит любой адрес, обойдёт баны и запишет в журналы чужие IP. Поэтому set_real_ip_from должен содержать только адреса узлов фильтрации, а прямой доступ к серверу для остальных лучше закрыть — см. как скрыть IP сервера.

Проверка

  1. Выполните nginx -t и перезагрузите конфигурацию: nginx -s reload или systemctl reload nginx.
  2. Откройте сайт со своего устройства.
  3. Найдите свой запрос в access.log — в первой колонке должен быть ваш адрес, а не адрес фильтра.
  4. Проверьте, что приложение (CMS, фреймворк) видит тот же адрес.

Для Apache — отдельное руководство про mod_remoteip.

Вопросы и ответы

В журнале всё ещё адреса фильтра. Что не так?

Чаще всего фильтр присылает запросы с адресов, которых нет в set_real_ip_from, или передаёт адрес в другом заголовке. Запишите в журнал $realip_remote_addr и $http_x_forwarded_for — станет видно, с какого адреса пришёл запрос и что было в заголовке.

Где разместить директивы — в http или в server?

Если все сайты на сервере работают за одним фильтром, удобнее в http. Если только часть — в server нужных сайтов. Директивы из location тоже работают, но такую настройку легко забыть при правках.

Нужно ли менять что-то в приложении?

Если приложение стоит за nginx и само читает X-Forwarded-For, его тоже нужно настроить на доверие только nginx. Многие фреймворки имеют для этого параметр списка доверенных прокси.

Ранний доступ

Подключим ваш сайт одним из первых

Сервис готовится к запуску. Оставьте заявку: проверим, от чего нужно защищать ваш проект, и подключим его в числе первых на условиях раннего доступа.