HTTP DoS Protection with nginx

HTTP DoS Protection with Nginx through ngx_http_limit_conn_module and ngx_http_limit_req_module modules.

The ngx_http_limit_conn_module module is used to limit the number of connections per the defined key, in particular, the number of connections from a single IP address.

Not all connections are counted. A connection is counted only if it has a request processed by the server and the whole request header has already been read.

Example configuration:

http {
    limit_conn_zone $binary_remote_addr zone=addr:10m;

    ...

    server {

        ...

        location /download/ {
            limit_conn addr 1;
        }

Directives

– Syntax: limit_conn zone number;
– Default: —
– Context: http, server, location

Sets the shared memory zone and the maximum allowed number of connections for a given key value. When this limit is exceeded, the server will return the 503 (Service Temporarily Unavailable) error in reply to a request. For example, the directives allow only one connection per an IP address at a time:

limit_conn_zone $binary_remote_addr zone=addr:10m;

server {
    location /download/ {
        limit_conn addr 1;
    }

There could be several limit_conn directives. For example, the following configuration will limit the number of connections to the server per a client IP and, at the same time, the total number of connections to the virtual server:

limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name zone=perserver:10m;

server {
    ...
    limit_conn perip 10;
    limit_conn perserver 100;
}

The ngx_http_limit_req_module module (0.7.21) is used to limit the request processing rate per a defined key, in particular, the processing rate of requests coming from a single IP address. The limitation is done using the “leaky bucket” method

Example Configuration:

http {
    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

    ...

    server {

        ...

        location /search/ {
            limit_req zone=one burst=5;
        }

Directives

– Syntax: limit_req zone=name [burst=number] [nodelay];
– Default: —
– Context: http, server, location

Sets the shared memory zone and the maximum burst size of requests. If the requests rate exceeds the rate configured for a zone, their processing is delayed such that requests are processed at a defined rate. Excessive requests are delayed until their number exceeds the maximum burst size in which case the request is terminated with an error 503 (Service Temporarily Unavailable). By default, the maximum burst size is equal to zero. For example, the directives allow not more than 1 request per second at an average, with bursts not exceeding 5 requests.

limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

server {
    location /search/ {
        limit_req zone=one burst=5;
    }

If delaying of excessive requests while requests are being limited is not desired, the parameter nodelay should be used:

limit_req zone=one burst=5 nodelay;

There could be several limit_req directives. For example, the following configuration will limit the processing rate of requests coming from a single IP address and, at the same time, the request processing rate by the virtual server:

limit_req_zone $binary_remote_addr zone=perip:10m rate=1r/s;
limit_req_zone $server_name zone=perserver:10m rate=10r/s;

server {
    ...
    limit_req zone=perip burst=5 nodelay;
    limit_req zone=perserver burst=10;
}

A practical example:

In http section of nginx.conf:

  	limit_conn_zone $binary_remote_addr zone=conn_limit_per_ip:20m;
  	limit_req_zone $binary_remote_addr zone=req_limit_per_ip:20m rate=2r/s;

In virtualhost:

location / {
     limit_req zone=req_limit_per_ip burst=6 nodelay;
     limit_conn conn_limit_per_ip 3;
     try_files $uri $uri/ /index.php$is_args$args;
     root /home/marian/www/unixteacher.org;
     index index.php index.html;
 }

You must remove limits for static content:

location ~* ^.+.(jpg|jpeg|gif|png|svg|ico|css|less|xml|html?|swf|js|ttf)$ {
     root /home/marian/www/unixteacher.org;
     expires 10y;
 }

Sources:

Nginx docs/manual for ngx_http_limit_conn
Nginx docs/manual for ngx_http_limit_req