nginx在CDN加速或使用SLB代理后,获取真实IP,做并发访问限制的方法(限流)

本文主要是介绍nginx在CDN加速或使用SLB代理后,获取真实IP,做并发访问限制的方法(限流),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文80%转载于张戈博客,后续加入了自己的理解和想法
原文地址:https://zhangge.net/4879.html

站点在运行时,为了防止DDoS 攻击、或内部接口调用造成的数据迸发,nginx提供了limit限流模块:

HttpLimitZoneModule 限制同时并发访问的数量
HttpLimitReqModule 限制访问数据,每秒内最多几个请求

一、普通配置:

什么叫普通配置?

普通配置就是针对【用户浏览器】→【网站服务器】这种常规模式的 nginx 配置。那么,如果我要对单 IP 做访问限制,绝大多数教程都是这样写的:

## 用户的 IP 地址 $binary_remote_addr 作为 Key,每个 IP 地址最多有 50 个并发连接
## 你想开 几千个连接 刷死我? 超过 50 个连接,直接返回 503 错误给你,根本不处理你的请求了
limit_conn_zone $binary_remote_addr zone=TotalConnLimitZone:10m ;
limit_conn  TotalConnLimitZone  50;
limit_conn_log_level notice;## 用户的 IP 地址 $binary_remote_addr 作为 Key,每个 IP 地址每秒处理 10 个请求
## 你想用程序每秒几百次的刷我,没戏,再快了就不处理了,直接返回 503 错误给你
limit_req_zone $binary_remote_addr zone=ConnLimitZone:10m  rate=10r/s;
limit_req_log_level notice;## 具体服务器配置
server {listen   80;location ~ \.php$ {## 最多 5 个排队, 由于每秒处理 10 个请求 + 5个排队,你一秒最多发送 15 个请求过来,再多就直接返回 503 错误给你了limit_req zone=ConnLimitZone burst=5 nodelay;fastcgi_pass   127.0.0.1:9000;fastcgi_index  index.php;include fastcgi_params;}   }

这样一个最简单的服务器安全限制访问就完成了,这个基本上你 Google 一搜索能搜索到 90% 的网站都是这个例子,而且还强调用“$binary_remote_addr”可以节省内存之类的云云。

二、CDN 或 SLB 代理之后

为了增加安全、性能,许多站点都用到了CDN加速,或者其他的二级代理,例如阿里的SLB负载均衡等等。

于是,网站的访问模式就变为:
用户浏览器 → CDN 节点 / SLB 节点→ 网站源服务器

甚至是更复杂的模式:
用户浏览器 → CDN/SLB 节点(CDN 入口、CC\DDoS 攻击流量清洗等) → 阿里云盾 → 源服务器

可以看到,我们的网站中间经历了好几层的透明加速和安全过滤, 这种情况下,我们就不能用上面的“普通配置”。因为普通配置中基于【源 IP 的限制】的结果就是,我们把【CDN /SLB节点】或者【阿里云盾】给限制了,因为这里“源 IP”地址不再是真实用户的 IP,而是中间 CDN /SLB节点的 IP 地址。

我们需要限制的是最前面的真实用户,而不是中间为我们做加速的加速服务器。

其实,当一个 CDN /SLB或者透明代理服务器把用户的请求转到后面服务器的时候,这个 CDN /SLB服务器会在 Http 的头中加入一个记录

X-Forwarded-For : 用户 IP, 代理服务器 IP

如果中间经历了不止一个代理服务器,这个记录会是这样

X-Forwarded-For : 用户 IP, 代理服务器 1-IP, 代理服务器 2-IP, 代理服务器 3-IP, ….

可以看到经过好多层代理之后, 用户的真实 IP 在第一个位置, 后面会跟一串中间代理服务器的 IP 地址,从这里取到用户真实的 IP 地址,针对这个 IP 地址做限制就可以了。

那么针对 CDN /SLB模式下的访问限制配置就应该这样写:

http{## 这里取得原始用户的IP地址,没走CDN/SLB的,给到$remote_addrmap $http_x_forwarded_for  $clientRealIp {default $remote_addr;~^(?P<firstAddr>[0-9\.]+),?.*$	$firstAddr;}#设置IP白名单,对内部的IP不设限map $clientRealIp $limit{default $clientRealIp;xx.xx.xx.xx "";}#以真实IP为单位,限制请求数,并返回429状态;limit_req_status 429;limit_req_zone $limit zone=ConnLimitZone:20m rate=5r/s;limit_req_log_level notice;#以真实IP为单位,限制该IP的并发连接数,并返回429状态;limit_conn_status 429;limit_conn_zone $limit zone=TotalConnLimitZone:20m ;limit_conn  TotalConnLimitZone 100;limit_conn_log_level notice;#以访问域名为单位,限制总并发链接数;limit_conn_zone $server_name zone=SumConnLimitZone:20m;
}## 具体Server:如下在监听php/go/java部分新增限制规则即可,或直接放在域名下面,限制全部访问
server {listen   80;location ~ \.php$ {#限制总并发连接数limit_conn SumConnLimitZone 10000;#最多5个排队, 由于每秒处理 10 个请求 + 5个排队,你一秒最多发送 15 个请求过来,再多就直接返回 429 错误给你了limit_req  zone=ConnLimitZone  burst=5  nodelay;fastcgi_pass   127.0.0.1:9000;fastcgi_index  index.php;include fastcgi_params;}   
}

三、如何验证

根据以上配置,我们知道nginx,每秒最多允许通过10+5个请求,在压测时,就会有两种情况:

  1. 在白名单内(到白名单的服务器测试),压测该站点,应该全部通过
  2. 不在白名单内,最多只允许通过10 +5 个请求,余下部分应该返回429

前提:压测总次数超过 10 +5,否则看不出效果。

centos一般都自带有 siege压测工具,还比较好用:
yum -y install siege

使用方法:
siege -c 3 -r 10 -b https://xxxx.xx.com/api/xxxx
-c 3 表示3个用户
-r 10 表示访问10次
以上表示:3个用户,每个用户访问10次请求,共计30次

经测试,每增加一台nginx,相同的配置应该是 x 2,例如:nginx1 的配置是 10+5,nginx2的配置也是10+5,域名部署在这两台nginx上,请求数最大允许为:20+10

以上测试,如果不能通过,应该是配置问题,那么我们用echo模块来调试下:

四、echo 模块
作者原文提到了 nginx 的一个 echo 模块,特意玩了下感觉挺有意思的,下面贴一下简单集成步骤。

①、给 nginx 集成 echo 模块:

cd /usr/local/src
#下载echo模块并解压:
wget https://github.com/openresty/echo-nginx-module/archive/v0.61.tar.gz
tar zxvf v0.61.tar.gz#下载nginx并解压
wget http://nginx.org/download/nginx-1.12.2.tar.gz
tar -xzvf nginx-1.12.2.tar.gz
cd nginx-1.12.2/#查看在用nginx的编译参数(如果是全新安装则省略)
/usr/local/nginx/sbin/nginx -V
nginx version: nginx/1.12.2
built by gcc 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC) #以下这行即为旧的编译参数:
configure arguments: --user=www --group=www --prefix=/usr/local/nginx --with-http_gzip_static_module
#在旧的编译参数基础上新增【--add-module=/echo模块的解压路径】参数,开始编译
./configure --prefix=/usr/local/nginx/nginx  --add-module=/usr/local/src/echo-nginx-module-0.61#make编译
make -j2#平滑升级nginx (如果是全新安装请执行:make install)
mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.old
cp -f objs/nginx /usr/local/nginx/sbin/
make upgrade

以上升级、编译和添加第三方模块不熟悉的朋友,可以参考我另外一篇博客:
https://mp.csdn.net/mdeditor/81136273

②、echo 用法举例:
其实就和 shell 的 echo 差不多,能否输出自定义信息。

比如,在 nginx 里面配置如下:

location /hello {echo "hello, world!";
}

访问 http://xxx.com/hello 就会在浏览器里面输出 hello, world! 了(如果域名开了 CDN 可能会报 404)。

又比如,测试本文提到的真实用户的 IP,只要在本文第二步配置基础上,加上如下规则并 reload 即可:

server {listen   80;server_name  yourdomain.com;## 以下是新增规则:## 当用户访问 /ip 的时候,我们输出 $clientRealIp 和 $limit变量,看看这个变量## 值是不是真的 用户源IP 地址location /ip{echo $clientRealIp;echo $limit;}
}

认真看的朋友,会问 clientRealIp 和 limit 有什么区别:
clientRealIp 如果走 SLB/CDN,获取的就是真实IP,反之,获取的就是remote_addr

limit 是在clientRealIp的基础上,排除了“IP白名单”,也就是说,当你的源IP,是白名单时,你的limit,应该为“空”,这样就不受限流了

所以,我们可以以此来判断,IP白名单是否有效:
curl http://xxx.xxx.cn/ip
这里写图片描述

本文介绍到这就差不多结束了,也是在神作的基础上精简整理并测试的,如果看完还有些许疑问,请前往查看神作原文,也许还是大神写的比较好理解(是否是原创我就不深究了,感觉也是转来转去,都没留链接,悲哀的互联网)!

转载:https://zhangge.net/4879.html

这篇关于nginx在CDN加速或使用SLB代理后,获取真实IP,做并发访问限制的方法(限流)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/250924

相关文章

Nginx 配置跨域的实现及常见问题解决

《Nginx配置跨域的实现及常见问题解决》本文主要介绍了Nginx配置跨域的实现及常见问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来... 目录1. 跨域1.1 同源策略1.2 跨域资源共享(CORS)2. Nginx 配置跨域的场景2.1

python使用库爬取m3u8文件的示例

《python使用库爬取m3u8文件的示例》本文主要介绍了python使用库爬取m3u8文件的示例,可以使用requests、m3u8、ffmpeg等库,实现获取、解析、下载视频片段并合并等步骤,具有... 目录一、准备工作二、获取m3u8文件内容三、解析m3u8文件四、下载视频片段五、合并视频片段六、错误

Python中提取文件名扩展名的多种方法实现

《Python中提取文件名扩展名的多种方法实现》在Python编程中,经常会遇到需要从文件名中提取扩展名的场景,Python提供了多种方法来实现这一功能,不同方法适用于不同的场景和需求,包括os.pa... 目录技术背景实现步骤方法一:使用os.path.splitext方法二:使用pathlib模块方法三

Python打印对象所有属性和值的方法小结

《Python打印对象所有属性和值的方法小结》在Python开发过程中,调试代码时经常需要查看对象的当前状态,也就是对象的所有属性和对应的值,然而,Python并没有像PHP的print_r那样直接提... 目录python中打印对象所有属性和值的方法实现步骤1. 使用vars()和pprint()2. 使

CSS实现元素撑满剩余空间的五种方法

《CSS实现元素撑满剩余空间的五种方法》在日常开发中,我们经常需要让某个元素占据容器的剩余空间,本文将介绍5种不同的方法来实现这个需求,并分析各种方法的优缺点,感兴趣的朋友一起看看吧... css实现元素撑满剩余空间的5种方法 在日常开发中,我们经常需要让某个元素占据容器的剩余空间。这是一个常见的布局需求

gitlab安装及邮箱配置和常用使用方式

《gitlab安装及邮箱配置和常用使用方式》:本文主要介绍gitlab安装及邮箱配置和常用使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1.安装GitLab2.配置GitLab邮件服务3.GitLab的账号注册邮箱验证及其分组4.gitlab分支和标签的

SpringBoot3应用中集成和使用Spring Retry的实践记录

《SpringBoot3应用中集成和使用SpringRetry的实践记录》SpringRetry为SpringBoot3提供重试机制,支持注解和编程式两种方式,可配置重试策略与监听器,适用于临时性故... 目录1. 简介2. 环境准备3. 使用方式3.1 注解方式 基础使用自定义重试策略失败恢复机制注意事项

nginx启动命令和默认配置文件的使用

《nginx启动命令和默认配置文件的使用》:本文主要介绍nginx启动命令和默认配置文件的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录常见命令nginx.conf配置文件location匹配规则图片服务器总结常见命令# 默认配置文件启动./nginx

在Windows上使用qemu安装ubuntu24.04服务器的详细指南

《在Windows上使用qemu安装ubuntu24.04服务器的详细指南》本文介绍了在Windows上使用QEMU安装Ubuntu24.04的全流程:安装QEMU、准备ISO镜像、创建虚拟磁盘、配置... 目录1. 安装QEMU环境2. 准备Ubuntu 24.04镜像3. 启动QEMU安装Ubuntu4

使用Python和OpenCV库实现实时颜色识别系统

《使用Python和OpenCV库实现实时颜色识别系统》:本文主要介绍使用Python和OpenCV库实现的实时颜色识别系统,这个系统能够通过摄像头捕捉视频流,并在视频中指定区域内识别主要颜色(红... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间详解