Configuring Cloudflare and Nginx

Configuring Cloudflare and Nginx

Configuring Cloudflare and Nginx

These are the two common optimizations for Nginx configuration when combined with Cloudflare. First is to resolve the client IP address from the HTTP header of the proxied request and the second - to block all clients trying to access the webpage by skipping Cloudflare.
Combining the two is tricky, however.

Mandating access through Cloudflare

This is obvious and well advertised by Cloudflare. We don’t want to allow global access directly to our host for security and performance reasons.

So, we need to get the list from the Cloudflare IP Ranges page. Then this range shall be used as in the example below

1allow 173.245.48.0/20;
2allow 103.21.244.0/22;
3...
4# don't forget to include the ipv6 range as well
5
6deny all;

IP address resolution

Having the actual client IP address resolved is important! It helps keep the rate limiting by the IP address work as intended originally, for example, and and is useful for many other applications.

1set_real_ip_from 173.245.48.0/20;
2set_real_ip_from 103.21.244.0/22;
3...
4# still the same with ipv6
5
6real_ip_header CF-Connecting-IP;
7real_ip_recursive on;

This configuration asks Nginx to read the HTTP header property CF-Connecting-IP and override the TCP client IP address by using the provided value, but only when that connection is originated from Cloudflare infrastructure.
In case there is no such header property, or if the connection is not from Cloudflare, then Nginx keeps the original IP address, but does not block the traffic.

The combined configuration

If the combination is done by putting all this knowledge together in the Nginx configuration, then the access to the webpage will be broken, because Nginx is doing the IP address resolution first, and then will try to verify the actual client IP address to be part of the Cloudflare IP range. This will fail, and the page will be inaccessible globally.

Don’t give up, though. The solution is simple.

 1set_real_ip_from 173.245.48.0/20;
 2set_real_ip_from 103.21.244.0/22;
 3set_real_ip_from 103.22.200.0/22;
 4set_real_ip_from 103.31.4.0/22;
 5set_real_ip_from 141.101.64.0/18;
 6set_real_ip_from 108.162.192.0/18;
 7set_real_ip_from 190.93.240.0/20;
 8set_real_ip_from 188.114.96.0/20;
 9set_real_ip_from 197.234.240.0/22;
10set_real_ip_from 198.41.128.0/17;
11set_real_ip_from 162.158.0.0/15;
12set_real_ip_from 104.16.0.0/13;
13set_real_ip_from 104.24.0.0/14;
14set_real_ip_from 172.64.0.0/13;
15set_real_ip_from 131.0.72.0/22;
16
17set_real_ip_from 2400:cb00::/32;
18set_real_ip_from 2606:4700::/32;
19set_real_ip_from 2803:f800::/32;
20set_real_ip_from 2405:b500::/32;
21set_real_ip_from 2405:8100::/32;
22set_real_ip_from 2a06:98c0::/29;
23set_real_ip_from 2c0f:f248::/32;
24
25real_ip_header CF-Connecting-IP;
26real_ip_recursive on;
27
28if ($remote_addr = $realip_remote_addr) {
29    return 403;
30}

We can save this snippet to /etc/nginx/cloudflare-whitelist.conf for example and include it in any server scope desired.
This simply blocks the access to the page to any client that did not pass the IP resolution step.