Nginx Multiple If Statements Cause Memory Usage to Jump
We need to block a large number of requests by IP address with nginx. The requests are proxied by a CDN, and so we cannot block with the actual client IP address (it would be the IP address of the CDN, not the actual client). So, we have $http_x_forwarded_for which contains the IP which we need to block for a given request.
Similarly, we cannot use IP tables, as blocking the IP address of the proxied client will have no effect. We need to use nginx to block the requested based on the value of $http_x_forwarded_for.
Initially, we tried multiple, simple if statements: http://pastie.org/5110910
However, this caused our nginx memory usage to jump considerably. We went from somewhere around a 40MB resident size to over a 200MB resident size.
If we changed things up, and created one large regex that matched the necessary IP addresses, memory usage was fairly normal: http://pastie.org/5110923
Keep in mind that we're trying to block many more than 3 or 4 IP addresses... more like 50 to 100, which may be included in several (20+) nginx server configuration blocks.
Thoughts? Suggestions?
I'm interested both in why memory usage would spike so greatly using multiple if blocks, and also if there are any better ways to achieve our goal.
I would suggest trying the map module with something like this:
map $http_x_forwarded_for $deny_access {
default 0;
1.2.3.4 1;
1.2.3.5 1;
1.2.3.6 1;
}
if ($deny_access = 1) {
return 403;
}
444 is a special status code which causes nginx to drop the connection without sending a response. In your case this is dropping the connection between nginx and the CDN -- the CDN then decides what to return to the client. I would suggest returning the standard 403 (Forbidden).
Another option would be to use the Real IP module to set the client IP to the value of X-Forwarded-For
and then use deny
directives to control access.
However, this would return a 403 (rather than the empty response returned by using 444). It also requires that Ngnix be compiled with --with-http_realip_module
—something that may not be an option if you are restricted to using a binary distribution.