Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Nginx rate limit is not rejecting exceeded requests?

This is my nginx configuration:

{
    # on top of conf file
    limit_req_zone $binary_remote_addr zone=main:10m rate=1r/s;  
    ...

    location /login {
            limit_req zone=main burst=3 nodelay;
            ModSecurityEnabled on;
            ModSecurityConfig /usr/local/nginx/conf/modsecurity.conf;
            proxy_pass http://localhost:4000;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

}

When hitting the api url (http://localhost:4000/login) multiple times using following code -

for i in {0..2000}; do (curl -Is http://localhost:4000/login | head -n1 &) 2>/dev/null; done

I am getting always getting 200 response code instead of getting 503 for some requests which should be rejected. Why is this happening?

like image 869
Anshul Bisht Avatar asked Apr 12 '17 11:04

Anshul Bisht


People also ask

How many requests NGINX can handle?

Once the rate limit of 10 requests per second is exceeded by a single client accessing /api/ , NGINX returns a “429 Too many requests” error to the client.

How do I limit NGINX connections?

To limit connections, use the limint_conn directive to set the memory zone to be used and the maximum number of allowed connections as shown in the following configuration snippet. This directive is valid within the HTTP, server, and location contexts. Save the file and close it.

What is zone size in NGINX?

State information for about 16,000 IP addresses takes 1 ;megabyte, so our zone can store about 160,000 addresses. If storage is exhausted when NGINX needs to add a new entry, it removes the oldest entry.


Video Answer


2 Answers

This is my config. Now it is correctly displaying the 200 & 503 requests after passign tthe threshold.

limit_req_zone $http_x_forwarded_for zone=req_limit_per_ip:100m rate=10r/m;
limit_conn_zone $http_x_forwarded_for zone=conn_limit_per_ip:100m;


server {

listen 80;

server_name *.xxxxxx.com;
add_header 'Access-Control-Allow-Headers' "X-Forwarded-For; X-Forwarded-Proto; X-Forwarded-Port; Host; X-Amzn-Trace-Id; Connection";
#add_header 'Access-Control-Allow-Headers' "X-Requested-With";
add_header 'Access-Control-Allow-Methods' "GET, POST, OPTIONS";
#add_header 'Access-Control-Allow-Origin' "$http_origin";

server_tokens off;
client_body_timeout 60s;
client_header_timeout 60s;
add_header 'X-Frame-Options' "SAMEORIGIN";
add_header 'Strict-Transport-Security' "max-age=31536000; includeSubDomains" ;

location /api/ {
    ModSecurityEnabled off;
    ModSecurityConfig /usr/local/nginx/conf/modsecurity.conf;
    limit_req zone=req_limit_per_ip burst=10 nodelay;
    proxy_pass http://xx.xxx.xxx.xxx:7000/;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
    proxy_connect_timeout       60s;
    proxy_send_timeout          60s;
    proxy_read_timeout          60s;
    send_timeout                60s;

}
}

To check the effect, I created a .js file and requested the above url 20 times inside a loop. You can check the results below -

Output: enter image description here

like image 177
Anshul Bisht Avatar answered Oct 13 '22 09:10

Anshul Bisht


For me limit_req was not working too. The issue was in wrong ordering - limit_req should come before proxy_pass

Works:

limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=5r/s;

server {
  listen      443;
  server_name example.com;

  limit_req zone=req_limit_per_ip burst=10 nodelay;

  location / {
    proxy_pass         http://be_server;
  }
}

Works

limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=5r/s;

server {
  listen      443;
  server_name example.com;

  location / {
    limit_req zone=req_limit_per_ip burst=10 nodelay;

    proxy_pass         http://be_server;
  }
}

Doesn't work

limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=5r/s;

server {
  listen      443;
  server_name example.com;

  location / {
    proxy_pass         http://be_server;

    limit_req zone=req_limit_per_ip burst=10 nodelay;
  }
}
like image 24
srghma Avatar answered Oct 13 '22 09:10

srghma