根本原因是系统级限制未同步更新,必须三处协同:systemd的LimitNOFILE、/etc/security/limits.conf中对应用户的软硬限制、nginx.conf中main上下文的worker_rlimit_nofile(≤硬限制),且必须restart而非reload才能生效。

worker_rlimit_nofile 配置重启后失效,根本原因不是 Nginx 写错了,而是它启动时从操作系统继承的文件描述符限制没变——配置本身生效了,但被系统级限制“卡住”了。要真正持久化,必须让 Nginx 进程每次启动都拿到你想要的上限值,这需要三处同步落地,缺一不可。
确保 systemd 服务限制持久生效
现代 Linux(如 Ubuntu 22.04+、CentOS 8+)普遍用 systemd 管理 Nginx,而 systemd 默认不读取 /etc/security/limits.conf。只改 limits 文件,对 systemctl 启动的 Nginx 完全无效。
- 创建覆盖配置:/etc/systemd/system/nginx.service.d/override.conf,内容为:
[Service] LimitNOFILE=131072
- 执行 systemctl daemon-reload 重载配置定义
- 执行 systemctl restart nginx —— 注意必须是 restart,reload 不会重置进程资源限制
- 验证:运行 systemctl show nginx | grep LimitNOFILE,输出应为 LimitNOFILE=131072
补充 /etc/security/limits.conf 防止边界场景失效
虽然 systemd 主导,但在某些场景下仍可能回退到 PAM 机制,比如手动用 nginx 用户执行调试命令、或某些容器/CI 环境。补上 limits 是兜底做法。
- 确认 Nginx 实际运行用户(常见为 www-data 或 nginx):ps -eo pid,comm,user | grep "nginx: master"
- 在 /etc/security/limits.conf 末尾添加两行(用户名按实际替换):
www-data soft nofile 131072 www-data hard nofile 131072
- 确认 /etc/pam.d/common-session 包含:session required pam_limits.so
- 该配置对新登录会话生效,但不影响已运行服务;所以它不替代 systemd 配置,而是增强兼容性
在 nginx.conf 中正确声明并验证落地
worker_rlimit_nofile 必须写在 main 上下文,且数值不能超过系统硬限制,否则静默降级或启动失败。
- 打开 /etc/nginx/nginx.conf,在 events 块之前、http 块之外的最外层添加:
worker_rlimit_nofile 131072;
- 重启后立刻验证是否真生效:cat /proc/$(pgrep -f "nginx: worker" | head -n1)/limits | grep "Max open files"
- 输出中 Soft Limit 必须等于 131072,Hard Limit ≥ 131072 —— 这是唯一可信依据,别只看配置文件
- 若 Soft Limit 仍是 1024 或 65536,说明 systemd 或 limits 没生效,需回头排查
避免 reload 导致的“假生效”错觉
很多人改完配置执行 nginx -s reload,发现日志没报错就以为成功了。但 reload 只重启 worker 进程,不重建进程资源限制——它沿用 master 进程启动时继承的旧 ulimit。
- 所有涉及 worker_rlimit_nofile、user、worker_processes 的变更,都必须用 systemctl restart nginx(或 service nginx restart)
- master 进程退出再启动,才会重新从 systemd 或 shell 环境读取新的 LimitNOFILE 或 ulimit 值
- 把 restart 当作标准操作,不要依赖 reload 来“热更新”资源类配置

















