[nginx] Using User-Agent & IP address to rate limit

lorenanicole nginx-forum at nginx.us
Mon Jul 28 15:35:51 UTC 2014


Nginx novice here - after spending some time both here, reading through
other community forums, and trial and error I'm looking for confirmation on
my current Nginx config and/or suggestions on a better Nginx config. The end
goal is to use both the IP address and User-Agent to rate limit requests
being proxied to an external API. Currently the config sets zones with their
respective rate limits and bursts using the IP address as the key. Inside
the main location directive the User-Agent is read and based on the
User-Agent the URI is rewritten to the location with the appropriate zone.

http {
    include       mime.types;
    default_type  application/octet-stream;

    limit_req_zone  $binary_remote_addr zone=one:10m   rate=136r/s; 
    limit_req_zone  $binary_remote_addr zone=two:10m   rate=150r/s; 
    limit_req_zone  $binary_remote_addr zone=three:10m rate=160r/s; 
    limit_req_zone  $binary_remote_addr zone=four:10m  rate=30r/m;

    sendfile        on;

    keepalive_timeout  65;

    server {
        listen       443;
        server_name  localhost;

        ssl             on;
        ssl_certificate /etc/nginx/ssl/nginx.crt;
        ssl_certificate_key /etc/nginx/ssl/nginx.key;

        ssl_session_timeout  5m;
        ssl_protocols  SSLv2 SSLv3 TLSv1;
        ssl_ciphers  HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers   on;

        proxy_ssl_session_reuse off;
        large_client_header_buffers 4 32K;

        location /java {
           limit_req  zone=one   burst=140;

           log_format java '$remote_addr - $remote_user [$time_local]'
'"$request" | STATUS: $status | BODY BYTES: $body_bytes_sent |'
'"$http_referer" "$http_user_agent"| GET PARAMS: $args | REQ BODY:
$request_body';
           access_log  /var/log/nginx-access.log  java;
           proxy_pass https://example.com/;

        }

        location /python {
           limit_req  zone=two   burst=140;
           #echo "You made it here with: " $request_body "and this: " $args
"and this: " $uri "and this: " $1;

           log_format python '$remote_addr - $remote_user [$time_local]'
'"$request" | STATUS: $status | BODY BYTES: $body_bytes_sent |'
'"$http_referer" "$http_user_agent"| GET PARAMS: $args | REQ BODY:
$request_body';
           access_log  /var/log/nginx-access.log  python;
           proxy_pass https://example.com/;
        }

        location /etc {
           limit_req  zone=four   burst=1;

           log_format etc '$remote_addr - $remote_user [$time_local]'
'"$request" | STATUS: $status | BODY BYTES: $body_bytes_sent |'
'"$http_referer" "$http_user_agent"| GET PARAMS: $args | REQ BODY:
$request_body';
           access_log  /var/log/nginx-access.log  etc;
           proxy_pass https://example.com/;
        }

        location / {
            root   html;
           index  index.html index.htm;

            if ($http_user_agent = Java/1.6.0_65) {
                rewrite ^(.*)$ /java$uri last;
            }

            if ($http_user_agent = python) {
                rewrite ^(.*)$ /python$uri last;
            }

            if ($http_user_agent = "") {
                rewrite ^(.*)$ /etc$uri last;
            }

        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

    }
}

The concern here is if there is a way to redirect the rewritten uri without
having to break out and start processing the request again (argument last)?
Additionally, is the setting of zone's using the IP address as the key the
proper way to control these different rate limiting and burst thresholds?

Posted at Nginx Forum: http://forum.nginx.org/read.php?2,252085,252085#msg-252085



More information about the nginx mailing list