Topics

Limit requests per IP on Nginx using HttpLimitZoneModule and HttpLimitReqModule except whitelist

– Make sure to check Nginx, PHP posts for information on Nginx and PHP and configuration.

Nginx offers two modules, HttpLimitReqModule and HttpLimitZoneModule, to simultaneous connections for the assigned session and the of requests for a given session from one IP address. Basically these modules are built to protect the web from possible DDos attacks; For example, this configuration limits remote clients to no more than 20 concurrently “open” connections per remote ip address:

http{
    limit_conn_zone  $binary_remote_addr zone=concurrent:10m;
    limit_conn_log_ warn;
    limit_conn  concurrent  20;


Additionally, this configuration creates zone “allips” allocating 5MB for this session then limits queries for remote ip address to 200 request per second

http{
    limit_req_zone $binary_remote_addr zone=allips:5m rate=200r/s;
    limit_req zone=allips burst=200;

As a result, additional requests or connections from the same remote ip address to Nginx will be dropped with 503 (Service Temporarily Unavailable) . But what if we want to create a whitelist of IPs; for instance, Search bots should not obey these limits. That can be accomplished by HttpGeoModule.

Firstly, a list of search bots CIDR is added to $limited variable, so that any IP that is not on list will return “1” else it returns “0”, as following:
– The example contains real CIDR list of search .

http{
     geo $limited {
        default 1;
        #google 
        64.233.160.0/19 0;
        65.52.0.0/14 0;
        66.102.0.0/20 0;
        66.249.64.0/19 0;
        72.14.192.0/18 0;
        74.125.0.0/16 0;
        209.85.128.0/17 0;
        216.239.32.0/19 0;
        #M$
        64.4.0.0/18 0;
        157.60.0.0/16 0;
        157.54.0.0/15 0;
        157.56.0.0/14 0;
        207.46.0.0/16 0;
        207.68.192.0/20 0;
        207.68.128.0/18 0;
        #yahoo
        8.12.144.0/24 0;
        66.196.64.0/18 0;
        66.228.160.0/19 0;
        67.195.0.0/16 0;
        74.6.0.0/16 0;
        68.142.192.0/18 0;
        72.30.0.0/16 0;
        209.191.64.0/18 0;
        #My IPs
        127.0.0.1/32 0;
        123.456.0.0/28 0; #example for your server CIDR
    }    

    map $limited $limit {
        1        $binary_remote_addr;
        0        "";
    }

Secondly, $limit variable will be added to limit_req instead of $binary_remote_addr to limit requests from other IPs that are not on the whilelist:

http{
    limit_req_zone $limit zone=notabot:5m rate=200r/s;
    limit_req zone=notabot burst=200;

Finally, these configuration with ab against PHP-FPM:
– example PHP file:

<?php
for( $i=0; $i < 1000; $i++)
	echo 'Hello World';
?>

– It is important to check the IP you are connecting with to the server before you start.

#benchmark  ab with compression enabled
ab -n2000 -c400  -H 'Accept-Encoding: gzip,deflate'  http://www.example./helloworld.php

# with server CIDR added to whitelist
Concurrency Level:      400
Time taken for tests:   0.426980 seconds
Complete requests:      2000
Failed requests:        275             <-------------------------
   (Connect: 0, Length: 275, Exceptions: 0)
Requests per second:    4684.06 [#/sec] (mean)
Time per request:       85.396 [ms] (mean)
Time per request:       0.213 [ms] (mean, across all concurrent requests)

# after commenting server CIDR from the whitelist
Concurrency Level:      400
Time taken for tests:   0.665429 seconds
Complete requests:      2000
Failed requests:        1807             <-------------------------
   (Connect: 0, Length: 1807, Exceptions: 0)
Write errors:           0
Requests per second:    3005.58 [#/sec] (mean)
Time per request:       133.086 [ms] (mean)
Time per request:       0.333 [ms] (mean, across all concurrent requests)

In conclusion, requests or connections from IPs on the whitelist will have no limits, whereas IPs outside the whitelist will be limited to a number of connections and requests, consequently, they will be dropped or fail as showen in the above ab example.