Let Proxied Servers See the Real Client IP

Introduction

If you use a reverse proxy, servers behind that proxy will likely see traffic as coming from the proxy’s IP. The problem with this is that if you have an application that logs traffic or uses IPs for any other purpose, a reverse proxy can break that functionality.

What is a reverse proxy?

A reverse proxy is a piece of software that sits between a client and a server. The client connects to the proxy, and the proxy connects to the server. The proxy then forwards the client’s request to the server and forwards the server’s response back to the client. Reverse proxies are often used to add additional functionality to a backend application stack such as load balancing, caching, SSL termination, etc.

The problem comes when a reverse proxy forwards a client’s request to a backend server. The backend server will see the request as coming from the proxy’s IP address, not the client’s IP address. This is because the client is connecting to the proxy, not the backend server.

How to pass a client’s IP address to a proxied server

There are a few ways to pass a client’s IP address to a proxied server. The most common way is to use the X-Forwarded-For header. This header is set by the proxy and contains the client’s IP address. The backend server can then read this header to get the client’s IP address with some additional configuration.

Changes Needed on the Proxy

Nginx on the proxy server

Nginx can be configured to pass the X-Forwarded-For header to the reverse proxy. This is done by using the proxy_set_header directive to set the header in the server block:

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

Apache on the proxy server

Apache can be configured to pass the X-Forwarded-For header to the reverse proxy. This is done by using the RequestHeader directive to set the header in the VirtualHost block:

RequestHeader set X-Forwarded-For "%{REMOTE_ADDR}s"

Changes Needed on the Proxied (“backend”) Server

Nginx on the proxied server

For nginx, the ngx_http_realip_module module must be loaded. This allows nginx to read the X-Forwarded-For header and use it as the client’s IP address by adding the following line to the server block:

real_ip_header X-Forwarded-For;

To define the IP from which to trust the X-Forwarded-For header, this line must also be included in the server block:

set_real_ip_from X.X.X.X;

where X.X.X.X is the proxy server’s IP address.

Apache on the proxied server

By default, Apache is loaded with the mod_remoteip module which accomplishes the same thing as the ngx_http_realip_module above for nginx.

To enable the module itself, run the following command:

a2enmod remoteip

This module can then be configured by adding the following line to the VirtualHost block:

RemoteIPHeader X-Forwarded-For

And to define the IP from which to trust the X-Forwarded-For header, this line must also be included in the VirtualHost block:

RemoteIPTrustedProxy X.X.X.X

where X.X.X.X is the proxy server’s IP address.

A note on WordPress and Docker

If you are running WordPress in Docker, the configuration to allow it to read the X-Forwarded-For header is likely already done for you. You can see this in the Dockerfile for the WordPress image (latest version as of this writing).

Resources