LOGO 首页 OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 技术文档 其他文档  
 
网站管理员

别让你的Nginx裸奔!生产环境下的访问控制实战,全是填坑经验

admin
2026年4月21日 7:30 本文热度 41


咱们搞运维的,Nginx那是吃饭的家伙,平时大家可能更多关注的是负载均衡、反向代理,或者怎么调优性能。但说句掏心窝子的话,安全这东西,平时不出事你觉得它多余,一出事那就是“救命稻草”。今天咱们不整那些虚头巴脑的理论,直接上生产环境的实战,聊聊Nginx访问控制那些事儿。这些配置都是我在无数次填坑过程中总结下来的,希望能给大伙提个醒,别让你的服务器在互联网上“裸奔”。

咱们先从最简单的说起,很多人觉得访问控制不就是设个密码,或者封个IP嘛。其实没那么简单。

拒绝不速之客:基于IP的访问控制

这应该是最直接的手段了。就像咱们小区的门禁,只让业主进,外人一律挡在门外。Nginx里的allowdeny指令就是干这个活的。这俩模块是ngx_http_access_module自带的,默认就装了,不用你去折腾编译安装。

我记得有一次,公司有个内部管理系统,原本是挂在内网域名下的,结果开发哥们为了方便测试,临时挂到了公网,也没做任何限制。结果没过两天,就被安全扫描器扫到了,虽然没出大事故,但那个报警邮件看得我后背发凉。后来我就给所有的内部后台都加上了IP白名单。

配置起来其实特简单,打开你的nginx.conf或者对应的站点配置文件,在server块或者location块里加上几行就行:

location /admin/ {
    allow
 192.168.1.0/24;  # 允许内网网段
    allow
 10.0.0.1;        # 允许某个特定的跳板机
    deny
 all;              # 拒绝其他所有人
}

这里有个小细节,很多人容易踩坑。Nginx匹配规则是从上往下匹配,一旦匹配成功就停止。所以顺序千万不能乱。你要是把deny all写在第一行,那后面所有的allow都白搭,谁都进不去,这叫“误伤友军”。我就干过这种傻事,配置完 reload 了一下,结果把自己关在外面了,只能灰溜溜地去机房连控制台改配置,那场面,别提多尴尬了。

还有个事儿得注意,如果你用了CDN,比如阿里云CDN或者Cloudflare,那你在这个allow里配置的IP可能就不是用户的真实IP了,而是CDN节点的IP。这时候你得先用set_real_ip_from把CDN的IP段设置一下,用X-Forwarded-For或者X-Real-IP头来获取真实用户IP,然后再做限制。不然你限制了个寂寞,或者把正常用户给封了。

给目录加把锁:基于用户的认证

有时候,我们需要给某个测试环境、或者某个临时的API接口加个密码,不想让随便什么人都能访问。这时候IP限制就不太灵活了,比如出差在外,IP是动态的,咋办?这时候就得请出ngx_http_auth_basic_module模块了。

这玩意儿就像给目录加了一把锁,只有输入对了用户名和密码才能进。

配置分两步走。第一步,得先有个密码文件。别想着自己去手写加密密码,Linux底下有现成的工具,Apache的htpasswd工具最方便。一般服务器装了Apache或者httpd-tools就有。没有的话装一下:

yum install httpd-tools -y

然后生成密码文件,比如我们建个/etc/nginx/.htpasswd文件,添加一个叫pyy的用户:

htpasswd -c /etc/nginx/.htpasswd pyy

回车后它会让你输入两次密码。注意那个-c参数是create的意思,如果你是第一次创建文件用-c,如果是追加用户,千万别带-c,不然原来的文件会被覆盖掉,我就因为这个被同事投诉过,把他们的账号给弄丢了。

文件有了,接下来就是Nginx配置:

location /test/ {
    auth_basic
 "Restricted Area";  # 这个是提示信息,随便写
    auth_basic_user_file
 /etc/nginx/.htpasswd;
}

配置完nginx -t测试一下,没问题就nginx -s reload。这时候你再去访问那个目录,浏览器就会弹出一个原生的登录框,丑是丑了点,但胜在实用。

这个功能在临时分享一些敏感数据,或者保护还没上线的功能时特别好用。不过要注意,这个Basic认证是Base64编码传输的,安全性并不是特别高,如果不配合HTTPS,密码其实相当于明文传输,抓个包就能看见。所以,能上HTTPS尽量上HTTPS。

