How to get X-Forwarded-For IP addresses in Apache Web Server
X-Forwarded-For, or XFF for short, is a special HTTP header field that is commonly used to identify the originating client IP address whether or not they are connecting to the server through an HTTP proxy or a load balancer. Such web hosting cases where the web server is behind a proxy or a load balancer are extremely common, and thus arises the necessity to be able to log the actual client’s IP address in your system instead of the proxy or load balancer IP. In order to be able to identify the client, you will need to configure your back end Apache HTTP Web Server to be able to use the XFF header and render the real customer IP in its log files. Otherwise, your Apache server will by default log only the receiving IP from the connecting proxy or load balancer.
This guide will show you how you can configure your Apache web server to use the X-Forwarded-For header information so that you can avoid corrupt or incorrect logged data when behind a proxy or load balancer. Note that if your landscape also uses GeoLocation systems behind your proxy or load balancer, your geolocation data will be also corrupt if you do not use the XFF headers.
Getting Started
• 1 Server (Cloud Server or Dedicated Server) with installed Apache HTTP Web Server
Tutorial
X-Forwarded-For in Practice
We will cover setting up your back end web server to use the special X-Forwarded-For HTTP header by using the example of CloudFlare. CloudFlare is a popular protection service against Distributed Denial of Service (DDoS) attacks and essentially acts as a proxy for your web servers. By acting as a reverse proxy for all incoming traffic to your web server, CloudFlare sends all traffic first to its own servers for DDoS detection before they reach your server.
This beneficial service however comes with the drawback that your web server will process all traffic it receives as originating from the CloudFlare server. This means that in cases where your web application relies on the originating visitor IP, it will instead pick up only the CloudFlare IP address instead of the actual original client’s IP address, thus possibly breaking the application logic and corrupting data such as web tracking. The content of your web server access logs would only contain the CloudFlare IP address listed as the $remote_addr. If you use originating IP for GeoLocalisation purposes, you will see your data as though all connections originated just from one IP, ruining the location data.
Due to the importance of being able to correctly identify your actual originating client, CloudFlare and other such services follow industry standards to include the original visitor’s IP address in the X-Forwarded-For header.
Loading the remoteip Module in Apache
In order to omit the IP address of the proxy service (such as CloudFlare) and instead use the real customer IP, we will need to activate a special Apache module known as remoteip when using Apache version 2.4 or higher.
The remoteip module is used to treat the useragent, the identified client, initiating the request as the actual client address, and not the possible load balancer, proxy, or other front end server address that Apache may be receiving. This means that your Apache web server will instead override the client IP address that it receives as the original useragent, such as the CloudFlare server IP address, in order to instead prefer the new useragent address from the XFF header as given by the RemoteIPHeader directive.
Luckily, this module is built by default in your Apache server installation and should not require an Apache recompilation. Instead, all you have to do is activate remoteip. As root or using the command sudo with a user possessing superuser privileges, execute the following command:
a2enmod remoteip
If you are using sudo, your command will instead look like:
sudo a2enmod remoteip
Next, open the Apache server configuration file. Depending on your system, this file called apache2.conf will be located in /etc/httpd/conf or /usr/local/apache2/conf. Open the file in a text editor such as nano after navigating to its location:
nano apache2.conf
In the file, search for the following line:
#LoadModule remoteip_module modules/mod_remoteip.so
Remove the first # if present from the line so it instead looks as follows. Then, close and save the file.
LoadModule remoteip_module modules/mod_remoteip.so
Defining Your Proxies and Services
Once the remoteip module has been loaded, you will need to edit the Apache remote IP configuration file. If it does not yet exist, create it in /etc/apache/conf-available/remoteip.conf. Open the file for editing in your preferred text editor, such as nano shown below:
nano /etc/apache/conf-available/remoteip.conf
The contents of the remoteip.conf file represent your proxy servers or services such as CloudFlare. To add a proxy with the internal IP address 192.168.1.10 in order to represent the CloudFlare server for example, you would need to add the following lines:
RemoteIPHeader X-Forwarded-For
RemoteIPTrustedProxy 192.168.1.10
You can add as many proxy definitions as you need to the remoteip.conf file in order to configure the usage of XFF headers for traffic coming from those proxies when using multiple services or load balancers. An example of adding multiple proxies is shown below:
RemoteIPHeader X-Forwarded-For
RemoteIPTrustedProxy 192.168.1.10 10.10.0.1
Note that if the end-user has an IP in the internal network however, RemoteIPTrustedProxy as used above will not work. To also accept internal network IPs if it suits your environmental needs, you will need to instead use the following to define your proxies in the configuration file:
RemoteIPHeader X-Forwarded-For
RemoteIPInternalProxy 192.168.1.10
Save and exit the file when you are finished.
Configuring Apache Log Formats to Use X-Forwarded-For
Next, you will need to modify the logging format used by Apache. Open the apache2.conf file in a text editor. Again, this file may be located in /etc/httpd/conf or /usr/local/apache2/conf depending on your system. Navigate to its location and open the file in a text editor:
nano apache2.conf
Search for the LogFormat line within the file. The standard logging format for Apache is shown below, you will likely see something similar in your file as well.
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combined
This format captures the header with the %h field, which will use the CloudFlare proxy address in our example by default. Since we want to instead use the originating client IP address in logging, you will have to modify the LogFormat definition to look as follows:
LogFormat "%a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
Notice how we have replaced the original header field position (%h) with the field %a. This is the X-Forwarded-For field that is responsible for displaying the correct originating client IP address and would be sent by services such as CloudFlare. Wherever you have a logging format definition, replace the %h with %a to use X-Forwarded-For.
With Apache being highly configurable, you can further modify the log format until it is best suited to your landscape and web applications by playing around with the placement of the XFF header field. When you are satisfied with the final format, save and exit the file. Next, you will need to reload Apache in order for your changes to take into effect.
Before reloading the server, you can verify that your configuration has no errors in it by using the Apache command apache2ctl:
apache2ctl configtest
If the previous step outputs no errors, you can feel safe reloading to the new configuration to start using XFF. Use the service command to restart the Apache web server:
service apache2 restart
Conclusion
Once your Apache web server restarts, it will begin logging the correct customer IP address information in place of any middleman services you may be using in your landscape. You can rest easy knowing that if you do use a proxy or other similar service, your client information data will be 100% preserved. Share this tutorial with your friends if you found it useful!