Using nginx to detect the Real Client IP and return a Status 403 Forbidden when your Site is Proxied by Cloudflare

by | Jan 29, 2025 | IT Tips | 0 comments

When using Cloudflare proxying. By default the nginx logs show the remote_addr (162.158.3.22) as one of the multitudinous Cloudflare proxy server IP addresses:

Following is how you can configure your nginx conf files to return 403 (Forbidden) to specified IP's and Subnets based on the CF-Connecting-IP header that Cloudflare sets with each proxied request

Check your instance of nginx has the geo module

Create a geo block conf file

1
2
3
4
5
6
7
8
9
10
11
# /etc/nginx/geo-block.conf
geo $http_cf_connecting_ip $block {
        default         0;
        # list your IPv4 and IPv6 IPs and subnets you want to block here followed by a 1
        154.26.130.54   1;
        188.166.220.242 1;
        1.14.77.81  1;
        134.199.144.0/20    1;
        2403:3433:21f:2ad0::/64 1;
        2403:3433:21f:2ad0:234::1 1;
}

Matched CF-Connecting-IP header IPs or Subnets set $block to be 1 (true), or 0 (false) by default

In the http context of your nginx config create a new custom log format that includes $http_cf_connecting_ip

1
2
3
4
5
6
7
8
9
# /etc/nginx/nginx.conf
http {
        # Custom logging Settings
        log_format cloudflareformat '$http_cf_connecting_ip $remote_addr $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent"';
 
      # remember to include the geo block conf
      include geo-block.conf

Reference the new log format of the site that is proxied by cloud format

1
2
3
4
server {
    server_name example.com.au www.example.com.au;
    access_log /var/log/nginx/tgn_access.log cloudflareformat;
    # lots of other config stuff...

Put in a some logic to return 403 when the connecting IP is matched

In the server context of an nginx site e.g. /etc/nginx/sites-enabled/default.conf add an if statement to return 403 if geo sets $block to 1 (true)

1
2
3
4
5
6
7
server {
     server_name example.com.au www.example.com.au;
     access_log /var/log/nginx/tgn_access.log cloudflareformat;
     // I put this after server_name before
     if ($block) {
                return 403;
     }

Finally each time you edit the geo-block.conf file to include some new IP addresses to deny. Check the syntax and run a reload

1
2
3
4
5
6
7
8
nginx -t
 
#output
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
 
# finally get nginx to reread its conf files if they have changed
systemctl reload nginx.service

Example of tailed logs showing an automatted attack and a 403 Access denied code being returned based on the value of $http_cf_connecting_ip

As seen from browser

More information on the options available for configuring your webserver to sit behind Cloudflares proxy service:

https://developers.cloudflare.com/support/troubleshooting/restoring-visitor-ips/restoring-original-visitor-ips

0 Comments

Submit a Comment

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

The reCAPTCHA verification period has expired. Please reload the page.