Cloudflare + nginx 限制ip访问的几种方式(白嫖cloudflare的ip数据库)

之前使用了ngx_http_geoip2_module模块来对自己的博客进行限制国家访问,其实我的博客前面还套了一层cloudflae免费的CDN,还可以用cloudflare来实现这个功能,顺便还能规避使用免费的IP数据库数据更新不及时的问题。

要求:需要域名解析使用Cloudflare ,并且dns记录里开启代理

图片

获取真实ip

在nginx限制国外ip访问结尾说使用cloudflare代理后获取不到访问者真实ip,这里先把这个解决一下

Cloudflare 使用 “CF-Connecting-IP” 标头和 “X-Forwarded-For” 标头发送源服务器访问者的 IP,要将原始访问者 IP 包含在日志中,我们在在 log_format 指令中添加变量 和http_x_forwarded_for即可

根据国家限制

根据国家做限制这里有两种实现方式

1、使用http标头在nginx里做

2、cloudflare上自定义安全规则

1、使用http标头

cloudflare提供了http标头CF-IPCountry包含原始访客国家的两个字符的国家代码。

除了ISO-3166-1 alpha-2 代码之外,Cloudflare 还使用以下特殊国家代码:

  • XX

    - 用于没有国家代码数据的客户,例如CN,US,JP

  • T1

    - 用于使用 Tor 网络的客户端。

我们修改一下日志格式为,在日志中打印一下国家代码

log_format debuglog '
  $remote_addr - $remote_user [$time_local] "$request"
  Status: $status
  Host: $host
  UA: $http_user_agent
  X-Real-IP: $http_x_real_ip
  X-Forwarded-For: $http_x_forwarded_for
  CF-Connecting-IP: $http_cf_connecting_ip
  CF-IPCountry: $http_cf_ipcountry
  Forwarded: $http_forwarded
  All: $http_x_forwarded_for,$http_cf_connecting_ip,$http_x_real_ip
';

访问日志如下:

  162.158.106.132 - - [14/Aug/2025:21:11:29 +0800]"GET /content.json?t=1755177088692 HTTP/1.1"
  Status:200
  Host: www.lishuai.fun
  UA: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36
  X-Real-IP:162.158.106.132
  X-Forwarded-For:162.158.106.132
  CF-Connecting-IP:160.16.79.228
  CF-IPCountry: JP
  Forwarded: -
  All:162.158.106.132,160.16.79.228,162.158.106.132

172.71.183.224 - - [14/Aug/2025:21:11:35 +0800]"GET /favicon.ico HTTP/1.1"
  Status:404
  Host: www.lishuai.fun
  UA: Mozilla/5.067805899 Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36
  X-Real-IP:172.71.183.224
  X-Forwarded-For:172.71.183.224
  CF-Connecting-IP:59.173.133.69
  CF-IPCountry: CN
  Forwarded: -
  All:172.71.183.224,59.173.133.69,172.71.183.224

可以看到日志中打印出的CF-Connecting-IPCF-IPCountry 后的内容就是访客的源IP和访客的国家。

比如我们这里只允许访客IP为中国访问

在nginx配置文件的http段里添加

    map $http_cf_ipcountry  $cf_allowed_country {
                default yes;
                CN no;
    }

在nginx配置文件server段添加

    location @deny403 {
        default_type 'text/html; charset=utf-8';
        return 403 "<html><head><meta charset='UTF-8'></head><body><h1>Access Denied</h1>
            <p>Your IP: $http_cf_connecting_ip</p>
            <p>Your Country: $http_cf_ipcountry</p>
            <p>请使用中国大陆IP访问</p>
            <p>Access is only allowed from IP addresses located in mainland China.</p>
            </body></html>";
    }

    # 使用cf返回的国家code限制
    if ($cf_allowed_country = yes) {
       return 403;
    }

nginx -s reload 重载一下配置验证一下,可以看到我使用日本和美国的ip进行访问均被拒绝了

图片

图片

2、cloudflare上自定义安全规则

复原一下nginx配置,保证对访问无限制,在cloudflare控制台下找到

图片

定义一个规则,针对www.lishuai.fun 阻止访客ip为Japan访问

注意: 这里规则会应用于cloudflare dns记录里所有开启代理的子域名上,如果需要对某个二级域名限制,可以使用主机名过滤一下,这里可以选择的很多,比如 ASN,国家/地区,请求方法,标头,http版本,uri,mime类型等等,不过没有提供根据访问ip所属的城市来限制

图片

我们这时候在使用日本ip访问就会发现,已经被拒绝了,并且403页面也是cloudflare提供的了

图片

根据城市限制

启用添加访问者位置标头的托管转换后,可以获取到更新位置相关的标头

图片

