Reveal real IP for Nginx behind a reverse proxy

Reveal real IP for Nginx behind a reverse proxy

pass real IP

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.

Restore real IPs by Nginx header name

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.

Ads by Google

林宏

Frank Lin

Hey, there! This is Frank Lin (@flinhong), one of the 1.4 billion 🇨🇳. This 'inDev. Journal' site holds the exploration of my quirky thoughts and random adventures through life. Hope you enjoy reading and perusing my posts.

YOU MAY ALSO LIKE

Setup an IKEv2 server with StrongSwan

Tutorials

2020.01.09

Setup an IKEv2 server with StrongSwan

IKEv2, or Internet Key Exchange v2, is a protocol that allows for direct IPSec tunneling between two points. In IKEv2 implementations, IPSec provides encryption for the network traffic. IKEv2 is natively supported on some platforms (OS X 10.11+, iOS 9.1+, and Windows 10) with no additional applications necessary, and it handles client hiccups quite smoothly.

Allowing Cloudflare IP addresses only in Nginx

Tutorials

2020.11.18

Allowing Cloudflare IP addresses only in Nginx

If your HTTP server is running behind Cloudflare, it is recommended to only allow traffic from Cloudflare IP addresses. We can config this systematically using iptables. However, it's also flexible to white list Cloudflare IPs just inside the Nginx service.

TOC

Buy Me A Coffee