【案例篇】为什么设置了 ulimit 但 nofile 限制仍不生效?

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模块负责管理用户登录时的资源限制,进行如下检查:

  1. 查看/etc/security/limits.conf文件,发现对所有用户的文件描述符限制配置为:
* hard nofile 655350
* soft nofile 655350

配置正确且未被修改

  1. 检查/etc/security/limits.d/目录下的自定义配置文件,未发现异常设置

PAM模块配置正常,排除该因素影响

(二)切入重点,分析 sshd 服务配置

考虑到用户是通过ssh登录后,nofile 数量减少的,所以重点排查与sshd服务相关的配置:

查看sshd进程的limit
[root@ ~]# systemctl status sshd
● sshd.service - OpenSSH server daemon
   Loaded: 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 ago
     Docs: man:sshd(8)
           man:sshd_config(5)
 Main PID: 6855 (sshd)
    Tasks: 6
   Memory: 34.6M
   CGroup: /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限制的原因
  1. 首先想到的是查看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:影响系统服务(如 sshdnginx 等)
  • user.conf:影响用户会话(如通过 SSH 登录的用户进程)

默认配置中通常包含以下参数:

[Manager]
DefaultLimitNOFILE=1024:4096  # 格式为 "软限制:硬限制"

当 system.conf 中 DefaultLimitNOFILE 被注释时,systemd 会使用其内置编译时默认值,而非系统传统的 /etc/security/limits.conf 配置(除非显式继承)。

验证方式:通过 systemctl show --property=DefaultLimitNOFILE 查看 systemd 实际生效的全局默认值,例如:

systemctl show --property=DefaultLimitNOFILE
输出示例:DefaultLimitNOFILE=1024:4096

2. systemd服务特定限制

每个 systemd 服务单元(.service 文件)可通过 LimitNOFILE 参数覆盖全局默认值:

[Service]
LimitNOFILE=65535  # 同时设置软限制和硬限制为 65535
# 或分别设置:LimitNOFILE=soft_limit:hard_limit
查看systemd配置

有了理论依据,我们查看下这台服务器的配置。果然是systemd/system.conf的全局配置影响了,结果和sshd查看的一样。
在这里插入图片描述

四、解决方案

(一)修改systemd配置

为恢复正常的文件描述符限制,进行如下操作:

  1. 编辑/etc/systemd/system.conf文件,将DefaultLimitNOFILE修改为:
DefaultLimitNOFILE=65536
  1. 重新加载systemd配置:
sudo systemctl daemon-reload

(二)验证修复效果

  1. 重启sshd服务:
sudo systemctl restart sshd

在这里插入图片描述

  1. 通过SSH重新登录服务器,执行ulimit -n,显示值恢复为65536,与本地控制台结果一致

在这里插入图片描述

五、经验总结

  1. 系统性排查:遇到资源限制类问题时,应从用户配置、PAM模块、服务管理工具systemd等多个层面进行系统性排查。
  2. 查看服务的 nofile 限制
systemctl show nginx.service | grep LimitNOFILE
# 输出示例:LimitNOFILE=65535:65535
  1. 检查运行中进程的限制
cat /proc/PID/limits | grep "Max open files"
# 输出示例:Max open files            65535                65535                files
  1. 优先级规则 systemd 的限制配置遵循 特定 > 全局 的优先级:
  • 服务单元文件(如 /lib/systemd/system/nginx.service)中的 LimitNOFILE
  • 服务覆盖文件(如 /etc/systemd/system/nginx.service.d/override.conf)中的 LimitNOFILE
  • /etc/systemd/system.conf 中的 DefaultLimitNOFILE
  • 系统默认值(通常为 1024:4096)
