Проверьте, что модуль есть
Модуль 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 сервера.
Проверка
- Выполните nginx -t и перезагрузите конфигурацию: nginx -s reload или systemctl reload nginx.
- Откройте сайт со своего устройства.
- Найдите свой запрос в access.log — в первой колонке должен быть ваш адрес, а не адрес фильтра.
- Проверьте, что приложение (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. Многие фреймворки имеют для этого параметр списка доверенных прокси.