Reveal real IP for Nginx behind a reverse proxy

Reveal real IP for Nginx behind a reverse proxy

pass real IP

Tools / Tutorials

2022.06.06

0 👣 #nginx #proxy

I’m currently using LogDNA for gathering Nginx logs. However, I can only see IPs from Cloudflare by default in the logs as my server was proxied by Cloudflare. Let’s see how to reveal the real IP address of the client 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 directive in the 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 a shell script I used to configure my Nginx server that get user’s real IPs from Cloudflare proxies:

#!/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/cloudflare-ips.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

Then, you can include the generated /etc/nginx/cloudflare-ips.conf file in your virtual domain configuration file where required:

include /etc/nginx/cloudflare-ips.conf;

After that, the $remote_addr variable should hold the correct IP address from the client.

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 that set_real_ip_from cannot work together with allow/deny configuration.

Since my Nginx server is just one level behind Cloudflare, I’m more intended to just allow requests from Cloudflare IPs, and get the real client’s IP from the $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 the $http_x_forwarded_for instead of the $remote_addr. See this post to find out how that works.

THE END
Ads by Google

林宏

Frank Lin, PhD

Hey, there! This is Frank Lin (@flinhong), one of the 1.41 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 tunnelling 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 configure this systematically using iptables. However, it's also flexible to white list Cloudflare IPs just inside the Nginx service.