Get real client IP from Nginx to Apache

Server environment

1
2
3
4
5
6
7
8
$ cat /etc/issue
Ubuntu 14.04.5 LTS

$ nginx -v
nginx version: nginx/1.4.6 (Ubuntu)

$ apachectl -v
Server version: Apache/2.4.7 (Ubuntu)
Server IP Web Client IP
192.168.33.10 192.168.33.11

Web Client -> Nginx -> Apache -> PHP Website

When i use nginx to proxy to apache, apache gets the ip address of nginx proxy as the client.
Through the apache log files, the PHP website running on the apache backend will all receive the same IP address
( 127.0.0.1, if apache and nginx are running in the same server).

Apache website configuration

My Apache listens 8013 port and accesses directory /www

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ cat /etc/apache2/sites-enabled/site.conf 
<VirtualHost *:8013>
ServerName www.a.com
ServerAlias *.a.com

DocumentRoot /www
<Directory /www>
Options Indexes FollowSymLinks MultiViews
AllowOverride all
Require all granted
</Directory>

ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Nginx proxy configuration

My nginx listens 80 port and passes all request to 127.0.0.1:8013 (Apache website) if request host is “www.a.com"

1
2
3
4
5
6
7
8
9
10
11
12
$ cat /etc/nginx/sites-enabled/a.com.conf
server {
server_name www.a.com
listen 80;
client_max_body_size 100M;

location / {
proxy_pass http://127.0.0.1:8013;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}

Very useful, but…
When i want to collect client IPs, it got all “127.0.0.1” in PHP script

Luckily, nginx provides a HTTP X-Forward-For header containing the client real ip address to allow Apache to recognize the origin client IP.

Install Apache rpaf module

1
$ sudo apt-get install -y libapache2-mod-rpaf

Check Apache rpaf module

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ cat /etc/apache2/mods-available/rpaf.conf 
<IfModule rpaf_module>
RPAFenable On

# When enabled, take the incoming X-Host header and
# update the virtualhost settings accordingly:
RPAFsethostname On

# Define which IP's are your frontend proxies that sends
# the correct X-Forwarded-For headers:
RPAFproxy_ips 127.0.0.1 ::1

# Change the header name to parse from the default
# X-Forwarded-For to something of your choice:
# RPAFheader X-Real-IP
</IfModule>

Enable Apache rpaf module

1
$ sudo a2enmod rpaf

Add apache website rpaf module support

1
2
3
4
RPAFenable On
RPAFsethostname On
RPAFproxy_ips 127.0.0.1 xx.xx.xx.xx
RPAFheader X-Real-IP

xx.xx.xx.xx is your proxy server ip address(es), multiple addresses can be space separated. It will tell mod_rpaf which host to get X-real-IP headers from.

The full apache website configuration:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ cat /etc/apache2/sites-enabled/site3.conf 
<VirtualHost *:8013>
ServerName www.a.com
ServerAlias *.a.com

DocumentRoot /www
<Directory /www>
Options Indexes FollowSymLinks MultiViews
AllowOverride all
Require all granted
</Directory>

RPAFenable On
RPAFsethostname On
RPAFproxy_ips 127.0.0.1 192.168.33.10
RPAFheader X-Real-IP

ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Restart Apache

1
$ sudo apachectl restart

Check Apache running access log to know the real access ip

After Web Client access to server

1
2
3
4
5
6
$ sudo tail -f /var/log/apache2/access.log
...
...
127.0.0.1 - - [18/May/2017:11:41:08 +0000] "GET / HTTP/1.0" 200 265 "-" "curl/7.35.0"
192.168.33.11 - - [18/May/2017:12:46:12 +0000] "GET / HTTP/1.0" 200 265 "-" "curl/7.35.0"
...

Share