How to Configure Nginx with Cloudflare, Cloudfront & Incapsula


Nginx Cloudflare, AWS Cloudfront, Incapsula & PageSpeed IP addresses:

Note: you may need to whitelist the IP addresses for the proxy in CSF Firewall for Cloudflare. For Cloudflare to prevent IP leaks you also want to enable Cloudflare Authenticated Origin Pull certificates on your Cloudflare Full SSL enabled sites.

If you use Cloudflare, AWS Cloudfront, Incapsula.com, Google PageSpeed Service or any reverse proxy in front of Nginx (Varnish cache, PageSpeed service, Cloud DDOS proxy etc), you will need to use Nginx's ngx_http_realip_module module which is compiled by default for Centmin Mod installs and set the set_real_ip_from and real_ip_header to properly allow Nginx to see the visiting user's real IP address and not the IP address of the reverse proxy or Cloudflare system.



Nginx Cloudflare IP addresses:

Cloudflare KB explains this here and maintains an updated list of Cloudflare IP addresses here. They also have a detailed list of article outlined here.

To use Cloudflare or a reverse proxy in front of Nginx you will need to add the following code to /usr/local/nginx/conf/nginx.conf in the http {} section if all sites on server are protected under Cloudflare. Or for specific domains and sites on server, in their domain name's Nginx vhost file which is being served via Cloudflare i.e. /usr/local/nginx/conf/conf.d/newdomain.com.conf within the server { } context. Then restart Nginx web server.

If using Centmin Mod 123.08stable or lower, see further below for manual setup instructions. If using Centmin Mod 123.09beta01 or newer branches, the generated Nginx vhost already have setup automated script to pull latest Cloudflare IPs for CSF Firewall whitelisting outlined here. The generated Nginx vhost will have an include file /usr/local/nginx/conf/cloudflare.conf that is prepopulated with Cloudflare IPs pulled in via a cronjob you manually setup as outlined here.

  # uncomment cloudflare.conf include if using cloudflare for
  # server and/or vhost site
  include /usr/local/nginx/conf/cloudflare.conf;

cronjob you manually setup

23 */36 * * * /usr/local/src/centminmod/tools/csfcf.sh auto >/dev/null 2>&1

Cloudflare IPs as at March 27th, 2018. A updated list of Cloudflare IP addresses here

For Cloudflare IPv4 addresses:

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 104.16.0.0/12;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
real_ip_header CF-Connecting-IP;

For Cloudflare IPv6 addresses: (Note: not entirely sure these are correct for IPv6).

 
# Cloudflare
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2c0f:f248::/32;
set_real_ip_from 2a06:98c0::/29;
real_ip_header CF-Connecting-IP;

If you'd combining both IPv4 and IPv6 it's the below format with only one real_ip_header CF-Connecting-IP; instance. Add the following code to /usr/local/nginx/conf/nginx.conf in the http {} section and/or any other domain name's Nginx vhost file which is being served via Cloudflare i.e. /usr/local/nginx/conf/conf.d/newdomain.com.conf within the server { } context. Then restart Nginx web server.

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 104.16.0.0/12;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
#set_real_ip_from 2400:cb00::/32;
#set_real_ip_from 2405:8100::/32;
#set_real_ip_from 2405:b500::/32;
#set_real_ip_from 2606:4700::/32;
#set_real_ip_from 2803:f800::/32;
#set_real_ip_from 2c0f:f248::/32;
#set_real_ip_from 2a06:98c0::/29;
real_ip_header CF-Connecting-IP;

For a typical reverse proxy i.e. haproxy load balancer which Centminmod.com site uses:

 set_real_ip_from yourreverseproxyip;
 real_ip_header X-Forwarded-For;

Full context examples below:

For Cloudflare:

user              nginx nginx;
worker_processes  1;

worker_rlimit_nofile 51200;

error_log         logs/error.log;

pid               logs/nginx.pid;

events {
    worker_connections  32768;
    use epoll;
}