更高级的玩法:结合GeoIP做地域封禁

有时候我们不仅想封IP,还想封地区。比如公司的业务只在国内开展,但是每天日志里全是来自大洋彼岸的扫描攻击,看着都烦。这时候就可以用GeoIP模块。

现在的Nginx默认应该都支持ngx_http_geoip_module,如果不支持,那你可能得重新编译安装一下,带上--with-http_geoip_module参数。不过现在很多都是动态加载模块,看情况而定。

首先你得下载GeoIP的数据库文件。以前MaxMind提供免费的GeoLiteCountry,现在虽然收费了,但GeoLite2还是能用的,就是得注册个账号下载。下载解压后,放到服务器某个目录下,比如/usr/share/GeoIP/

配置文件里这么写:

http {
    # 加载数据库文件

    geoip_country
 /usr/share/GeoIP/GeoLite2-Country.mmdb;

    # 定义一个变量,判断是否允许访问

    # 这里假设我们只允许中国(代码CN)访问

    map
 $geoip_country_code $allowed_country {
        default
 no;
        CN
 yes;
    }

    server
 {
        location
 / {
            if
 ($allowed_country = no) {
                return
 403 "Service not available in your region.";
            }
            # 其他配置...

        }
    }
}

这招在应对某些特定地域的攻击时特别有效。之前有个客户,是个本地生活服务的APP,只做本地生意,我直接给他配置了只允许本地IP段访问,外加GeoIP过滤,日志瞬间干净了,CPU负载都降了好几个点。

不过这玩意儿也有坑。那个GeoIP数据库不是实时更新的,IP库这东西变动很频繁,偶尔会有误杀的情况。比如有些用户用了国外的代理,或者IP库定位不准,就会被挡在外面。所以配置完,一定要留好监控,看看有没有大量的403报错,或者给个友好的提示页面,别让用户以为网站挂了。

防止恶意刷接口:请求频率限制

刚才说的都是怎么控制“谁能进”,接下来咱们聊聊怎么控制“怎么进”。这就是限流,也是访问控制的重要一环。

如果你的接口被人家用脚本狂刷,或者有人恶意CC攻击,你的服务器资源瞬间就会被耗尽。Nginx的ngx_http_limit_req_module模块就是专门干这个的。它用的是“漏桶算法”,不管你发请求多快,到了我这儿都得按规矩排队漏下去。

配置分两块。第一块在http块里定义限流规则:

http {
    # 定义一个叫 my_limit 的限流区域

    # $binary_remote_addr 是根据客户端IP来限制

    # zone=my_limit:10m 定义区域名字和共享内存大小,10M大概能存16万个IP状态

    # rate=10r/s 表示每秒允许10个请求

    limit_req_zone
 $binary_remote_addr zone=my_limit:10m rate=10r/s;
}

然后在server或者location里应用这个规则:

location /api/ {
    # burst=20 允许突发流量,也就是短时间内可以多来20个请求排队

    # nodelay 超过burst限制直接拒绝,不进行延迟处理

    limit_req
 zone=my_limit burst=20 nodelay;
  
    # 被限制时返回的状态码,默认是503,我们可以改成429 Too Many Requests

    limit_req_status
 429;
  
    proxy_pass
 http://backend;
}

这里的burstnodelay参数特别有讲究。如果不加burst,请求非常平滑,每秒严格控制在10个,多一个都不行,用户体验可能不太好,感觉网站一卡一卡的。加了burst=20,就像给桶扩容了,瞬间来30个请求,前10个正常处理,后20个排队。但是如果不加nodelay,那排队的20个请求处理起来会很慢,因为要按rate的速度漏出去。加了nodelay,就是排队的那20个请求也会立马转发给后端,但是桶里的“令牌”用光了,再来请求就直接拒绝。

这块参数怎么调,得看你的业务。如果是秒杀场景,burst设大点,nodelay必须加,保证瞬时并发。如果是普通的API,设小点,保护后端。

我有次把burst设得太小,结果公司搞营销活动,流量稍微一上来,全是503报错,被运营妹子追着问是不是服务器炸了。所以说,这玩意儿得压测,得根据实际情况慢慢调优。

