openresty geo实战:怎么让nginx按IP归属地精准拦截或放行流量

openresty geo实战:怎么让nginx按IP归属地精准拦截或放行流量

本文关键词:openresty geo

前阵子帮朋友搭了个内网测试环境,他非要在外面挂个公网IP,结果没两天就被爬虫爬疯了,服务器CPU直接飙到90%。这哥们急得团团转,问我咋办。我说你这没做地域限制啊,人家一看你是国内IP就疯狂请求,国外IP反而没动静。咱得用openresty geo模块搞一下,按IP归属地来分流或者拦截,这才是正经路子。

很多人一听到“geo”就头大,觉得要搞什么复杂的数据库或者API接口。其实真没必要,对于大多数中小项目,直接用openresty自带的geo模块就够了。它不依赖外部服务,解析速度极快,内存占用也低。我一般习惯在nginx.conf或者单独建个geo.conf文件里写规则,这样管理起来清爽,不至于把主配置文件搞得一团糟。

先说个最基础的场景:我想屏蔽某些特定地区的恶意流量。比如最近某几个省份的僵尸网络特别多,我就想在openresty geo里把它们标记出来。写法其实挺直观的,就像这样:

geo $bad_ip {

default 0;

1.2.3.0/24 1;

5.6.7.0/24 1;

}

这里的意思很简单,如果请求的IP匹配后面那些网段,$bad_ip变量就是1,否则是0。然后我在location块里加个判断:

if ($bad_ip) {

return 403;

}

就这么几行代码,那些恶意请求直接就被拒之门外了。注意啊,if指令在nginx里是个坑,别乱用,但在做简单的拦截时,它确实是最快最省事的办法。不过得小心,别把正常用户也给误伤了,最好先拿日志测几天,看看命中率准不准。

再进阶一点,如果你想做地域白名单,只允许国内IP访问,那逻辑反一下就行。把默认值设为1,然后把你不想允许的国外IP段设为0。这时候openresty geo的优势就出来了,因为它是在内存里查表的,比去调API接口快太多了,几乎不增加请求延迟。

有个细节得提醒下,IP段别写太细。比如你写1.2.3.4/32,那这个IP就被封了,但如果是1.2.3.0/24,那就是整个C段都被封。一般建议用/24或者/16这种粒度,除非你特别确定某个IP有问题。另外,记得定期更新IP段库,因为IP分配是动态的,昨天的黑名单今天可能就失效了。

我还见过有人用openresty geo做简单的A/B测试,按地域分发不同内容。比如北京用户看首页A,上海用户看首页B。虽然这功能有点大材小用,但确实能实现。只要在geo块里定义不同变量,然后在proxy_pass或者rewrite里根据变量值跳转就行。不过这种玩法对业务逻辑要求高,容易出bug,新手慎玩。

最后说下排查问题。如果配完了发现没生效,先查nginx -t看语法对不对,再看error.log有没有报错。很多时候是因为变量名写错了,或者if判断的位置不对。openresty geo的变量作用域是server或者location级别,别搞混了。

总之,做流量控制,openresty geo是个神器。不用装插件,不用搞数据库,几行配置就能搞定大部分地域限制需求。关键是得根据实际情况灵活调整,别照搬网上的代码,每个业务场景都不一样。多试几次,你就能摸出门道了。

对了,配置完记得reload nginx,别直接restart,不然服务会断一下。小细节决定成败,这点经验我是真真切切踩坑换来的。希望这篇能帮到正在头疼IP管理的朋友。