将带有访问者 IP 地址位置信息的 HTTP 标头添加到发送到原始服务器的请求中:

  • cf-ipcity

    :访客所在的城市(来自ip.src.city字段的值)。

  • cf-ipcountry

    :访客的国家(来自ip.src.country字段的值)。

  • cf-ipcontinent

    :访客的大陆(来自ip.src.continent字段的值)。

  • cf-iplongitude

    :访客的经度(来自ip.src.lon字段的值)。

  • cf-iplatitude

    :访客的纬度(来自ip.src.lat字段的值)。

  • cf-region

    :访客的地区(来自ip.src.region字段的值)。

  • cf-region-code

    :访客的地区代码(来自ip.src.region_code字段的值)。

  • cf-metro-code

    :访客的都市代码(来自ip.src.metro_code字段的值)。

  • cf-postal-code

    :访客的邮政编码(来自ip.src.postal_code字段的值)。

  • cf-timezone

    :访问者时区的名称(来自ip.src.timezone.name字段的值)。

注意:即使关闭**“添加访问者位置标头”**,也会向原始服务器发送HTTP 标头,cf-ipcountry 这也是上面不用修改任何设置在配置文件使用$http_cf_ipcountry来对访客的国家做限制。

这时候我们就可以根据城市来限制访问了,修改nginx的配置文件,在http段添加如下日志文件格式,

    log_format  log_cf  '$http_cf_connecting_ip $http_cf_ipcountry $http_cf_ipcity - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" "$scheme://$host$request_uri" $remote_addr '
                      '$http_cf_ipcontinent $http_cf_iplongitude $http_cf_iplatitude $http_cf_regio' ;

这个时候日志就根据我们的定义打印出了,国家和城市等信息

129.146.246.88 US Phoenix - - [14/Aug/2025:22:39:21 +0800] "GET /favicon.ico HTTP/1.1" 403 311 "https://www.lishuai.fun/2025/08/06/ollam-run-gpt-oss-20b/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36" "172.70.211.195" "http://www.lishuai.fun/favicon.ico" 172.70.211.195 NA -111.99840 33.46650 -
58.59.246.97 CN Nanning - - [14/Aug/2025:22:39:24 +0800] "GET /favicon.ico HTTP/1.1" 404 548 "-" "Mozilla/5.067805899 Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36" "172.71.183.224" "http://www.lishuai.fun/favicon.ico" 172.71.183.224 AS 108.31667 22.81667 -

现在有两个ip,所属城市分别Osaka和Tokyo ,现在我想限制ip所属城市为Tokyo时禁止访问

修改nginx配置文件,在http段添加如下

    map $http_cf_ipcity  $cf_deny_city {
        default no ;
        Tokyo yes;
    }

修改nginx配置文件,在server段下添加如下

    location @cfdeny403 {
        default_type 'text/html; charset=utf-8';
        return 403 "<html><head><meta charset='UTF-8'></head><body><h1>Access Denied</h1>
            <p>Your IP: $http_cf_connecting_ip</p>
            <p>Your Country: $http_cf_ipcountry</p>
            <p>Your City: $http_cf_ipcity</p>
            <p>请使用中国大陆IP访问</p>
            <p>Access is only allowed from IP addresses located in mainland China.</p>
            </body></html>";
    }
    if ( $cf_deny_city = yes) {
        return 403;
    }

当使用ip所属城市为Tokyo访问

图片

当使用ip所属城市为Osaka访问正常

图片

通过日志我们也可以看出来,当访问者城市是Tokyo 状态码是403 ,当访问者城市是Osaka ,状态码是200

160.16.79.228 JP Tokyo - - [14/Aug/2025:23:10:03 +0800] "GET /ip.html HTTP/1.1" 403 346 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36" "172.69.165.80" "http://www.lishuai.fun/ip.html" 172.69.165.80 AS 139.69171 35.68950 -
219.94.232.108 JP Osaka - - [14/Aug/2025:23:10:12 +0800] "GET /ip.html HTTP/1.1" 403 205 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36" "162.158.108.110" "http://www.lishuai.fun/ip.html" 162.158.108.110 AS 135.50107 34.69379 -
219.94.232.108 JP Osaka - - [14/Aug/2025:23:10:21 +0800] "GET / HTTP/1.1" 200 18972 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36" "162.158.108.110" "http://www.lishuai.fun/" 162.158.108.110 AS 135.50107 34.69379 -
219.94.232.108 JP Osaka - - [14/Aug/2025:23:10:23 +0800] "GET /content.json?t=1755184223022 HTTP/1.1" 200 4867 "https://www.lishuai.fun/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36" "162.158.108.110" "http://www.lishuai.fun/content.json?t=1755184223022" 162.158.108.110 AS 135.50107 34.69379 -

总结

个人最后还是使用cloudflare提供的标头的方式,通过获取到国家和城市,本来想着使用cloudflare提供的数据能更好的去使用goaccess去分析,并且也不用再去手动更新ip数据库里,并且cloudflare的ip数据库还是很准确的,相当于白嫖了商用IP数据库,结果发现goaccess 中根据ip显示的国家和城市只能通过指定ip数据库文件去解析,这个比较遗憾,不过还是可以根据cloudflare提供的国家和城市,以及goaccess的分析可以更精确的对一些访问进行限制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

马立杰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值