神奇的Nginx变量与Map指令

有些时候,我们的需求比较变态。比如,我想封禁所有User-Agent里包含"Java"或者"Python"字样的请求,防止爬虫;或者我想只允许特定URL带特定参数的请求。这时候if指令就派上用场了。

虽然网上都说if is evil,但在location里做些简单的判断还是挺好用的。

比如封杀特定UA:

location / {
    # $http_user_agent 代表请求头里的User-Agent

    if
 ($http_user_agent ~* (python|curl|java|wget)) {
        return
 403;
    }
}

这招对付那些不伪装UA的简单爬虫一抓一个准。

再高级点的,比如我们想根据请求参数做白名单。有个接口,只有带着特定token参数的请求才能访问。这时候可以用map指令,这可是个好东西,能帮我们减少很多if判断,让配置更清爽。

http {
    # $arg_token 就是url里的token参数

    map
 $arg_token $is_allowed {
        default
       0;
        "my_secret_key" 1;
    }
  
    server
 {
        location
 /private_api/ {
            if
 ($is_allowed = 0) {
                return
 403;
            }
            proxy_pass
 http://backend;
        }
    }
}

这样配置,只有当URL是/private_api/?token=my_secret_key时,$is_allowed才是1,否则都是0,直接403。这比写一堆正则匹配要清晰得多,性能也更好。

还有个大杀器:auth_request

最后再提一个比较高级的功能,ngx_http_auth_request_module。这个模块允许你把认证逻辑委托给一个外部服务。

啥意思呢?比如你们公司有个统一的SSO登录中心,或者有个专门的鉴权微服务。你不想在Nginx里维护复杂的密码文件,也不想写Lua脚本去连数据库。那就可以用这个。

配置大概是这样的:

location /private/ {
    auth_request
 /auth;
    # 这里的 /auth 是一个内部location

    error_page
 401 = @error401;
  
    proxy_pass
 http://backend_service;
}

location
 = /auth {
    internal;  # internal表示这个location只能内部重定向访问,外部直接访问404
    proxy_pass
 http://auth_service/validate;
    proxy_pass_request_body
 off; # 不转发请求体,只转发头
    proxy_set_header
 Content-Length "";
    proxy_set_header
 X-Original-URI $request_uri;
}

流程是这样的:用户访问/private/,Nginx会先偷偷发一个子请求到/auth,也就是你的鉴权服务。如果鉴权服务返回200,Nginx就继续把请求转发给后端;如果返回401或403,Nginx就直接拦截。

这个玩法扩展性极强。你可以把IP黑白名单、用户Token校验、甚至复杂的权限逻辑都放在那个auth_service里去写,用什么语言都行,只要返回特定的HTTP状态码就行。Nginx只负责挡在前面做调度。这在微服务架构里特别常见,实现了业务逻辑和网关配置的解耦。

填坑总结

写了这么多,其实Nginx的访问控制无非就是“你是谁”、“你从哪来”、“你要干什么”这三个问题。

我们在生产环境落地的时候,往往不是单一使用某一种手段,而是组合拳。比如,先封禁恶意UA,再限制IP地域,然后对关键接口做频率限制,最后对后台管理页面做IP白名单+密码认证。

还有几个小坑大家注意一下:

  1. 1. 配置完一定要测试nginx -t是保命符,但有时候语法对不代表逻辑对,最好有个测试环境先验证。
  2. 2. 日志是关键:不管你配置得多么完美,总会有漏网之鱼或者误杀。一定要盯着日志看,特别是配置变更后的那段时间。
  3. 3. 版本差异:Nginx版本更新挺快,有些模块的指令在不同版本下可能有细微差别,遇到报错多看官方文档,别光百度。

运维这活儿,就是要在便利性和安全性之间找平衡。锁得太死,业务跑不起来;放得太宽,半夜起来救火。咱们能做的,就是尽量把墙筑得高一点,门留得合适一点。

今天的分享就到这儿吧,希望能给大家在Nginx安全加固方面提供点思路。这些都是我平时一点一点攒下来的经验,不一定是最完美的,但绝对是实战中能用得上的。


阅读原文:原文链接


该文章在 2026/4/21 10:17:05 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2026 ClickSun All Rights Reserved  粤ICP备13012886号-2  粤公网安备44030602007207号