要让 limit_conn 发挥真实防护效果,必须协同系统级文件描述符配置:先设 limits.conf 和 systemd 的 limitnofile、sysctl 的 fs.file-max;再配 nginx 的 worker_rlimit_nofile 和 worker_connections;最后定义 limit_conn_zone 并启用 limit_conn 规则,配合日志与状态码优化及三项验证。

要让 limit_conn 发挥真实防护效果,必须和系统级文件描述符(FD)配置协同生效。否则会出现“配了 1000 并发,实际连 200 都撑不住”的情况——根本原因是连接数被底层 FD 限制卡死了。
先确保系统允许足够多的文件描述符
nginx worker 进程能打开多少连接,直接受限于它运行时的 ulimit -n 值,而这个值由两层控制:
-
/etc/security/limits.conf:对用户或服务设软硬限制
例如添加:* soft nofile 65535* hard nofile 65535
注意:若 nginx 以 systemd 服务方式启动,还需在 service 文件中显式设置LimitNOFILE=65535 -
/etc/sysctl.conf:全局内核上限不能低于单进程需求
添加:fs.file-max = 2000000
执行sysctl -p生效
再在 nginx.conf 中正确配置 worker 级 FD 上限
仅改系统限制还不够,nginx 主进程必须把权限“传递”给 worker 进程:
- 在
nginx.conf的主块(main context)加:worker_rlimit_nofile 65535; - 该值不能超过上一步设置的
hard nofile,否则会被静默截断 - 同时在
events块中匹配设置:worker_connections 65535;
一个 worker 最大连接数 ≤ 其可用 FD 数(通常还要预留少量给日志、配置读取等)
最后定义并启用 limit_conn 规则
有了足够 FD,limit_conn 才能真正按需计数而不崩溃:
- 在
http块定义共享内存区(必须提前):limit_conn_zone $binary_remote_addr zone=perip:10m;
用$binary_remote_addr更省内存,10MB 可存约 16 万个 IP 状态 - 在
server或location中启用限制:limit_conn perip 100;
表示每个客户端 IP 最多维持 100 个并发 TCP 连接 - 建议搭配增强项提升实用性:
—limit_conn_log_level error;(避免限流日志刷屏)
—limit_conn_status 503;(明确返回状态码)
—keepalive_timeout 15;(及时释放空闲连接,避免占满配额)
验证是否真正生效
三项检查缺一不可:
- 运行
ulimit -Hn && ulimit -Sn查看 nginx worker 实际生效的 limits(可找一个 worker 进程 PID,读/proc/PID/limits) - 用
ss -s或netstat -an | grep :80 | wc -l观察当前 ESTABLISHED 连接数是否接近预期上限 - 触发限流后检查 access log 中
$limit和$limit_key字段,确认是哪个 key 被拦截、是否符合 zone 定义逻辑











