【案例篇】为什么设置了 ulimit 但 nofile 限制仍不生效?
目录
- OpenSSH升级后ulimit -n值变小的排查与解决案例
- 一、问题背景
- 二、问题现象
- 三、排查过程
- (一)核查PAM模块配置
- (二)切入重点,分析 sshd 服务配置
- 查看sshd进程的limit
- 分析sshd服务limit限制的原因
- 峰回路转,真相往往需要敏锐的👀
- (三)找到1024的真相,1024是哪里配置的呢
- 1. systemd全局默认限制
- 2. systemd服务特定限制
- 查看systemd配置
- 四、解决方案
- (一)修改systemd配置
- (二)验证修复效果
- 五、经验总结
OpenSSH升级后ulimit -n值变小的排查与解决案例
一、问题背景
分享一个运维工作中有趣的案例。
按照安全部的要求,需要修复服务器主机OpenSSH安全漏洞,将测试开发环境中所有Linux服务器的OpenSSH从8.0p1版本升级至9.9p2。升级完成后,运维人员在日常巡检中发现,通过SSH登录服务器后执行ulimit -n
命令,返回的可打开文件描述符上限值从原来的655350下降到1024。 这是什么原因引起的呢?
二、问题现象
如下图: root用户通过ssh登录后,查看ulimit -n
同样的虚拟机,通过云管理控制台界面登录root用户,再执行ulimit -n
后结果如下
)
同样的用户,登录方式不一样,ulimit -n 的结果差别这么大?
三、排查过程
(一)核查PAM模块配置
由于PAM模块负责管理用户登录时的资源限制,进行如下检查:
- 查看
/etc/security/limits.conf
文件,发现对所有用户的文件描述符限制配置为:
* hard nofile 655350
* soft nofile 655350
配置正确且未被修改
- 检查
/etc/security/limits.d/
目录下的自定义配置文件,未发现异常设置
PAM模块配置正常,排除该因素影响
(二)切入重点,分析 sshd 服务配置
考虑到用户是通过ssh登录后,nofile 数量减少的,所以重点排查与sshd服务相关的配置:
查看sshd进程的limit
[root@ ~]# systemctl status sshd
● sshd.service - OpenSSH server daemonLoaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)Active: active (running) since Fri 2025-06-06 19:04:19 CST; 2 days agoDocs: man:sshd(8)man:sshd_config(5)Main PID: 6855 (sshd)Tasks: 6Memory: 34.6MCGroup: /system.slice/sshd.service├─ 6855 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups├─14700 sshd-session: root [priv]├─14702 sshd-session: root@pts/0├─14703 -bash├─14825 systemctl status sshd└─14826 less
执行systemctl status sshd,获得Main PID为 6855。
那么如何查看进程的limit的状态呢,可以通过/proc
如上图:sshd服务的进程nofile的Soft Limit就是1024
因为sshd服务本身的限制,所以通过sshd登录的用户也限制文件描述符大小是1024。
关于软限制和硬限制的说明,在我之前的文章: 被 ulimit 玩脱的那些血泪史 中有过介绍
- 软限制(soft):当前实际生效的限制,用户可通过 ulimit 命令自行调整(需不超过硬限制)。
- 硬限制(hard):软限制的上限,通常由系统管理员设置,普通用户无法超越。
分析sshd服务limit限制的原因
- 首先想到的是查看sshd服务的配置文件,其中最主要关注的配置就是“UsePAM”。
如上图所示,UsePAM配置是关闭的,而升级openssh之前这部分配置是开启的,当前的sshd服务因为没有开启UsePAM的功能,所以没有使得/etc/security/limits.conf 的配置生效 !
那似乎解决方法已经很清楚了,我们可以把UsePAM 改成 yes,然后重启下sshd服务。说干就干!
现在/etc/ssh/sshd_config 文件已修改,也执行了systemctl restart sshd,然后我们重新ssh登录服务器,看看效果。
哎哎哎,这不对啊,明明已经开启了PAM模块了啊,咋还是1024呢,这不合理啊!
峰回路转,真相往往需要敏锐的👀
其实分析到这里,我也没有头绪了,但是越到这里,越要抓住重点,既然就是sshd服务的问题,那刚才我们重启了sshd服务,我们是不是要检查下,刚才的操作是否生效呢,对了,查询下sshd服务的状态和日志。
果然,大家也可以看到,sshd在启动过程中竟然报了一个语法错误。
Starting sshd:/etc/ssh/sshd_config line 82: Unsupported option UsePAM
# 通过sshd -t 命令也可以同样发现这个报错。
[root@a ~]# sshd -t
/etc/ssh/sshd_config line 82: Unsupported option UsePAM
这个报错通过查询一些资料,这个报错多半是openssh的编译过程参数少了–with-pam 参数,所以新升级的openssh服务,缺少pam的选项的内容。
(三)找到1024的真相,1024是哪里配置的呢
现在我们已经知道了,因为sshd服务,编译的时候就没有带上–with-pam 参数,同时呢没有开启UsePAM yes 的配置。所以没有使得/etc/security/limits.conf 的配置生效 !
那现在问题来了,为什么当前ssh登录的用户的nofile 就是1024呢。这个1024是哪里配置的呢?
在现代 Linux 系统中,systemd 作为初始化系统和服务管理器,会对进程的 nofile(文件描述符限制)产生多方面影响。
1. systemd全局默认限制
systemd
为所有服务和进程设置了默认的 nofile
限制,该限制由 /etc/systemd/system.conf
和 /etc/systemd/user.conf
控制:
system.conf
:影响系统服务(如sshd
、nginx
等)user.conf
:影响用户会话(如通过 SSH 登录的用户进程)
默认配置中通常包含以下参数:
[Manager]
DefaultLimitNOFILE=1024:4096 # 格式为 "软限制:硬限制"
2. systemd服务特定限制
每个 systemd
服务单元(.service
文件)可通过 LimitNOFILE
参数覆盖全局默认值:
[Service]
LimitNOFILE=65535 # 同时设置软限制和硬限制为 65535
# 或分别设置:LimitNOFILE=soft_limit:hard_limit
查看systemd配置
有了理论依据,我们查看下这台服务器的配置。果然是systemd/system.conf的全局配置影响了,结果和sshd查看的一样。
四、解决方案
(一)修改systemd配置
为恢复正常的文件描述符限制,进行如下操作:
- 编辑
/etc/systemd/system.conf
文件,将DefaultLimitNOFILE
修改为:
DefaultLimitNOFILE=65536
- 重新加载systemd配置:
sudo systemctl daemon-reload
(二)验证修复效果
- 重启
sshd
服务:
sudo systemctl restart sshd
- 通过SSH重新登录服务器,执行
ulimit -n
,显示值恢复为65536,与本地控制台结果一致
五、经验总结
- 系统性排查:遇到资源限制类问题时,应从用户配置、PAM模块、服务管理工具systemd等多个层面进行系统性排查。
- 查看服务的 nofile 限制
systemctl show nginx.service | grep LimitNOFILE
# 输出示例:LimitNOFILE=65535:65535
- 检查运行中进程的限制
cat /proc/PID/limits | grep "Max open files"
# 输出示例:Max open files 65535 65535 files
- 优先级规则 systemd 的限制配置遵循 特定 > 全局 的优先级:
- 服务单元文件(如 /lib/systemd/system/nginx.service)中的 LimitNOFILE
- 服务覆盖文件(如 /etc/systemd/system/nginx.service.d/override.conf)中的 LimitNOFILE
- /etc/systemd/system.conf 中的 DefaultLimitNOFILE
- 系统默认值(通常为 1024:4096)