Using nginx to detect the real client IP and return a Status 403 Denied when your site is proxied by Cloudflare

When you setup a website…

Login

Blog History

When you setup a website sitting behind the Cloudflare Free Plan Cloudflare sends a CF-Connecting-IP header to tell your webserver what the real IP of the connecting client is. You can't see this in the default nginx logs.

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

To get my logs to show the Real Client IP I've modified my log_format in the http context in nginx.conf to produce the above log entries so I can see the Remote Client IP in my nginx server logs

I've also added an include to a file that has a geo map in it

# /etc/nginx/nginx.conf
http {

        # 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"';

      include geo-block.conf

When checking my logs I've been finding thousands of automated POST requests to /xmlrpc.php:

188.166.220.242 162.158.189.21 - [29/Jan/2025:06:28:12 +0000] "POST //xmlrpc.php HTTP/2.0" 200 179 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4240.193 Safari/537.36"
188.166.220.242 162.158.189.21 - [29/Jan/2025:06:28:12 +0000] "POST //xmlrpc.php HTTP/2.0" 200 179 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4240.193 Safari/537.36"
188.166.220.242 162.158.189.21 - [29/Jan/2025:06:28:12 +0000] "POST //xmlrpc.php HTTP/2.0" 200 179 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4240.193 Safari/537.36"
188.166.220.242 162.158.189.21 - [29/Jan/2025:06:28:12 +0000] "POST //xmlrpc.php HTTP/2.0" 200 179 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4240.193 Safari/537.36"
188.166.220.242 162.158.189.21 - [29/Jan/2025:06:28:13 +0000] "POST //xmlrpc.php HTTP/2.0" 200 179 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4240.193 Safari/537.36"

I want to block these by returning 0 (false) or 1 (true) if the CF-Connecting-IP matches the IP's or subnets I want to block

Here is the contents of /etc/nginx/geo-block.conf

geo $http_cf_connecting_ip $block {
        default         0;
        154.26.130.54   1;
        188.166.220.242 1;
}

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)

server {
    server_name example.com; 
   // I put this after server_name before 
    if ($block) {
                return 403;
    }

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

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

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.