Bypass limit_conn_zone for POST from localhost #84

Open
hmoen opened this Issue Jan 23, 2013 · 19 comments

2 participants

@hmoen

I'm running a nodejs server on my site. Any action on the site (reading a node, making a comment, sharing a node, etc) creates an event sent to the nodejs server via POST. I had quite a bit of traffic today causing the following error in the nginx site log:

2013/01/23 14:29:42 [error] 13111#0: *313773 limiting connections by zone "arbeit", client: 127.0.0.1, server: www.saludmedica.com, request: "POST /nodejs/message/ HTTP/1.1", host: "localhost:80"

Is there anyway I can modify the following in nginx.conf to bypass the limit just for localhost/127.0.0.1?
limit_conn_zone $binary_remote_addr zone=arbeit:10m;

I'd like to keep the limit for external ips.

Thanks!

@perusio
Owner

Which locations are concerned? You can create a no-limit zone for those locations. Show me the locations concerned and I'll tell how to do it. Something like, for each concerned location:

...
error_page 418 = @no-limit;
...


location @no-limit {

   # no limits here.

}  

Obviously the limit_conn directive has to be moved to each location that is to be limited. Alternatively you can set a pretty liberal zone (with a high limit_conn) and place it at the locations that you don't want to be limited.

@hmoen

The only locations with no limit should be localhost/127.0.0.1. Maybe down the road certain internal ips. (I'm using Amazon cloud)

@perusio
Owner

That's not a location, that's a hostname/IP. I mean the locations of your server configuration, like
location = /index.php and so on.

@hmoen

location = /nodejs/message

Thanks.

@perusio
Owner

Try:

location = /nodejs/message {
     limit_conn arbeit 4096;
     # nodeJS POST's here....
}
@perusio
Owner

Oops. That's not limited to loopback. Instead do:

## site.conf (server level)
location = /nodejs/message {
    error_page 418 = @large-limit;
    if ($is_loopback) {
        return 418;
    }
 } 

 location @large-limit {
     limit_conn arbeit 4096;  
 }

This requires a geo directive at the http level:

## nginx.conf (http level)
geo $is_loopback {
     default 0;
     127.0.0.1 1;
     ::1 1;
 }
@hmoen

So should I keep the following in nginx.conf or remove?
limit_conn_zone $binary_remote_addr zone=arbeit:10m;

Then, am I adding the following in nginx.conf or mysite.conf?
location = /nodejs/message {
error_page 418 = @large-limit;
if ($is_loopback) {
return 418;
}
}

location @large-limit {
limit_conn arbeit 4096;

}

geo $is_loopback {
default 0;
127.0.0.1 1;
::1 1;
}

@perusio
Owner

I've edited my previous comment. See it. Also, yes you keep the limit_conn_zone definition.

@hmoen

Sorry for delay in testing. I get the following error:

root@ip:/etc/nginx# nginx -t
nginx: [emerg] "geo" supports IPv4 only in /etc/nginx/nginx.conf:60
nginx: configuration file /etc/nginx/nginx.conf test failed

@hmoen

Any other method? This article seems to elude that there's on ipv6 support currently:
http://forum.nginx.org/read.php?29,232648,232658#msg-232658

@perusio
Owner

You need version 1.3.10 to get IPv6 support on the geo module: http://nginx.org/en/CHANGES

@hmoen

Is this version stable for production?

@perusio
Owner

It is. In fact is the one Igor and Maxim recommend. It's just that the "dev" branch can have API changes that can pose problems if you're using not well maintained 3rd party modules.

@perusio
Owner

Mind you, it's where the fixes appear first always.

@hmoen

Ok, I'll implement, test, and get back with results.

@hmoen

I installed latest development version, but I'm getting following nginx error:

nginx: [alert] version 1.3.8 of nginx.pm is required, but 1.2.5 was found
nginx: configuration file /etc/nginx/nginx.conf test failed

Do you know anything about this? I Googled it, but could not find anything.

@perusio
Owner
@hmoen

I'm a NOOB when it comes to nginx, how would I disable the perl module? (commands?)

@perusio
Owner

I have a better suggestion. At the http level define your geo variable $is_loopback. But now use a map to avoid the if. At the http level add:

map $is_loopback $address {
    default $binary_remote_address;
    1 0;
}

Now declare your limit zone like this:

limit_conn_zone $address zone=arbeit:10m;

Whenever '$address` is the null string (for loopback only) there's no value to be used as a basis for the limit zone.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment