为什么ssh长时间空闲后,终端就卡死了
·
Table of Contents
问题原因
- SSH 连接在长时间空闲后“卡死”(表现为终端无响应、输入无回显、Ctrl+C 无效等),\
- 通常不是 SSH 协议本身“卡”了,而是连接被中间网络设备(如 NAT 网关、防火墙)静默丢弃所致。
具体分析
- TCP 连接超时被中间设备丢弃
- 多数 NAT 路由器或云服务商(如 AWS、阿里云)的防火墙/安全组默认 TCP 空闲超时时间为 5–15 分钟(例如 AWS 默认 350 秒)。
- 若 SSH 会话长时间无数据包交换(即使你在终端看着 htop 不动也算“空闲”),中间设备会悄悄丢弃连接状态,但不向两端发送 RST/FIN。
- 此时:
- 客户端仍以为连接 alive,输入无响应(包发出去但被丢,无 ACK);
- 服务端也无感知,直到尝试写数据才发现对端已不可达(但可能延迟很久)。
- 服务端或客户端的 TCP keepalive 默认关闭或间隔太长
- Linux 默认的 TCP keepalive 是 net.ipv4.tcp_keepalive_time = 7200 秒(2 小时),远晚于中间设备的超时。
- 所以 keepalive 包来不及发送,连接已被丢弃。
- 终端控制字符阻塞(较少见)
- 如误按 Ctrl+S(XOFF 流控),导致终端本地“卡住”,但此情况可通过 Ctrl+Q 解除,且不影响 SSH 底层连接。
解决方案(推荐组合使用)
启用 SSH 客户端保活(最常用)
在 客户端 的 ~/.ssh/config 中为对应主机配置:
Host your-server # 或 * 表示全局
HostName example.com
User peter
ServerAliveInterval 60 # 每60秒客户端发一个空包探测
ServerAliveCountMax 3 # 连续3次无响应则断开
TCPKeepAlive yes # 同时启用底层 TCP keepalive(可选)
✅ 效果:每 60 秒发一次 SSH_MSG_CHANNEL_REQUEST "[email protected]",穿透 NAT 设备,防止被丢弃。
服务端保活(需有服务器权限)
在服务端 /etc/ssh/sshd_config 中添加:
ClientAliveInterval 60
ClientAliveCountMax 3
重启 sshd:sudo systemctl restart sshd
⚠️ 注意:若中间设备超时 < 60 秒(如某些企业防火墙为 30 秒),可设为 30。
系统级 TCP keepalive 调优(全局生效)
临时调整(重启失效):
# Debian/Ubuntu
sudo sysctl -w net.ipv4.tcp_keepalive_time=300
sudo sysctl -w net.ipv4.tcp_keepalive_intvl=60
sudo sysctl -w net.ipv4.tcp_keepalive_probes=3
# 永久生效:写入 /etc/sysctl.d/99-tcp-keepalive.conf
诊断技巧
- 检查是否真“卡”:另开终端 ping your-server。若 ping 通但 SSH 卡住 → 确认为 SSH 连接被丢弃。
- 查看 SSH 日志(服务端):journalctl -u ssh -f
- 抓包验证:sudo tcpdump -i any host your-server and port 22,看是否有 keepalive 包。