http {
 # Cloudflare
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 104.16.0.0/12;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
real_ip_header CF-Connecting-IP;

    index  index.php index.html index.htm;
    include       mime.types;
    default_type  application/octet-stream;

For a typical reverse proxy i.e. haproxy load balancer which Centminmod.com site uses:

user              nginx nginx;
worker_processes  1;

worker_rlimit_nofile 51200;

error_log         logs/error.log;

pid               logs/nginx.pid;

events {
    worker_connections  32768;
    use epoll;
}

http {
 set_real_ip_from yourreverseproxyip;
 real_ip_header X-Forwarded-For;

    index  index.php index.html index.htm;
    include       mime.types;
    default_type  application/octet-stream;

You can also use Nginx include file to make editing easier i.e. add the settings to /usr/local/nginx/conf/csfips.conf you create and include it.

user              nginx nginx;
worker_processes  1;

worker_rlimit_nofile 51200;

error_log         logs/error.log;

pid               logs/nginx.pid;

events {
    worker_connections  32768;
    use epoll;
}

http {
include /usr/local/nginx/conf/csfips.conf;

    index  index.php index.html index.htm;
    include       mime.types;
    default_type  application/octet-stream;

with contents of:

 # Cloudflare
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 104.16.0.0/12;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
real_ip_header CF-Connecting-IP;

Save the Nginx vhost file and then restart Nginx server

  service nginx restart

or via command line shortcut

  ngxrestart


Nginx AWS Cloudfront IP addresses:

Amazon AWS Cloudfront lists it's IP Ranges at https://docs.aws.amazon.com/general/latest/gr/aws-ip-ranges.html. They seem to only use IPv4 IP ranges for AWS Cloudfront service so there are no IPv6 IPs to deal with.

For Amazon AWS Cloudfront IPv4 addresses:

To grab the list of IPv4 IP ranges for Amazon AWS Cloudfront, you can use jq tool which you can use yum -y install jq if it's missing on your service.

First download the ip-ranges.json file via wget to a directory of your choice.

wget -4 https://ip-ranges.amazonaws.com/ip-ranges.json -O ip-ranges.json

Within that directory you saved ip-ranges.json to, you can use jq tool to filter what you need.

Services listing which groups Amazon AWS IP range listings by service type. The service we are interested in is Cloudfront only.

cat ip-ranges.json | jq -r '.prefixes[] | .service' | sort | uniq

cat ip-ranges.json | jq -r '.prefixes[] | .service' | sort | uniq

AMAZON
AMAZON_CONNECT
API_GATEWAY
CLOUD9
CLOUDFRONT
CODEBUILD
DYNAMODB
EC2
EC2_INSTANCE_CONNECT
GLOBALACCELERATOR
ROUTE53
ROUTE53_HEALTHCHECKS
ROUTE53_HEALTHCHECKS_PUBLISHING
S3
WORKSPACES_GATEWAYS

Only list the full AWS Cloudfront service json entries

cat ip-ranges.json | jq -r '.prefixes[] | select(.service=="CLOUDFRONT")'

small sample display output

cat ip-ranges.json | jq -r '.prefixes[] | select(.service=="CLOUDFRONT")'

{
  "ip_prefix": "52.78.247.128/26",
  "region": "ap-northeast-2",
  "service": "CLOUDFRONT",
  "network_border_group": "ap-northeast-2"
}
{
  "ip_prefix": "52.220.191.0/26",
  "region": "ap-southeast-1",
  "service": "CLOUDFRONT",
  "network_border_group": "ap-southeast-1"
}
{
  "ip_prefix": "34.232.163.208/29",
  "region": "us-east-1",
  "service": "CLOUDFRONT",
  "network_border_group": "us-east-1"
}

Only list Amazon AWS Cloudfront IP ranges

cat ip-ranges.json | jq -r '.prefixes[] | select(.service=="CLOUDFRONT") | .ip_prefix'

cat ip-ranges.json | jq -r '.prefixes[] | select(.service=="CLOUDFRONT") | .ip_prefix'
144.220.0.0/16
52.124.128.0/17
54.230.0.0/16
54.239.128.0/18
52.82.128.0/19
99.84.0.0/16
204.246.172.0/24
54.239.192.0/19
70.132.0.0/18
13.32.0.0/15
205.251.208.0/20
13.224.0.0/14
13.35.0.0/16
204.246.164.0/22
204.246.168.0/22
71.152.0.0/17
216.137.32.0/19
205.251.249.0/24
99.86.0.0/16
52.46.0.0/18
52.84.0.0/15
204.246.173.0/24
130.176.0.0/16
205.251.200.0/21
204.246.174.0/23
64.252.128.0/18
205.251.254.0/24
143.204.0.0/16
205.251.252.0/23
204.246.176.0/20
13.249.0.0/16
54.240.128.0/18
205.251.250.0/23
52.222.128.0/17
54.182.0.0/16
54.192.0.0/16
13.124.199.0/24
34.226.14.0/24
52.15.127.128/26
35.158.136.0/24
52.57.254.0/24
18.216.170.128/25
13.52.204.0/23
13.54.63.128/26
13.59.250.0/26
13.210.67.128/26
35.167.191.128/26
52.47.139.0/24
52.199.127.192/26
52.212.248.0/26
52.66.194.128/26
13.113.203.0/24
99.79.168.0/23
34.195.252.0/24
35.162.63.192/26
34.223.12.224/27
52.56.127.0/25
34.223.80.192/26
13.228.69.0/24
34.216.51.0/25
3.231.2.0/25
54.233.255.128/26
18.200.212.0/23
64.252.64.0/18
52.52.191.128/26
3.234.232.224/27
52.78.247.128/26
52.220.191.0/26
34.232.163.208/29

Now to get the Amazon AWS Cloudfront service only IP ranges and manipulate the IP ranges into Nginx real IP set_real_ip_from format

cat ip-ranges.json | jq -r '.prefixes[] | select(.service=="CLOUDFRONT") | .ip_prefix' | while read i; do echo "set_real_ip_from ${i};"; done; echo "real_ip_header X-Forwarded-For;"

resulting output set_real_ip_from output

cat ip-ranges.json | jq -r '.prefixes[] | select(.service=="CLOUDFRONT") | .ip_prefix' | while read i; do echo "set_real_ip_from ${i};"; done; echo "real_ip_header X-Forwarded-For;"
set_real_ip_from 144.220.0.0/16;
set_real_ip_from 52.124.128.0/17;
set_real_ip_from 54.230.0.0/16;
set_real_ip_from 54.239.128.0/18;
set_real_ip_from 52.82.128.0/19;
set_real_ip_from 99.84.0.0/16;
set_real_ip_from 204.246.172.0/24;
set_real_ip_from 54.239.192.0/19;
set_real_ip_from 70.132.0.0/18;
set_real_ip_from 13.32.0.0/15;
set_real_ip_from 205.251.208.0/20;
set_real_ip_from 13.224.0.0/14;
set_real_ip_from 13.35.0.0/16;
set_real_ip_from 204.246.164.0/22;
set_real_ip_from 204.246.168.0/22;
set_real_ip_from 71.152.0.0/17;
set_real_ip_from 216.137.32.0/19;
set_real_ip_from 205.251.249.0/24;
set_real_ip_from 99.86.0.0/16;
set_real_ip_from 52.46.0.0/18;
set_real_ip_from 52.84.0.0/15;
set_real_ip_from 204.246.173.0/24;
set_real_ip_from 130.176.0.0/16;
set_real_ip_from 205.251.200.0/21;
set_real_ip_from 204.246.174.0/23;
set_real_ip_from 64.252.128.0/18;
set_real_ip_from 205.251.254.0/24;
set_real_ip_from 143.204.0.0/16;
set_real_ip_from 205.251.252.0/23;
set_real_ip_from 204.246.176.0/20;
set_real_ip_from 13.249.0.0/16;
set_real_ip_from 54.240.128.0/18;
set_real_ip_from 205.251.250.0/23;
set_real_ip_from 52.222.128.0/17;
set_real_ip_from 54.182.0.0/16;
set_real_ip_from 54.192.0.0/16;
set_real_ip_from 13.124.199.0/24;
set_real_ip_from 34.226.14.0/24;
set_real_ip_from 52.15.127.128/26;
set_real_ip_from 35.158.136.0/24;
set_real_ip_from 52.57.254.0/24;
set_real_ip_from 18.216.170.128/25;
set_real_ip_from 13.52.204.0/23;
set_real_ip_from 13.54.63.128/26;
set_real_ip_from 13.59.250.0/26;
set_real_ip_from 13.210.67.128/26;
set_real_ip_from 35.167.191.128/26;
set_real_ip_from 52.47.139.0/24;
set_real_ip_from 52.199.127.192/26;
set_real_ip_from 52.212.248.0/26;
set_real_ip_from 52.66.194.128/26;
set_real_ip_from 13.113.203.0/24;
set_real_ip_from 99.79.168.0/23;
set_real_ip_from 34.195.252.0/24;
set_real_ip_from 35.162.63.192/26;
set_real_ip_from 34.223.12.224/27;
set_real_ip_from 52.56.127.0/25;
set_real_ip_from 34.223.80.192/26;
set_real_ip_from 13.228.69.0/24;
set_real_ip_from 34.216.51.0/25;
set_real_ip_from 3.231.2.0/25;
set_real_ip_from 54.233.255.128/26;
set_real_ip_from 18.200.212.0/23;
set_real_ip_from 64.252.64.0/18;
set_real_ip_from 52.52.191.128/26;
set_real_ip_from 3.234.232.224/27;
set_real_ip_from 52.78.247.128/26;
set_real_ip_from 52.220.191.0/26;
set_real_ip_from 34.232.163.208/29;
real_ip_header X-Forwarded-For;

You can also use Nginx include file to make editing easier i.e. add the resulting set_real_ip_from output to /usr/local/nginx/conf/cloudfront_ips.conf you create and include it in your Nginx vhost config file like you do for Cloudflare include file /usr/local/nginx/conf/csfips.conf outlined above.

So you can pipe the resulting set_real_ip_from output into to /usr/local/nginx/conf/cloudfront_ips.conf using command

( cat ip-ranges.json | jq -r '.prefixes[] | select(.service=="CLOUDFRONT") | .ip_prefix' | while read i; do echo "set_real_ip_from ${i};"; done; echo "real_ip_header X-Forwarded-For; " ) > /usr/local/nginx/conf/cloudfront_ips.conf

include it in your Nginx vhost domain config file i.e. /usr/local/nginx/conf/conf.d/newdomain.com.conf within the server { } context.

include /usr/local/nginx/conf/cloudfront_ips.conf;


Nginx Incapsula IP addresses:

Incapsula.com explains there IP ranges here.

For Incapsula IPv4 addresses:

 # Incapsula
set_real_ip_from 199.83.128.0/21;
set_real_ip_from 198.143.32.0/19;
set_real_ip_from 149.126.72.0/21;
set_real_ip_from 103.28.248.0/22;
set_real_ip_from 45.64.64.0/22;
set_real_ip_from 185.11.124.0/22;
set_real_ip_from 192.230.64.0/18;
set_real_ip_from 107.154.0.0/16;
set_real_ip_from 2a02:e980::/29;
real_ip_header X-Forwarded-For;


Nginx Google PageSpeed Service IP addresses:

Google also explains this in their Google PageSpeed Service FAQ. They don't provide a convenient list of IP addresses though, you have to do some work as explained in 'Google's IP addresses' page. When you run the nslookup commands on that page you get first the list of netblocks then the list of Google IP addresses from each of those netblocks like below.

For Centmin Mod users, first install bind-utils YUM package which contains nslookup command.

  yum -q -y install bind-utils

Then run commands:

nslookup -q=TXT _spf.google.com 8.8.8.8
nslookup -q=TXT _netblocks.google.com 8.8.8.8
nslookup -q=TXT _netblocks2.google.com 8.8.8.8
nslookup -q=TXT _netblocks3.google.com 8.8.8.8

Which output the following:

nslookup -q=TXT _spf.google.com 8.8.8.8
Server:         8.8.8.8
Address:        8.8.8.8#53

Non-authoritative answer:
_spf.google.com text = "v=spf1 include:_netblocks.google.com include:_netblocks2.google.com include:_netblocks3.google.com ~all"

Authoritative answers can be found from:

nslookup -q=TXT _netblocks.google.com 8.8.8.8
Server:         8.8.8.8
Address:        8.8.8.8#53

Non-authoritative answer:
_netblocks.google.com   text = "v=spf1 ip4:64.18.0.0/20 ip4:64.233.160.0/19 ip4:66.102.0.0/20 ip4:66.249.80.0/20 ip4:72.14.192.0/18 ip4:74.125.0.0/16 ip4:108.177.8.0/21 ip4:173.194.0.0/16 ip4:207.126.144.0/20 ip4:209.85.128.0/17 ip4:216.58.192.0/19 ip4:216.239.32.0/19 ~all"

Authoritative answers can be found from:

nslookup -q=TXT _netblocks2.google.com 8.8.8.8
Server:         8.8.8.8
Address:        8.8.8.8#53

Non-authoritative answer:
_netblocks2.google.com  text = "v=spf1 ip6:2001:4860:4000::/36 ip6:2404:6800:4000::/36 ip6:2607:f8b0:4000::/36 ip6:2800:3f0:4000::/36 ip6:2a00:1450:4000::/36 ip6:2c0f:fb50:4000::/36 ~all"

Authoritative answers can be found from:

nslookup -q=TXT _netblocks3.google.com 8.8.8.8
Server:         8.8.8.8
Address:        8.8.8.8#53

Non-authoritative answer:
_netblocks3.google.com  text = "v=spf1 ip4:172.217.0.0/19 ip4:108.177.96.0/19 ~all"

Authoritative answers can be found from:

Take the ipv4 (and ipv6 ips if you use ipv6) from Non-authoritative answer section to form the list of Google PageSpeed Service's IP address list and add real_ip_header X-Forwarded-For; line to complete what is required for Nginx configuration. Then add the following code to /usr/local/nginx/conf/nginx.conf in the http {} section. Then restart Nginx web server.

For Google PageSpeed Service IPv4 addresses:

 # Google IPs IPv4
set_real_ip_from 64.18.0.0/20;
set_real_ip_from 64.233.160.0/19;
set_real_ip_from 66.102.0.0/20;
set_real_ip_from 66.249.80.0/20;
set_real_ip_from 72.14.192.0/18;
set_real_ip_from 74.125.0.0/16;
set_real_ip_from 108.177.8.0/21;
set_real_ip_from 173.194.0.0/16;
set_real_ip_from 207.126.144.0/20;
set_real_ip_from 209.85.128.0/17;
set_real_ip_from 216.58.192.0/19;
set_real_ip_from 216.239.32.0/19;
set_real_ip_from 172.217.0.0/19;
set_real_ip_from 108.177.96.0/19;
real_ip_header X-Forwarded-For;

For Google PageSpeed Service IPv6 addresses:

 # Google IPs IPv6
set_real_ip_from 2001:4860:4000::/36;
set_real_ip_from 2404:6800:4000::/36;
set_real_ip_from 2607:f8b0:4000::/36;
set_real_ip_from 2800:3f0:4000::/36;
set_real_ip_from 2a00:1450:4000::/36;
set_real_ip_from 2c0f:fb50:4000::/36;
real_ip_header X-Forwarded-For;