limit_req is not working with dynamically extracted user address

Maxim Dounin mdounin at
Fri Mar 18 14:21:32 UTC 2016


On Fri, Mar 18, 2016 at 09:45:58AM -0400, malish8632 wrote:

> Hi, if our HTTP block looks like below where we find IP from X-Forwarded-For
> using perl module it looks like zone and limit_req are not using correct
> variable $user_real_ip or it is reset right after logging.
> The nginx_access_log shows the first logged field correctly as $user_real_ip
> - which is first element of comma separated IP addresses in X-Forwarded-For
> header from different hopes. User request comes thorough several different
> CDN and DDOS services.
> But when limit_req kicks in it would take for some reason last element in
> same header X-Forwarded-For which of course not our intention.
> Can you help understand why and what we are doing wrong?

How did you found that limit_req uses a wrong element?


> 2016/03/17 17:44:15 [error] 19382#0: *8 limiting requests, excess: 5.613 by
> zone "one", client: 333.101.98.188, server:, request: "GET
> /our/api/here HTTP/1.1", host: ""

The "client: 333.101.98.188" is the client address as automatically 
logged by nginx for all error messages (also known as $remote_addr).  
It's not related to the limit string used by limit_req.


>     perl_set $user_real_ip '
>         sub {
>             my $r = shift;
>             my $str = $r->header_in("X-Forwarded-For");
>             my @fields = split /,/, $str;
>             my $real_ip = $fields[0];
>             return $real_ip;
>         }
>     ';

Note well: this can be easily tricked by clients using a fake 
address in initial X-Forwarded-For header.  You may want to use 
the realip module instead, it allows to trust only known proxies, 
see here:

Maxim Dounin

More information about the nginx mailing list