The X-Forwarded-For Header is a simple yet powerful solution to a very common problem. I'm not sure why, but for some reason it also seems to cause a lot of confusion. NGINX is often deployed as a cluster behind a layer 7 load balancer (Reverse Proxy)...

Now, being a proxy implementation, Layer 7 offers a whole host of options such as ACLs, clever persistence methods, the ability to add/remove/modify HTTP headers, etc.

So, what's the problem?

A reverse proxy is NOT source IP address transparent.

This is a pain when you need the client source IP address to be correct in the logs of the backend servers. Now I can think of a couple of solutions to this problem:

  1. Implement a fully transparent two-arm reverse proxy using TPROXY (yuk!).
  2. Configure the load balancer to add an X-Forwraded-For Header with the source IP of the client.
  3. Use Layer 4 instead (although I guess you've already ruled that out?)

Personally, I think that by far the easiest option when load balancing a website / web application is to use the X-Forwarded-For Header.

Free consultancy
from the load balancer experts

With - When you create a Layer 7 HTTP mode VIP configuration - the X-Forwarded-For Header is enabled by default. So all you need to do is a slight modification to the logging directive in the web server configuration (to tell it to use the header).

What about other reverse proxies?

NGINX can also be used as the load balancer of course:

        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

Or you can use HAProxy (my preference):

      option forwardfor

So, how do we configure NGINX to use the X-Forwarded-For Header?

With NGINX, there are two ways which the service can be modified to use the X-Forwarded-For Header and it all depends if the NGINX binary was compiled with the option --with-http_realip_module as to which method you might pursue. You can check if the module was included by running the following command: nginx -V and reviewing the output.

Option 1 - Altering the log directive format

This option can be implemented whether or not the --with-http_realip_module was specified at compilation time and modifies the format for the access_log directive to include the X-Forwarded-For Header contents.

In the configuration file /etc/nginx/nginx.conf you will need to change the entries:

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

To show the X-Forwarded-For Header contents first in the log line entries:

    log_format  main  '$http_x_forwarded_for - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '

    access_log  /var/log/nginx/access.log  main;

After making this change, the NGINX service will need restarting in the usual manner.
systemctl restart nginx

Option 2 - Using the 'real_ip' module

Assuming that NGINX has been compiled with the --with-http_realip_module option, the httpd or server stanza in the /etc/nginx/nginx.conf file need to be modified with the set_real_ip_from and real_ip_header directives, like so:

    # Directives for setting real_ip/XFF IP address in log files
    set_real_ip_from; #IP address of master LB
    set_real_ip_from; #IP Address of slave LB
    real_ip_header      X-Forwarded-For;

The real ip module is used to change client source IP address (and optionally, the port too) to the value stored in the specified header. The reason I have set the set_real_ip_from directive twice is that I was running an HA clustered pair of appliances and this covers the base IP addresses from each node.
After making this change, the NGINX service will need restarting in the usual manner.
systemctl restart nginx

After completing the changes detailed in either option, the access log on the real servers should now show the X-Forwarded-For Header contents.

If you experience any issues when configuring this or have any questions which we might be able to help with, contact our support engineers and we'll do everything we can to assist.