<think> 我们正在解决ulimit命令不生效的问题。用户可能已经尝试过使用`ulimit -s unlimited`或者修改了.bashrc文件,但发现限制并未改变。我们需要系统地分析原因并提供解决方案。 常见原因: 1. 系统安全策略限制(如/etc/security/limits.conf配置) 2. 用户权限不足(非root用户可能无法提高硬限制) 3. 修改的配置文件不正确(如修改了.bashrc但实际使用的是其他shell) 4. 配置未重新加载(需要source或重新登录) 5. 应用程序在子shell中运行(如通过脚本启动,且脚本未设置ulimit) 解决步骤: 1. 检查当前shell的ulimit设置 2. 检查系统全局限制配置文件 3. 检查用户级配置文件(如.bashrc, .profile等)是否配置正确 4. 检查是否在脚本中运行,脚本是否设置ulimit 5. 尝试以root用户修改系统级限制 注意:ulimit的修改分为硬限制和软限制。普通用户只能降低硬限制,提高硬限制需要root权限;而软限制可以提高到不超过硬限制。 详细步骤: </think> ### 一、ulimit命令不生效的核心原因分析 1. **权限不足** 普通用户无法突破系统的硬性限制(hard limit),修改需root权限[^1]。 2. **配置位置错误** 修改了无效的shell配置文件(如误改`.bashrc`但实际使用zsh)。 3. **作用域限制** ulimit仅作用于当前shell进程及其子进程,后台服务或GUI应用需独立配置[^2]。 4. **系统策略限制** `/etc/security/limits.conf`中的全局策略会覆盖用户级设置: ```bash $ cat /etc/security/limits.conf # 可能包含: # * hard stack 8192 ``` --- ### 二、系统级解决方案 #### ✅ 方案1:提升权限修改硬限制 ```bash # 切换到root用户 sudo su - # 查看当前硬限制 ulimit -Hs # 临时提高栈限制 ulimit -Hs unlimited # 永久修改(需编辑系统文件) echo "root hard stack unlimited" >> /etc/security/limits.conf ``` #### ✅ 方案2:修复配置文件路径 根据不同shell选择正确配置文件: | Shell类型 | 配置文件 | 修改命令 | |-----------|-------------------|------------------------------| | Bash | `~/.bashrc` | `echo "ulimit -s unlimited" >> ~/.bashrc` | | Zsh | `~/.zshrc` | `echo "ulimit -s unlimited" >> ~/.zshrc` | | 系统全局 | `/etc/profile` | 需root权限编辑 | #### ✅ 方案3:系统服务独立配置 对systemd服务(如docker/nginx),创建覆盖配置: ```ini # /etc/systemd/system/<服务名>.service.d/override.conf [Service] LimitSTACK=infinity # 关键参数 LimitCORE=infinity ``` 重载服务: ```bash sudo systemctl daemon-reload sudo systemctl restart <服务名> ``` #### ✅ 方案4:绕过系统限制 对需大栈空间的程序(如`urg-full64`),使用`prlimit`工具: ```bash prlimit --stack=unlimited -- <命令> # 示例 prlimit --stack=unlimited -- urg -full64 -dir cov_db ``` --- ### 三、验证与排查流程 1. **验证配置加载** ```bash # 查看当前栈大小(单位KB) ulimit -s # 检查生效的配置文件 grep "ulimit" ~/.*rc /etc/profile /etc/bash.bashrc ``` 2. **层级权限测试** ```mermaid graph LR A[普通用户] -->|ulimit -s unlimited| B{报错?} B -->|是| C[尝试sudo临时修改] C --> D[成功?] D -->|是| E[需root永久配置] D -->|否| F[检查/etc/security/limits.conf] ``` 3. **系统策略检测** ```bash # 检查全局限制策略 sudo grep -r "stack" /etc/security/ # 检查内核强制限制 cat /proc/sys/kernel/threads-max ``` --- ### 四、终极解决方案 当所有方法失效时,直接修改内核参数: ```bash # 编辑/etc/sysctl.conf sudo nano /etc/sysctl.conf # 增加: kernel.threads-max=unlimited vm.max_map_count=268435456 # 立即生效 sudo sysctl -p ``` > ⚠️ 此操作需重启系统,可能影响系统稳定性[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值