I’m currently using LogDNA for tracking Nginx logs. Meanwhile, my Nginx server is behind Cloudflare proxy, I can only see IPs of Cloudflare by default in LogDNA. Let’s see how to reveal user’s real IP address in the logs behind such reverse proxy server by using ngx_http_realip_module
.
Check ngx_http_realip_module
First, let’s see whether the ngx_http_realip_module
was installed.
nginx -V 2>&1 | egrep --color -o 'http_realip_module'
nginx -V 2>&1 | egrep --color -o 'realip_module'
If your Nginx was installed by apt
, this module should be compiled by default.
Edit your Nginx configuration file such as nginx.conf
or any virtual domain configuration. For example:
sudo nano /etc/nginx/nginx.conf
Set the following in http
, server
, or location
context as follows:
real_ip_header X-Forwarded-For;
If you’re using Cloudflare, try the following:
real_ip_header CF-Connecting-IP;
Some cloud reverse proxy passes on header named X-Real-IP
, so try the following:
real_ip_header X-Real-IP;
Get real IPs from reverse proxy
We need to define the trusted IPs that are known to send correct replacement addresses. Typically we need to add upstream server IPs using following syntax:
set_real_ip_from ipv4_address;
set_real_ip_from ipv6_address;
set_real_ip_from sub/net;
set_real_ip_from CIDR;
For example:
set_real_ip_from 123.123.123.123;
set_real_ip_from 123.123.123.0/24;
For Cloudflare’s IPs, you can use the script from https://github.com/ergin/nginx-cloudflare-real-ip to automatically config/update the IPs.
Restart Nginx server
After setting your configuration files, don’t forget to restart/reload Nginx. It’s better to check the configs before reload Nginx:
sudo nginx -t
sudo systemctl reload nginx
A helper script for Cloudflare
Here’s the shell script I used to configure my Nginx server that only allow Cloudflare IPs to access and get user’s real IPs from Cloudflare proxy:
#!/bin/bash
set -e
cf_ips() {
echo "# https://www.cloudflare.com/ips"
for type in v4 v6; do
echo "# IP$type"
curl -s "https://www.cloudflare.com/ips-$type" | sed "s|^|set_real_ip_from |g" | sed "s|\$|;|g"
echo
done
echo "real_ip_header CF-Connecting-IP;"
echo "# Generated at $(LC_ALL=C date)"
}
cf_ips > /etc/nginx/allow-cloudflare.conf
sudo systemctl reload nginx
Sample output like:
# https://www.cloudflare.com/ips
# IPv4
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/12;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;
# IPv6
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2a06:98c0::/29;
set_real_ip_from 2c0f:f248::/32;
real_ip_header CF-Connecting-IP;
# Generated at Sat Dec 26 17:03:29 CST 2020
You can include the generated /etc/nginx/allow-cloudflare.conf
file in your virtual domain configuration file where required:
include /etc/nginx/allow-cloudflare.conf;
Also, it’s better to set a cron job to run the above script to update the Cloudflare IPs regularly.
A little more
However, I found the set_real_ip_from
cannot work together with Nginx’s allow/deny
configuration.
Since my Nginx server is just one level behind Cloudflare’s proxy, I’m intend to just allow requests from Cloudflare IPs, and get the real client’s IP from $http_x_forwarded_for
. For system logs, we can adapt the Nginx [log_format](https://docs.nginx.com/nginx/admin-guide/monitoring/logging/)
to log forwarded IPs using $http_x_forwarded_for
instead of $remote_addr
.