Forwarding Visitor’s Real-IP + Nginx Proxy/Fastcgi backend correctly

Here, we are dealing with 2 nginx servers. A front-end nginx, proxying request to another nginx-server running behind firewall. This backend-nginx is a WordPress setup, using PHP-FPM (fastcgi) on our case. Article is valid for any code/application running behind fastcgi upstream.

To manage security properly, we need to pass-on visitors real-IP to backend-nginx. In backend-nginx, WordPress do some stuff based on user-ip.

On Front-End Nginx

First, a portion of Nginx config from front-end proxy

proxy_set_header        X-Real-IP       $remote_addr;
proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;

With this config, backend-nginx receives extra HTTP  Headers which are passed to fastcgi upstream (PHP/WordPress in our case).

If you see output of phpinfo() you will see extra headers as highlighted below:

phpinfo()

The problem with above setup is that fastcgi app running behind backend-nginx, uses REMOTE_ADDR value whenever it needs to deal with visitor IP address.

A solution would be check existence ofHTTP_X_REAL_IP and use that value instead. I think WordPress does this for itself but one of our custom plugin was not already doing that. We could either fix it in PHP code, but rather than modifying every piece of PHP code which rely on REMOTE_ADDR, we added following lines inside backend-nginx conf:

location ~ \.php$ {
        fastcgi_param REMOTE_ADDR $http_x_real_ip;
        #...other rules
}

With this change phpinfo() shows correct user IP forREMOTE_ADDR value.

remote-ip-in-php

Now any piece of code, which depend onREMOTE_ADDR value will work as it is!

Nginx’s HTTP Real IP Module

If you want to do some real-user IP-based stuff in backend, it will NOT work.

Nginx itself will not see real-user IP. Only application/codes behind fastcgi will benefit from above change.

For Nginx, you can simply use variable $http_x_real_ip instead of IP-address.

Below is an example of $http_x_real_ip usage to emulate allow/deny functionality:

        if ($http_x_real_ip != 115.115.82.210) {
                return 403;
        }

There are cases when a workaround using $http_x_real_ip may not be possible. In those caes, we can use Nginx’s Http Real IP Module.

You can fix real-ip andREMOTE_ADDR by adding a line like below to your backend nginx-config:

        set_real_ip_from   192.168.122.1;

Make sure you replace 192.168.122.1 with REMOTE_ADDR value that was being received originally. It is IP of proxy-nginx as seen by backend-nginx.

Advantage of Http Real IP Module is that it sets correct IP for nginx config as well as fastcgi backend app in one go. Apart form this, it is secure also.

You can use earlier way if your Nginx is not built with --with-http_realip_module option.

If you have any questions, feel free to check our Nginx support forum.

Link: WordPress-Nginx Tutorials Series

2 responses to “Forwarding Visitor’s Real-IP + Nginx Proxy/Fastcgi backend correctly”

  1. Do you know if there is a way to have NGINX report the FQDN of the visitor’s address? I’ve tried a number of configurations but nothing seems to work. I can only get user’s IP to output to the logs..