Linux SSH 会话频繁断开的排查方法

7次阅读

Linux SSH 会话频繁断开的排查方法

ssh 连接被服务端主动断开的典型表现

你执行命令到一半,终端突然卡住几秒后显示 Connection closed by remote host 或直接断连,且本地 ssh 进程退出。这不是网络抖动导致的临时丢包,而是服务端(sshd)主动终止了连接。

根本原因通常是服务端设置了空闲超时策略。OpenSSH 默认启用 ClientAliveIntervalClientAliveCountMax 机制:若客户端在指定时间内未发任何数据包,sshd 会发送探测包;连续几次无响应就 kill 掉该连接。

常见错误配置包括:

  • ClientAliveInterval 0(禁用探测)但搭配了 TCPKeepAlive no,导致内核无法感知链路异常
  • ClientAliveInterval 60ClientAliveCountMax 3,意味着最多 3 分钟无交互就会断连
  • MaxStartupsMaxsessions 被设得过低,高并发时新连接被拒绝或旧连接被踢出

如何确认是服务端配置导致的断连

登录服务器后检查 /etc/ssh/sshd_config 中的关键项,并比对当前生效值:

运行 sudo sshd -T | grep -E "(clientalive|tcpkeepalive|maxstart|maxsess)" 获取实际加载的配置(注意:此命令需 root 权限,且不校验语法,仅输出合并后的结果)。

重点关注以下字段是否被显式修改过:

  • ClientAliveInterval:非零值即启用保活探测,单位秒
  • ClientAliveCountMax:默认 3,表示允许连续丢失多少次探测响应
  • TCPKeepAlive:设为 yes 可让内核在传输层维持连接,但对 NAT 网关不友好
  • MaxStartups:如设为 10:30:60 表示最多 10 个未认证连接,超过后按概率丢弃

如果发现 ClientAliveInterval 是 60、120 或其他较小值,基本可锁定问题来源。

客户端侧快速绕过断连的实操方式

无需改服务器配置,也能稳定长连接。在本地 SSH 客户端加保活参数即可:

  • 临时使用:ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=3 user@host
  • 永久生效:编辑 ~/.ssh/config,加入对应 Host 块:
    Host myserver
    HostName 192.168.1.100
    User admin
    ServerAliveInterval 30
    ServerAliveCountMax 3
  • ServerAliveInterval 必须小于服务端的 ClientAliveInterval,否则探测包赶不上服务端判定节奏
  • 避免设 ServerAliveInterval 0 —— 这会禁用客户端保活,完全依赖服务端策略

注意:ServerAlive* 是客户端行为,只影响本机发起的连接;而 ClientAlive* 是服务端行为,影响所有接入的客户端。

排查 NAT 或中间设备干扰的必要步骤

即使服务端和客户端都配了保活,仍可能因路由器防火墙、云平台 SLB 清理空闲连接而断连。这类断连通常没有日志痕迹,且复现不稳定。

验证方法:

  • 在客户端执行 ping -i 30 target_ip 同时保持 SSH 连接,观察是否还断——若不断,说明是纯空闲导致;若仍断,大概率是中间设备干的
  • tcpdump -i any port 22 抓包,看最后收到的是否为 RST 或 FIN 包,以及源 IP 是否来自网关而非目标服务器
  • 云服务器(如阿里云、AWS)需检查安全组/网络 ACL 是否启用了“连接空闲超时”,该值常为 900 秒(15 分钟),且不可调

这种场景下,唯一可靠解法是客户端持续发送保活帧,ServerAliveInterval 建议设为 300(5 分钟)以内,避开中间设备阈值。

真正麻烦的是那些既没日志、又不回 RST 的“静默丢包”设备——它们会让 SSH 卡住几十秒才报错,此时必须结合 ConnectTimeout 和重试逻辑做容错,而不是指望一次配置解决所有问题。

text=ZqhQzanResources