WordPress 使用 Nginx 限制每个 IP 地址访问 URL 的频率

编辑于:2022年01月04日

WordPress 使用 Nginx 限制每个 IP 地址访问 URL 的频率

在保护 API 接口、阻止暴力破解和预防 CC 攻击等方面,我们希望限制单个 IP 访问 URL 的频率,比如每秒只能请求一次,或每分钟访问一次等,Nginxlimit_req_zone 可以实现限制请求速率的需求。虫子菌将以宝塔面板 + WordPress 网站为例,详细解读 limit_req_zone 的参数配置。

1. limit_req_zone

http {
    #...
    #设置名为 cccitu 的内存区域,10 MB大小,单个 IP 限制每分钟访问 1 次
    limit_req_zone $binary_remote_addr zone=cccitu:10m rate=1r/m;

    server {
        #...
        #对 https://www.cccitu.com/5065.html 进行访问频率限制
        location =/5065.html {
            #如果同 IP 一分钟内发起 10 并发请求,第 1 个请求立即处理,缓存 5 个请求后每分钟处理一个,剩下的 4 个直接返回 503 错误
            limit_req zone=cccitu burst=5 nodelay;
        }
    }
}

如上所示,limit_req_zone 的启用只有非常简单的两行代码,将它们写在 Nginx 的配置文件中即可生效。

imit_req_zone $binary_remote_addr zone=one:10m rate=1r/s; 只能放在 http {} 内;limit_req zone=one burst=5 nodelay; 则可以根据需要放在 http {} (对服务器内所有的网站生效)、server {} (对具体的一个网站生效)或 location {} (对具体的一个网址生效)

2. 实例部署

虫子菌以使用宝塔面板部署的 WordPress 的网站为例,假设要限制对 https://www.cccitu.com/5065.html 的请求速率,每个 IP 地址,每分钟只能访问此网址 1 次。部署过程分为两部分:第一部分在 http {} 内开启 limit_req_zone 功能,第二部分在 location {} 内对具体 URL 做频率限制。

2.1 第一部分 http {}

2.1.1 代码部署:

#zone= 和 rate= 的内容,可以根据需要自行设置
limit_req_zone $binary_remote_addr zone=cccitu:10m rate=1r/s;

将如上代码添加到 Nginx 配置文件的 http {} 内。

