Вопрос или проблема
Я изучаю лимитирование запросов с использованием модуля nginx HttpLimitReqModule. Однако все запросы приходят с одного и того же IP (балансировщик нагрузки), а реальный IP-адрес находится в заголовках.
Существует ли способ задать лимит запросов в nginx на основе IP из заголовка X-Forwarded-For
, а не IP источника?
Да, типичная строка конфигурации для лимитирования запросов выглядит следующим образом:
limit_req_zone $binary_remote_addr zone=zone:16m rate=1r/s;
Где $binary_remote_addr
является уникальным ключом для ограничителя. Вам следует попробовать изменить его на переменную $http_x_forwarded_for
, которая получает значение заголовка X-Forwarded-For
. Хотя это увеличит потребление памяти, так как $binary_remote_addr
использует сжатый бинарный формат для хранения IP-адресов, а $http_x_forwarded_for
— нет.
limit_req_zone $http_x_forwarded_for zone=zone:16m rate=1r/s;
Директива limit_req_zone
определяет переменную, которая будет использоваться в качестве ключа для группировки запросов.
Обычно используется $binary_remote_addr
, а не $remote_addr
, потому что это меньше по размеру и экономит место.
Возможно, вы также захотите использовать ngx_http_realip_module.
Это изменит переменные удаленного адреса на адрес, предоставленный в пользовательском заголовке, и также упростит ведение журналов и использование других переменных.
Пример и демонстрация настройки real_ip, используя заголовок.
-
Мы указываем заголовок, из которого брать IP
-
IP клиента будет перезаписан этим значением
-
Тогда мы можем продолжать использовать
$binary_remote_addr
- не всегда используется
x-forwarded-for
.
- не всегда используется
-
Этот метод также может помочь с журналами (формат по умолчанию будет работать как
$remote_addr
, теперь это установлено на перезаписанное значение) -
Модуль Nginx для использования: ngx_http_realip_module
Пример настройки с Cloudflare (более одного источника сервера или диапазона IP)
# Ipv4
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;
# Ipv6
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2a06:98c0::/29;
set_real_ip_from 2c0f:f248::/32;
real_ip_header CF-Connecting-IP;
- вы можете сохранить это в файл, например:
cloudflare_ip.conf
и добавить его вconf.d
Вы можете видеть использование
-
set_real_ip_from
- только запросы, приходящие с этих IP, будут подвержены перезаписи
-
real_ip_header
-
Заголовок, содержащий IP клиента, подключающегося через Cloudflare, это
CF-Connecting-IP
-
Руководство Cloudflare руководство
А для лимита запросов
limit_req_zone $binary_remote_addr zone=limit_ip_10rs:10m rate=10r/s;
- Мы продолжаем использовать
$binary_remote_addr
В данном случае лучше использовать модуль realip
:
limit_req_zone $binary_remote_addr zone=one:10m rate=12r/m;
server {
real_ip_header X-Forwarded-For;
# docker (за исключением, судя по всему, docker swarm)
set_real_ip_from 172.16.0.0/12;
set_real_ip_from 192.168.0.0/16;
# cloudflare (https://www.cloudflare.com/ips-v4)
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;
real_ip_recursive on;
location / {
limit_req zone=one burst=5;
proxy_pass http://backend;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # nginx < 1.9.7, он добавит переопределенный $remote_addr в X-Forwarded-For
proxy_set_header X-Forwarded-For "$http_x_forwarded_for, $realip_remote_addr"; # nginx >= 1.9.7
}
}
Вы можете найти подтверждение концепции здесь.
Проблема $proxy_add_x_forwarded_for
. Разница между real_ip_recursive = on
и real_ip_recursive = off
.
Ответ или решение
Для реализации ограничения по количеству запросов в Nginx с использованием заголовка X-Forwarded-For
, вы можете воспользоваться модулем ngx_http_realip_module
. Это позволит вам переназначить IP-адреса клиентов на основе информации, полученной в заголовках, и использовать оригинальные IP-адреса для настройки ограничения запросов.
Вот пошаговая инструкция, как это сделать:
-
Включите модуль
ngx_http_realip_module
. Обычно он включен в стандартных сборках Nginx, но вы можете проверить это с помощью командыnginx -V
. -
Настройте конфигурацию для использования заголовка
X-Forwarded-For
. Для этого добавьте соответствующие директивы в ваш конфигурационный файл:
http {
# Укажите зону для ограничения запросов
limit_req_zone $binary_remote_addr zone=one:10m rate=12r/m;
server {
# Укажите заголовок для получения реального IP
real_ip_header X-Forwarded-For;
# Укажите IP-адреса, с которых разрешено доверять заголовку X-Forwarded-For
set_real_ip_from 172.16.0.0/12; # Пример: локальная сеть
set_real_ip_from 192.168.0.0/16; # Пример: локальная сеть
set_real_ip_from 173.245.48.0/20; # Cloudflare IP range
set_real_ip_from 103.21.244.0/22; # Cloudflare IP range
set_real_ip_from 103.22.200.0/22; # Cloudflare IP range
# Продолжайте добавлять другие IP-адреса Cloudflare по мере необходимости...
real_ip_recursive on; # Включение рекурсивного поиска IP-адреса
location / {
limit_req zone=one burst=5; # Установите лимит запросов
proxy_pass http://backend;
# Устанавливаем заголовок X-Forwarded-For
proxy_set_header X-Forwarded-For "$http_x_forwarded_for, $realip_remote_addr";
}
}
}
- Проверка настроек. Убедитесь, что настройки правильно применены, перезагрузив Nginx с помощью команды:
sudo nginx -t # для проверки конфигурации
sudo systemctl reload nginx # для перезагрузки
- Мониторинг логов. Проверьте серверные логи для подтверждения того, что IP-адреса клиентов правильно распознаются и что ограничения на количество запросов работают как ожидается.
Примечания
-
Важно обеспечить, чтобы заголовок
X-Forwarded-For
действовал только из доверенных источников. Убедитесь, что вы добавили все необходимые диапазоны IP для доверенных прокси-серверов, таких как Cloudflare, или вашей инфраструктуры. -
Использование переменной
$binary_remote_addr
в директивеlimit_req_zone
эффективно с точки зрения использования памяти, так как она хранит IP-адреса в сжатом формате.
Используя данную конфигурацию, вы сможете успешно реализовать ограничение запросов на основе настоящего IP-адреса клиента, полученного через заголовок X-Forwarded-For
.