NGINX: limit_req – ограничение количества запросов

Автор: | 09/08/2019

Задача – установить лимит количества запросов с одного IP:

  1. добавить rate limiter на URI /user/oauth/refresh_token
  2. число запросов – 5 в минуту с одного IP
  3. если запросов больше – возвращаем 429 Too Many Requests

Используем NGINX и его модуль ngx_http_limit_req_module.

limit_req_zone

Для работы “лимитера” – следует создать зону, в которой будут хранится данные (а именно – кол-во запросов с каждого IP).

Добавляем его в nginx.conf, блок http {}:

...
limit_req_zone $binary_remote_addr zone=backend_oauth:10m rate=5r/m;
...

Тут:

  • $binary_remote_addr – переменная с IP клиента
  • zone=backend_oauth:10m – создаём зону памяти с именем backend_oauth и размером 10 мегабайт (размер $binary_remote_addr см. в ngx_stream_limit_conn_module)
  • rate=5r/m – максимум 5 запросов в минуту

Also:

limit_req

Далее – в конфиге виртуалхоста создаём location, который хотим ограничить, и в него добавляем limit_req:

...
    location /v3/user/oauth/refresh_token {
        limit_req zone=backend_oauth nodelay;
        limit_req_status 429;
        try_files $uri $uri/ /index.php?$args;
        fastcgi_pass 127.0.0.1:9014;
        include fastcgi_params;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        fastcgi_param DOCUMENT_ROOT $root_path;
        fastcgi_param  SCRIPT_FILENAME  $root_path$fastcgi_script_name;
        fastcgi_intercept_errors on;
    }
...

Проверяем синтаксис, перечитываем конфиги:

[simterm]

root@bttrm-stage-app-2:/home/admin# nginx -t && systemctl reload nginx
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

[/simterm]

Apache benchmark

Проверяем:

[simterm]

$ ab -n 100 -c 10 "https://stage.example.com/v3/user/oauth/refresh_token/"

[/simterm]

И логи:

[simterm]

root@bttrm-stage-app-2:/home/admin# tail -f /var/log/nginx/stage.example.com-access.log | grep 194.***.***.26
194.***.***.26 - - [08/Aug/2019:14:26:29 +0300] "GET /v3/user/oauth/refresh_token/ HTTP/1.1" 404 27 "-" "ApacheBench/2.3"
194.***.***.26 - - [08/Aug/2019:14:26:29 +0300] "GET /v3/user/oauth/refresh_token/ HTTP/1.1" 429 162 "-" "ApacheBench/2.3"
194.***.***.26 - - [08/Aug/2019:14:26:29 +0300] "GET /v3/user/oauth/refresh_token/ HTTP/1.1" 429 162 "-" "ApacheBench/2.3"
194.***.***.26 - - [08/Aug/2019:14:26:29 +0300] "GET /v3/user/oauth/refresh_token/ HTTP/1.1" 429 162 "-" "ApacheBench/2.3"
194.***.***.26 - - [08/Aug/2019:14:26:29 +0300] "GET /v3/user/oauth/refresh_token/ HTTP/1.1" 429 162 "-" "ApacheBench/2.3"
...

[/simterm]

429 отдаётся, всё работает.

NGINX, limit_req и AWS ALB

Упоминают (правда – в 2014 году), что при использовании Load Balancer от AWS – использование $binary_remote_addr может не работать, и вместо него требуется использовать $http_x_forwarded_for, но сейчас работает с $binary_remote_addr. Возможно – благодаря set_real_ip_from (см. NGINX: реальный IP в логах при работе за AWS Load Balancer).

Ссылки по теме