2.1.2 参数解读:

  • zone=cccitu:10m
  • 将 IP 地址保存在名为 cccitu 内存区域,该区域储存空间为 10 MB。区域名称可以随便设置,但要注意后面用的时候名称要一致;1m 空间大约能保存 1.6 万条 IP 地址,10m 完全够用了,空间满了新数据会覆盖旧数据。

  • rate=1r/m
  • 限制访问请求频率为每分钟 1 次,可根据需要自行设置,1r/s 是 1 秒 1 次,30r/m 是 1 分钟 30 次(换算为 2 秒 1 次),需要注意时间单位只能选择 s (秒)或 m (分),最低频率限制是每分钟 1 次访问请求。

    2.2 第二部分 location {}

    2.2.1 代码部署:

    location = /5065.html {
            #以下需根据实际情况修改
            #教程:https://www.cccitu.com/5065.html
            limit_req zone=cccitu burst=5 nodelay;
            try_files $uri $uri/ /index.php?$args;
            fastcgi_pass unix:/tmp/php-cgi-73.sock;
            
            #以下固定内容,无需修改
            fastcgi_index index.php;
            include fastcgi_params;         
            fastcgi_param  SCRIPT_FILENAME $document_root/$fastcgi_script_name; 
        }
    

    将如上代码添加到 Nginx 的配置文件针对 www.cccitu.com 站点的 server {} 内。

    2.2.2 参数解读:

  • location = /5065.html
  • = /5065.html 只对网址 www.cccitu.com/5065.html 生效,= / 只对 www.cccitu.com 生效,只保留 location 后面什么也不写则是对该网站的所有网址生效。

  • limit_req zone=cccitu burst=5 nodelay;
  • zone=cccitu 是存放 IP 地址的内存区域名称,要与第一部分在 http {} 中设置的名称保持,前面叫 cccitu,这里也要写 cccitu。这一行其实有 3 种写法,在此例子中我们将限制频率为 1 分钟 1 次(rate=1r/s),如果瞬间并发了 10 次请求,这 3 种写法的效果分别如下 :

    #立即处理第 1 个请求,其余 9 个直接返回 503 错误
    limit_req zone=cccitu; 
    
    #立即处理第 1 个请求,第 2-6 个请求缓存后排队 1 分钟处理 1 个,第 7-10 个请求返回 503 错误
    limit_req zone=cccitu burst=5; 
    
    #立即处理第 1-5 个请求,第 7-10 请求返回 503 错误
    limit_req zone=cccitu burst=5 nodelay; 
    
  • try_files $uri $uri/ /index.php?$args;
  • 是 WordPress 的伪静态(宝塔面板——网站——设置——伪静态)如果你没设置伪静态或者没用 WordPress,可以删掉不写。

  • fastcgi_pass unix:/tmp/php-cgi.sock;
  • PHP 连接配置,有 192.168.1.25:9001unix:/tmp/php8.sock 两种写法,并且不同版本的 PHP 所写内容也不同,具体怎么写,请与所使用 PHP 的 FPM 配置文件一致(宝塔面板——软件商店——所安装PHP——FPM 配置文件)

    其它没提及的内容,是默认固定配置,不用专门修改。

    2.3 额外补充:

    location = /5065.html {
            #教程:https://www.cccitu.com/5065.html
            limit_req zone=cccitu burst=5 nodelay;
            try_files $uri $uri/ /index.php?$args; 
        }
    

    对于宝塔面板 + WordPress,如果针对的 URL 文章/标签/分类,不是 网站首页、wp-login.php、admin-ajax.php 等,那么,http {} 保持不变,location {} 有更简单的写法,如上所示。

    相关推荐

    6 条评论

    1. 7042-22120219

      写的最通俗易懂的,并且按照教学设置好了!
      但是我有个问题想问下大佬,希望大佬看到了能给我一个回复~
      就是rate=2r/s; 这个请求是什么意思?
      是指一个页面吗?还是说这个页面上所有的内容,包括CSS,JS,图片等等~
      我设置了2r/s,但是页面也能打开~
      然后就是burst,我设置了burst=1,似乎一些图片什么的就显示不出来了~
      我就有点搞不明白这个请求~~
      可以讲解一下吗?

      • @7042-22120219 如果不是针对某个具体的URL做限制,那么:

        rate=2r/s 是每秒允许2个请求,网页由 html/css/js/png/jpg 等组成。如果你网站没用 CDN,所有 JS/CSS/PNG 等文件都保存在服务器并且每次都从服务器读取,那么别人打开你的一个网址,就要同时产生 html/css/js/png 等 10几个请求,如果只允许每秒 2 次请求,就非常严苛了。具体的请求次数,你可以在浏览器控制台查看。

        burst=1 是允许的列队数量。假如一个页面有 10 次请求,你设置 burst=1 ,就是允许在第1秒处理其中的 2 个请求,剩下的8个请求,在第 2 秒处理 1 个,剩下的 7 个请求返回 503 错误,所以你网页的的图片请求,被报 503,就打不开了。

        • 7042-22120219

          @CCCiTU 我看浏览器下面请求要将近100次,有的页面要将近200个请求了。。如果设置1秒允许一个ip访问1个html页面。。我设置200r/s,burst=50,应该可以吧?

          • @7042-22120219 100次全是来自你服务器的域名吗?如果你用了广告联盟/或者其它第三方JS,那么真实的请求数量就不会这么多了,其次css/js一般会缓存到浏览器,除了第一次访问以及缓存到期了,一般不会反复请求。这些情况你需要综合考虑。如果你只是想控制每个IP的并发访问次数,而不是类似1小时只允许一个IP访问一千次这种固定的次数限制,那么 burst 可以设置高一些没事,让这些请求1秒1秒的排队处理就行,用户访问会慢,但不会报错。

            • 7042-22120219

              @CCCiTU 并发不是一个ip同时打开很多页面才叫并发吗?我只是想限制单个ip的访问速率,我觉得我网站有一些ip每天访问太高了,估计是抓取或者是采集的,这些到无所谓,但是有时加上自然访问高峰,服务器的负载和cpu就直接百分百了。所以想限制下速率。。单个ip控制在1秒一个页面,毕竟正常访问,打开一个页面就在1秒左右。。

            • @7042-22120219 只控制并发的话,那你预估一下页面请求次数,来控制允许每秒或者每分钟的访问次数就行了。