SSH总断开:keepalive与超时配置
来源: 飞翔小编 2026/11/5 10:28:31 浏览量:0
一、SSH断连的四类成因:先定位再动手

连接掉线时先别急着换服务器。SSH 会话断开的机制只有四类,判读日志和现象各只要两条信息就能分清是哪一类,后面所有参数调整都是从这个判断里长出来的。
第一类是服务端主动踢人。sshd 侧有一个没有任何数据流动时的空闲计时器,超过阈值就发一条断开通知并关掉会话。这类断连的特征很固定:断开的时刻和你上一次敲键盘的时间点高度相关,而且服务端日志里能查到对应的记录。检查命令是 journalctl -u sshd --since "1 hour ago" | grep -i -E "disconnect|timeout|close",如果是 Debian 系就把 sshd 换成 ssh。
第二类是中间设备回收会话表。家用路由器、公司出口网关、云上安全组后面挂的软路由,都维护一张 TCP 连接表。一条连接如果长时间没有数据包,NAT 会在几十秒到几十分钟后把映射老化掉,此后你再发数据,收到的就是 RST 或者干脆石沉大海。这类断连的特征是:没有任何服务端日志、断开时你在敲键盘、而且往往发生在你切到手机热点、连上会议室 WiFi、或者笔记本从有线切到无线之后。
第三类是客户端网络本身断了。网卡被系统休眠挂起、VPN 隧道重建、WiFi 信号切换、路由表刷新,都会让 TCP 连接凭空消失。表现是本地网络事件日志里有对应的记录,而且往往一断就是一片服务同时断,而不是单个 SSH。
第四类是负载均衡或 SSH 跳板机上的空闲超时。多一层网关就多一组超时参数,客户端再怎么调也顶不过中间层。
判读顺序有个固定套路:先看服务端日志有没有记录。有记录就是第一类,没有记录就看客户端网络事件,没有的话就是第二类或第四类。而第二类和第四类的解法完全一致:让数据流动起来。
二、客户端参数:ServerAliveInterval 怎么设才对

客户端这一侧真正起作用的只有三个参数,方向搞反了比不配还糟。
ServerAliveInterval 是客户端在空闲时主动发心跳包的间隔,ServerAliveCountMax 是连续多少次心跳没有得到回应后判定连接已死并断开。默认情况下 OpenSSH 是不发心跳的,连接完全依赖 TCP 层的 keepalive,而多数系统上 TCP keepalive 的首次探测间隔是 7200 秒,也就是两小时才发一个探测包——这个时间对 NAT 表老化来说太晚了。
合理的配置原则是:心跳间隔要小于你链路上的 NAT 会话老化时间,同时又不能太短,否则空闲时也在占用流量和 CPU。一个能落地的经验区间是 30 到 60 秒。取 30 秒时,配合 ServerAliveCountMax 3,意味着链路真正断掉后最多 90 秒客户端就会自己报 Connection lost 并退出,而不是像现在这样一直挂着、等到你敲下第一个字符才发现界面已经死了。
TCPKeepAlive yes 也要打开,但它和上面两个不是一回事。TCPKeepAlive 控制的是操作系统层的 TCP SO_KEEPALIVE 选项,依赖系统自身的 TCP 参数(Linux 上 net.ipv4.tcp_keepalive_time 一般是 7200 秒),它防的是主机崩溃、网线被拔这种级别的断,不防 NAT 表老化。所以它是补充,不是主力。
三条建议写进 ~/.ssh/config:
# ~/.ssh/config
Host *
ServerAliveInterval 30
ServerAliveCountMax 3
TCPKeepAlive yes
ControlMaster auto
ControlPath ~/.ssh/ctl-%r@%h:%p
ControlPersist 10m
ControlMaster 这三行经常被忽略,但它才是根治频繁重连的关键。开启之后,第一次连接会建立一个主连接,后续所有 SSH 会话都复用这条隧道;主连接断了,OpenSSH 会自动重新建立并把挂载的会话接上。配合 ControlPersist 10m,即使你主动退出全部会话,主连接还会保持十分钟,这段时间内再连同一台机器是秒开的,根本不会经历 TCP 握手和密钥交换。
有一类情况必须关掉它:如果你在做端口转发隧道(-L、-R),复用连接时转发规则是跟着主连接走的,反复开关隧道容易出现"隧道还在但端口没监听"的错觉。遇到这种问题临时加 -o ControlMaster=no 即可。
三、服务端 sshd_config 的六个超时项,逐条拆开

服务端能调的参数比客户端更多,但真正需要动的通常只有三个,其余了解一下就够了。
ClientAliveInterval 是服务端反向发心跳的间隔,ClientAliveCountMax 是连续多少次没回应后服务端主动断开。注意方向:客户端的 ServerAliveInterval 是客户端问服务端、服务端的 ClientAliveInterval 是服务端问客户端。两边都配上,才能在任一方向单边失效时快速发现。
ClientAliveInterval 60 配 ClientAliveCountMax 3,等价于服务端在连接空闲 180 秒后主动清理掉这个会话。它解决的是"客户端悄悄消失但服务端还占着进程和内存"这个问题——僵尸会话堆积起来会显著吃内存。默认 OpenSSH 在这一项上是 0,也就是不启用自动清理。
TCPKeepAlive yes 让服务端在建立连接时打开系统级 TCP keepalive,用来发现硬断线。这一项值得开,但同样不能替代应用层心跳。
LoginGraceTime 30 控制认证阶段的宽限时间,默认 120 秒。它不影响已登录会话,但在公网机器上把默认值调小能压缩暴力破解的暴露窗口。
MaxSessions 10 与 MaxStartups 10:30:60 控制并发会话与并发未认证连接。前者默认 10,批量跑脚本时会撞上限;后者控制的是尚未完成认证的连接队列,是暴力破解的第一道闸门。这两个参数属于安全加固范畴,不是断连问题。
UseDNS no 值得单独提一句。开启时服务端会在反查客户端 IP 的主机名,DNS 超时会让登录过程明显变慢甚至看起来像连不上;关掉它只是少了日志里的主机名,不影响功能。
改完服务端配置必须重载而不是重启,重载不会踢掉现有会话:
# 备份后修改,并用 sshd -t 检查语法,避免写错一行把自己关在门外
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
sudo sshd -t && sudo systemctl reload sshd
# Debian/Ubuntu 上服务名是 ssh,RHEL 系是 sshd
先备份、先 -t 检查、再 reload,这三步顺序不能颠倒。sshd -t 报语法错误时不要强行 reload,否则服务起不来,你就只能通过控制台的 VNC 或救援模式进去了。
四、中间网络设备:NAT 表老化才是断连主因

如果服务端日志里找不到断开记录,那八成问题出在你和服务器之间的某个中间设备上,它在悄悄回收连接。
原理是这样的:服务器看到的是你的公网 IP,但你的内网 IP 和端口在路由器上做了转换。路由器维护一张映射表,记录"内网某 IP 某端口 公网某 IP 某端口"的对应关系。一旦这个映射长时间没有流量,路由器就把它删除。此后你发包时,路由器找不到对应关系,只能新建一条新连接,而服务器那边还拿着旧的、已经失效的连接,于是两边对不上话,表现就是连接卡死或者被重置。
判断方法有两个,都不需要改任何配置。第一个是在客户端抓包,看 TCP 包有没有真的发出去:
# 抓到 SSH 流量,只看包头,不显示负载
sudo tcpdump -i any -n 'tcp port 22' -c 20 -vv
如果断线后你看到客户端发出的是 RST 而不是数据包,说明是中间设备直接拒绝;如果看到数据包发出去但收不到任何回应,那就是回程路径被丢弃了。第二个方法更直接:改用手机热点连一次同样的服务器,如果热点下稳定不断,那问题就锁定在你原来那条宽带的出口设备上。
常见的会话老化时间参考值:家用路由器和普通企业网关多数在 300 秒到 1800 秒之间;运营商级 NAT 可能更长;云厂商的 NAT 网关通常配得比较宽松,但很多企业防火墙会在 350 秒左右断开空闲连接。500 到 900 秒是各条链路都能安全覆盖的取值。
对应的客户端参数组合是:
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
TCPKeepAlive yes
60 秒间隔意味着每分钟都有一次心跳,任何老化阈值在 300 秒以上的中间设备都不会把连接回收掉;连续 3 次失败也就是 180 秒后判定链路已死,客户端会立刻给你一个明确的错误,而不是假装还在连接。
有个容易忽略的坑:心跳本身也是流量,如果你的服务器按流量计费且带宽很窄,一个空闲 SSH 会话每分钟会占用几百字节——一年下来不到 1 GB,完全可以忽略。但如果你开了 ControlMaster 又忘了关,主连接会一直挂着,每分钟的心跳会一直存在。两者都不构成流量压力,只是别把这当成关闭心跳的理由。
五、长任务怎么办:别让 tmux 当唯一防线

心跳解决的是"连接还活着吗",解决不了"任务跑完了吗"。如果断线时正在执行编译、数据导出、模型训练这类长任务,进程会跟着 SSH 会话一起被杀掉——因为 sshd 退出时会给会话里的所有进程组发 SIGHUP。
正确的做法是让任务跑在会话之外。tmux 是最常用的一层:
# 新建一个命名会话并进入
tmux new -s train
# 在 tmux 里执行长任务
python train.py --epochs 100
# 临时离开但保持任务运行:按 Ctrl+b 然后按 d
# 重新连回来
tmux attach -t train
# 看所有会话
tmux ls
关键点在于必须先进入 tmux 再启动任务。如果先跑任务再 tmux,新建的 tmux 里是没有那个进程的。很多人的"tmux 保活"其实没用,原因就在这里。
更彻底的办法是让 systemd 托管任务,它不依赖任何登录会话:
# 把命令写成 systemd 服务
sudo tee /etc/systemd/system/train.service >/dev/null <<'EOF'
[Unit]
Description=Training Job
After=network-online.target
[Service]
Type=simple
User=root
WorkingDirectory=/root/project
ExecStart=/usr/bin/python3 train.py --epochs 100
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now train
# 看日志
journalctl -u train -f
systemd 服务的三个好处是:机器重启后自动拉起、可以用 Restart=on-failure 做崩溃重试、日志统一进 journald 不会丢。缺点是没有交互式终端,脚本里如果用了交互式输入(比如 ssh 提示密码、vim 之类)会直接挂住。
screen 是 tmux 的老前辈,用法类似:screen -S job 创建,Ctrl+a d 脱离,screen -r job 恢复。功能上被 tmux 完全覆盖,新项目直接用 tmux。
还有一个折中方案叫 mosh。它不是 SSH,而是一套独立的协议,会话状态保存在服务器上,客户端断网后重连可以恢复终端滚动内容和输入历史,中间还有 UDP 传输。它的代价是需要服务端装 mosh-server、客户端装 mosh,并且默认走 UDP 17 端口,很多公司网络会把它拦掉。对需要长时间挂着的交互式工作——比如盯着训练日志手动改参数——它比 tmux 舒服得多。
六、算账:一次断连到底损失多少时间

"总断开"听起来是小事,但把它换算成时间就知道为什么值得花半小时配好。
一次 SSH 断连的实际损失至少包含四段:等待察觉的时间、重新建连的时间、重新登录认证的时间、以及操作上下文的丢失成本。前三段是纯技术开销,第四段是真正的隐性成本——如果断连时你正在手工改配置文件,重连后要重新定位、改到一半的行、还有可能丢失没有保存的编辑内容。
按前面的参数算一笔账。ServerAliveInterval 60 加 ServerAliveCountMax 3,链路真断之后的察觉时间上限是 180 秒。SSH 密钥认证下一次连接通常在 1 到 3 秒内完成,也就是说每次断连大约浪费 3 分钟。加上人工察觉和重连操作,保守估计每次断连占用 5 分钟。
如果一台机器每天断 6 次,一年就是 1095 次,合计 5475 分钟,也就是 91 小时。如果这些断连都发生在你正在盯着的任务上,每次还要额外花 10 分钟恢复上下文,一年就是 182 小时。两项相加超过 270 小时——这是一个人三个多月的完整工作日。
再看钱的一侧。按当前渠道库里 sixtynet 的年付套餐折算:LAX-STARTER 是 200 美元年付,折合每月 16.67 美元,2 核 2G、40 GB 盘、2000 Mbps 端口、5000 GB 月流量,折合每 TB 流量 3.413 美元;同一家 LAX-MICRO 是 400 美元年付,折合每月 33.33 美元,4 核 4G、80 GB NVMe、4000 Mbps、10000 GB 月流量,同样是每 TB 3.413 美元;LAX-MEDIUM 是 800 美元年付,折合每月 66.67 美元,8 核 8G、160 GB NVMe、10000 Mbps、20000 GB 流量。若按一天断 6 次的频率,一年 91 小时的时间成本,在 LAX-STARTER 的月价 16.67 美元面前是一个不容忽视的数字。
反过来看选配带宽和流量的性价比。sixtynet 的 LAX-Storage-500G 是 400 美元年付,折合每月 33.33 美元,4 核 4G、500 GB 盘、10000 Mbps 端口、10000 GB 流量,每 GB 磁盘只有 0.067 美元,折合每 TB 流量仍是 3.413 美元;同系列 LAX-Storage-1TB 是 700 美元年付,折合每月 58.33 美元,8 核 8G、1000 GB 盘、15000 GB 流量,每 GB 磁盘 0.058 美元。同一家的 LAX-LARGE 则是 1600 美元年付、折合每月 133.33 美元,8 核 16G、320 GB NVMe、40000 GB 流量。
把这些数字换成人民币更有体感:云途 HK.DS.M 是 350 元每月、32 GB 内存、480 GB 盘、1000 Mbps、10000 GB 流量;HK.DS.P 是 750 元每月、64 GB 内存、1024 GB 盘、2000 Mbps、40000 GB 流量;HK.DS.S 是 800 元每月、128 GB 内存、6000 GB 盘、2000 Mbps、40000 GB 流量,超出额度的流量重置价是 500 元;HK.DS.B 是 1200 元每月、128 GB 内存、2000 GB 盘、1000 Mbps、40000 GB 流量;DS.ES.B 是 1500 元每月、256 GB 内存、1920 GB 盘、2000 Mbps、30000 GB 流量。这些都是按月计费的。
按每 GB 内存的单价排,云途 HK.DS.S 最低,约 6.25 元每月每 GB 内存;其次是 DS.ES.B,约 5.86 元每月每 GB 内存,但它只有 30000 GB 流量;HK.DS.P 约 11.72 元;HK.DS.M 约 10.94 元。流量单价方面,HK.DS.S 与 DS.ES.C 同为每 TB 20.48 元,而 HK.DS.B 因为只有 1000 Mbps 端口,每 TB 流量要到 30.72 元。
结论很清楚:如果你只是要一台能远程登录、跑脚本、不掉线的机器,内存和流量都是次要变量,真正要盯的是端口速率和线路稳定性。
七、验收标准:可量化的阈值与测试脚本

配置改完不能凭感觉判断有效。下面这套阈值可以直接当成验收单,每一条都有明确的数字。
心跳存活判定:客户端发送心跳后,服务端的响应必须在 2 秒内回来。测量方法是在服务器上开一个 tcpdump 抓心跳包,在客户端同时用 ping 和 ssh -v 观察,正常情况下心跳往返时间应当小于 200 毫秒。
断链察觉时间:从物理断网到客户端报错,间隔必须小于 180 秒。用 ServerAliveInterval 60 加 ServerAliveCountMax 3 时,理论上界就是 180 秒,实测应该在 60 到 180 秒之间。测法是拔网线或者关掉手机热点,记录从断开到终端返回提示的时间。
重连耗时:从执行 ssh 到拿到可用提示符,必须小于 5 秒。用密钥登录时应该稳定在 1 到 3 秒;如果你还在用密码登录,把它降到 1 秒以内是必须做的事。
空闲会话不泄漏:一台机器上连续建立 200 个 SSH 会话然后全部关闭,服务端的 sshd 进程数必须回到基线附近(允许 5% 以内的浮动)。这条尤其重要,因为 MaxSessions 和 MaxStartups 的默认值会在大量会话场景下把新连接直接拒掉。
长任务存活率:在 tmux 或 systemd 里启动一个跑 30 分钟的任务,中途强制断开客户端,任务必须继续跑到自己结束,且退出码为 0。这条是区分"配好了"和"只是看起来好了"的关键。
# 一键跑一遍关键项
# 1) 查当前生效的客户端配置
ssh -G example.com | grep -E "serveralive|tcpkeepalive|control"
# 2) 看服务端 sshd 进程的常驻内存排行
ps -eo comm,rss --sort=-rss | awk 'NR==1{print "进程 RSS_MB"} NR>1 && $2>20000 {printf "%s %.0f\n", $1, $2/1024}'
# 3) 数当前会话数
pgrep -c sshd
# 4) 测重连耗时
time ssh -o BatchMode=yes example.com "echo ok"
八、什么情况下不该只靠 keepalive 硬撑

心跳参数不是万能药,有几种情况它解决不了,硬调只会掩盖真问题。
机房位置与本地线路不匹配时。如果你的服务器在俄罗斯机房,而你从国内访问,问题不在超时而在路由质量。渠道库里 RosCloud 系列(justg 在售)就是俄罗斯节点的 VPS,全部 500 Mbps 端口、1024 GB 到 6144 GB 月流量、按月计费,配置从 RosCloud-01 的 2 核 1G 19.99 美元到 RosCloud-06 的 7 核 24G 69.99 美元,单价随配置上升而下降,RosCloud-06 约每 TB 流量 11.665 美元。俄罗斯节点的流量单价是美西同类方案的数倍,原因是跨洲回程的带宽成本高。这类机器上再好的心跳也救不了跨境绕路带来的高延迟和丢包。替代方案是:需要这类地区 IP 的业务(比如特定地区的服务节点)放到那里,接受高延迟只跑后台任务;如果你的主要诉求是稳定登录,就换到离你更近的节点,把俄罗斯机器只作为备份。
线路类型本身会主动断开长连接时。CN2 GIA、9929 这类优化线路与普通国际线路的一个差别在于策略不同,有些会主动回收超长空闲的 TCP 流。心跳能延长时间但不能改变策略,此时应当缩短心跳间隔到 30 秒,或者干脆改用 mosh 这类不依赖长连接保活的协议。
共享带宽被限速时。注意上面那些套餐里的端口速率:sixtynet 从 LAX-STARTER 的 2000 Mbps 到 LAX-LARGE 的 10000 Mbps,另有 Los Angeles China Unicom-Premium 标注 100 Mbps 带宽、2500 美元年付(折合每月 208.33 美元)。当端口速率本身不高、且共享带宽在高峰期被压到很低时,你感受到的"卡住"其实是排队而不是断连,心跳包同样会被延迟,误判成掉线。替代方案是选端口速率与你的实际需求匹配的套餐,不要用 100 Mbps 端口的机器跑需要持续大吞吐的任务。
IP 资源需要频繁更换时。sshd 的 MaxStartups 与防爆破策略会把频繁重连的来源当成扫描行为。频繁更换 IP 重连时,应该调高 MaxStartups 并把 LoginGraceTime 调大,而不是去动心跳。
计费方式与流量额度不匹配时。云途的 HK.DS.S 是 800 元每月含 40000 GB 流量,超出后的重置价是 500 元;HK.DS.B 是 1200 元每月、40000 GB 流量,但端口只有 1000 Mbps。如果你为了不断连把心跳间隔调到 10 秒,心跳流量本身微不足道,但连接一直保持意味着所有后台任务也在持续消耗流量,这时应该改看计费方式:按流量计费的机器不适合跑常驻的持续下载类任务。
这四种情况的共同点是:断连的根因不在"会话空闲",而在网络路径、策略、限速或计费。遇到这几种,先解决根因,再回来调心跳。
九、跨网络切换与客户端选择

笔记本从家里到公司、WiFi 切到 4G、VPN 上下线,是断连的高发场景。这里有几个能立刻见效的做法。
第一是让客户端主动感知网络变化并重连,而不是等 TCP 超时。Windows 上的 OpenSSH 从 8.x 开始就支持这个能力:
# Windows 10/11 自带的 OpenSSH 客户端
ssh -o "ServerAliveInterval=60" -o "ServerAliveCountMax=3" user@host
# 如果用 Git for Windows 自带的 ssh
ssh -V
macOS 和 Linux 上,NetworkManager 配的 wifi 会在切网时触发接口变更,加上前面说的 ControlMaster 复用与 ControlPersist,重连基本是秒级的。
第二是换客户端。PuTTY 的配置项在 Connection 分类下,勾上 "Keep alive alive" 之类并填入秒数即可,但它的 keepalive 是纯 TCP 层的空包探测,不要把它当成 SSH 应用层心跳。Windows Terminal 支持打开一个 ssh 标签页,配好 ~/.ssh/config 后直接 ssh user@host 就带着全部参数。JetBrains 系 IDE 内置的 SSH 控制台,支持复用会话和自定义保活间隔,但它的连接配置与 ~/.ssh/config 是两套系统,需要分别设置。
第三是移动端。手机上的 SSH 客户端普遍支持自定义心跳间隔,但移动网络在切换基站、进入电梯、锁屏时会瞬间切换 IP 源地址,这是最容易触发断连的环境。在移动端上做长任务,务必放在 tmux 里。
第四是跳板机。一台跳板机后面挂十几台机器时,跳板机自身的 ClientAliveInterval 会同时决定所有下游会话的存活判定。所以调跳板机的超时参数收益是乘数级的:跳板机设 60 秒 / 3 次,下游每一台都受益。而如果每台机器单独 SSH 到跳板机、而不是用 ssh -J jump user@target 的 ProxyJump 方式,连接数会翻倍,也更容易撞上 MaxSessions。
十、故障排查命令清单与常见报错解读

遇到断连先跑这几条命令,大部分情况能直接定位。
# 1) 客户端:看本次连接协商出的实际参数(配置文件里的不一定生效)
ssh -v user@host 2>&1 | grep -E "ServerAlive|TCPKeepAlive|ControlMaster|Connecting to"
# 2) 服务端:查 sshd 的实际配置来源(Debian 是 /etc/ssh/sshd_config,RHEL 可能拆成 sshd_config.d 目录)
sudo sshd -T | grep -E "clientalive|tcpkeepalive|maxsessions|maxstartups|logingracetime"
# 3) 服务端:看断开原因
sudo journalctl -u ssh -n 200 --no-pager | grep -i -E "disconnect|timeout|reset|refused"
# 4) 客户端:统计一段时间内断了多少次
grep -c "Connection reset by peer" ~/.bash_history 2>/dev/null
# 或者从服务端日志统计
sudo journalctl -u ssh --since "24 hours ago" --no-pager | grep -ci disconnect
# 5) 看会话是否泄漏(连开 200 个再对比)
pgrep -c sshd
Connection reset by peer 表示对端或中间设备主动发了 RST,属于链路被拒,回到第四节的 NAT 判断流程。
Connection timed out 表示报文发出去没有回包,通常是路由问题或防火墙拦截,用 traceroute 看在哪一跳断掉:traceroute -T -p 22 host 或 mtr -T -P 22 host。
ClientAliveInterval exceeded 或者 Timeout, server not responding 出现在服务端日志里,说明心跳发出去了但没收到回应,此时问题在回程路径,不在空闲超时。
Too many authentication failures 是密钥太多或者 agent 里塞了太多私钥,SSH 会依次尝试每个密钥,服务端达到 MaxAuthTries 就断开。解决办法是在 ~/.ssh/config 里写死 IdentityFile ~/.ssh/id_ed25519 加 IdentitiesOnly yes。
kex_exchange_identification: Connection closed by remote host 通常是 fail2ban 或者封禁策略把来源 IP 拦了,日志里能看到对应记录。
no matching host key type found 是服务端升级了 OpenSSH 后禁用了旧的密钥算法,用 ssh -o "HostKeyAlgorithms=+ssh-rsa" 临时验证一下,确认后更新 known_hosts。
十一、五个常见误区

误区一:以为 keepalive 能修复网络故障。心跳只能发现故障,不能修复故障。链路真的断了、路由绕了、带宽被限了,调任何参数都不会让速度变快。
误区二:把 TCPKeepAlive 当成应用层心跳。它的探测间隔由系统参数决定,Linux 上默认 7200 秒,对 NAT 老化来说太晚。真正起作用的是 ServerAliveInterval。
误区三:心跳间隔调得越短越保险。30 秒一次心跳本身没成本,但如果你在几百台机器上批量下发配置,会话数、文件描述符、连接数都会同步上涨。间隔从 30 秒改到 60 秒,察觉时间上界从 90 秒变成 180 秒,多数场景完全够用。
误区四:只改客户端不改服务端。只改客户端,遇到服务端 sshd 主动清理空闲会话的情况依然会断。两边都要配。
误区五:以为 tmux 能保存所有工作。tmux 保的是终端会话和里面正在跑的进程,不是你的编辑缓冲区。如果用 vim 开着文件没保存就断线,tmux 里进程还在,vim 的未保存内容也还在,这个没问题;但如果用的是某些不写盘的编辑器,或者你自己把文件清空了,tmux 帮不上忙。真正的保险是定时保存加版本控制。
补一个关于 ServerAliveCountMax 的细节:它和 ServerAliveInterval 是相乘关系。设成 3 意味着连续 3 个心跳周期都没回应才判定死亡,也就是 3 倍间隔时长。设为 0 或 1 会让客户端在第一次心跳无响应时立刻断开,在链路抖动时非常敏感,实际使用里 3 是个稳妥的起点。
十二、决策建议:按场景选配置

把上面的内容压缩成可执行的选择。
如果你只是要一台远程登录的机器做日常运维,选带宽和流量都够用、内存 2 GB 起步的套餐即可。以当前渠道库看,sixtynet 的 LAX-STARTER 是 200 美元年付,折合每月 16.67 美元,2 核 2G、40 GB、2000 Mbps、5000 GB 流量,每 TB 流量 3.413 美元;同档若想要更多内存和 NVMe,LAX-MICRO 是 400 美元年付、折合每月 33.33 美元,4 核 4G、80 GB NVMe、4000 Mbps、10000 GB 流量,每 TB 同样是 3.413 美元。国内访问为主、希望付款方便且流量额度大的,看云途 HK.DS.M(350 元每月,32 GB / 480 GB / 1000 Mbps / 10000 GB)和 HK.DS.P(750 元每月,64 GB / 1024 GB / 2000 Mbps / 40000 GB)。
如果你要跑常驻服务、需要大内存,直接看内存单价而不是总价。云途 HK.DS.S 是 800 元每月给到 128 GB 内存、6000 GB 盘、2000 Mbps、40000 GB 流量,每 GB 内存约 6.25 元,是几档里内存最划算的;DS.ES.B 是 1500 元每月给到 256 GB 内存、1920 GB 盘、30000 GB 流量,每 GB 内存约 5.86 元更低,但流量只有 30000 GB 且每 TB 流量单价升到 51.2 元,流量敏感的业务要算清楚。需要大存储又对内存要求一般的,看 sixtynet LAX-Storage-500G(400 美元年付,500 GB 盘,每 GB 磁盘 0.067 美元)和 LAX-Storage-1TB(700 美元年付,1000 GB 盘,每 GB 磁盘 0.058 美元)。
如果你主要诉求是不掉线本身,那把预算花在带宽和线路上,而不是花在 SSH 参数上。同样是 sixtynet,端口从 2000 Mbps 提到 10000 Mbps 的 LAX-MEDIUM 是 800 美元年付、折合每月 66.67 美元,8 核 8G、20000 GB 流量,每 TB 3.413 美元;需要中国方向专线且能接受低带宽的,Los Angeles China Unicom-Premium 是 2500 美元年付、折合每月 208.33 美元、100 Mbps 端口。注意后者没有公开的内存和磁盘数据,这一条以官网当日报价为准。
如果你要的是俄罗斯方向的业务节点,直接看 RosCloud 系列:按月计费,从 RosCloud-01 的 2 核 1G 20 GB 盘 1024 GB 流量 19.99 美元,到 RosCloud-06 的 7 核 24G 320 GB 盘 6144 GB 流量 69.99 美元,每 GB 内存单价从 19.99 美元降到 2.92 美元,每 TB 流量从 19.99 美元降到 11.665 美元。配置越大越划算,但流量单价依然是欧美方案的数倍,别把它当通用主力机。
配置层面统一给一条:客户端 ServerAliveInterval 60、ServerAliveCountMax 3、TCPKeepAlive yes、ControlMaster auto、ControlPersist 10m;服务端 ClientAliveInterval 60、ClientAliveCountMax 3、TCPKeepAlive yes、UseDNS no;长任务进 tmux 或 systemd。这套东西在任何一台机器上花十分钟配好,之后基本不用再看。
十三、十分钟落地清单:一份可以直接复制的配置

把所有要点压缩成一次性的操作序列,按顺序执行就不会漏。
第一步,备份并检查现有配置。服务端先把 sshd_config 复制一份备份,然后用 sshd -T 把当前生效的全部参数打印出来存一份,这一步比直接读配置文件更可靠,因为配置文件可能有 include 分片,你读到的不是最终生效值:
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
sudo sshd -T > /root/sshd_before.txt
grep -E "clientalive|tcpkeepalive|maxsessions|maxstartins|logingracetime|usedns" /root/sshd_before.txt
第二步,改服务端。删掉原有的 ClientAliveInterval 和 ClientAliveCountMax 行再写入新值,避免同一参数出现两次导致 sshd 取到第一个值:
sudo sed -i '/^[[:space:]]*ClientAliveInterval/d; /^[[:space:]]*ClientAliveCountMax/d' /etc/ssh/sshd_config
printf '\nClientAliveInterval 60\nClientAliveCountMax 3\nTCPKeepAlive yes\nUseDNS no\n' | sudo tee -a /etc/ssh/sshd_config
# 语法检查通过才重载
sudo sshd -t && sudo systemctl reload sshd
sudo sshd -T | grep -E "clientalive|tcpkeepalive|usedns"
第三步,改客户端。把下面这段写进 ~/.ssh/config,注意 Host * 这一行后面的缩进用空格也行,但配置项必须每行一个:
cat >> ~/.ssh/config <<'EOF'
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
TCPKeepAlive yes
ControlMaster auto
ControlPath ~/.ssh/ctl-%r@%h:%p
ControlPersist 10m
EOF
chmod 600 ~/.ssh/config
第四步,验证参数确实生效。ssh -G 会输出 SSH 针对某个主机最终会使用的全部配置,包括配置文件、命令行参数和默认值:
ssh -G example.com | grep -iE "serveralive|tcpkeepalive|controlmaster|controlpersist"
输出里应当看到 serveraliveinterval 60、serveralivecountmax 3、tcpkeepalive yes、controlmaster auto。看不到就说明配置没被读取,检查文件末尾有没有多余空行导致解析中断。
第五步,做一次破坏性测试。选一个不重要的时间点,手动拔网线或者关闭 WiFi,记录从断开到终端报错的秒数。合格线是 180 秒以内,之后重连耗时不超过 5 秒。
第六步,把长任务迁进 tmux 或 systemd。已经跑着的任务不能直接搬,稳妥的做法是:用 tmux 起一个新会话,在里面重新执行任务命令,旧的进程确认不需要之后再杀掉。或者用 systemd,把命令写进 service 单元,这样还能额外拿到崩溃重试和开机自启。
整个流程走完不超过十分钟。之后唯一需要做的就是:换了网络环境、升级了 OpenSSH、或者 sshd_config 被别的工具覆盖之后,重新跑一次第四步和第五步确认。
按你的情况,下一步该看哪家
上面讲的是判断标准,但多数人最后还是想问一句「那我该买谁」。按你的实际情况对照下面几条,直接去看对应的机型页比继续比价更快:
- 做跨境或店群、需要多 IP:优先看 IP 类型与换 IP 政策,别只看配置。看 iwebfusion 当前机型与价格
- 主要访客在国内、在意打开速度:先确认回程线路,再谈配置。看 racknerd 当前机型与价格
- 只是开发测试、临时用:按小时或月付,用完就删,别买年付。看 spinservers 当前机型与价格
价格与库存以商家页面当日显示为准,下单前建议先确认退款窗口与是否支持按月付费。
十四、常见问题

心跳间隔到底设多少秒最合适? 60 秒是覆盖面最广的取值,能扛住绝大多数老化阈值在 300 秒以上的路由器和企业网关,同时心跳流量小到可以忽略。链路质量差、经常遇到 30 到 60 秒就被回收的网络,可以降到 30 秒;服务器数量多、连接规模大的场景,60 秒比 30 秒更合适,因为察觉时间的上界从 90 秒变成 180 秒,多出来的 90 秒换来的连接资源节省是值得的。
配了心跳还是断,是不是就没办法了? 先看服务端日志有没有断开记录。有记录说明是服务端主动清理,检查 ClientAliveInterval 和 ClientAliveCountMax 是否生效;没记录说明问题在链路或中间设备,用 tcpdump 看客户端的包有没有真的发出去。如果包发出去了没回应,就是路由或防火墙问题,调参数解决不了。
ServerAliveCountMax 设成 0 会怎样? 表示不做基于心跳的失效检测,连接只靠 TCP 层判断。这等于关掉了这个机制,回退到默认行为,也就是等操作系统层面超时,通常要等很久。
心跳会不会影响服务器性能? 单条 SSH 会话每 60 秒发一个几十字节的包,CPU 和带宽占用都可以忽略。但心跳会保持连接处于 ESTABLISHED 状态,如果你有基于连接数做限制的策略,需要把它们算进配额。
ControlMaster 会在服务器上留下残留进程吗? 会。主连接会保持到你断开全部复用它的会话加上 ControlPersist 指定的时间。可以用 ssh -O exit host 主动关闭主连接,或者把 ControlPersist 设成 no 让它随最后一个会话一起退出。服务器上可以用 pgrep -af "sshd: root@notty" 看到这些复用连接。
Windows 上的 OpenSSH 支持这些参数吗? 支持,Windows 10 1809 以后内置了 OpenSSH 客户端,配置逻辑和 Linux 版一致,配置文件同样放在 C:\Users\你的用户名\.ssh\config。但要注意 PuTTY 和 OpenSSH 是两套独立配置,参数不通用。
改完 sshd_config 需要重启服务器吗? 不需要,systemctl reload sshd 即可重载配置且不打断已有会话。前提是先用 sshd -t 确认语法正确,否则 reload 失败时服务可能起不来。
用密码登录和用密钥登录对断连有影响吗? 有。密码登录每次重连都要多花一次交互输入,几秒到十几秒不等,且在断线频繁时体验非常差。密钥登录能让重连稳定在 1 到 3 秒,配合 ServerAliveCountMax 的自动感知,整个断连恢复过程基本不需要人工干预。
长任务用 nohup 和用 tmux 有什么区别? nohup 让进程忽略 SIGHUP,进程能继续跑,但标准输入输出仍然绑在原终端上,交互式任务会因为 stdin 关闭而异常,而且没有会话管理能力。tmux 提供的是一个完整的终端复用环境,任务、日志、滚动历史都能重新接回来,还能同时开多个窗口。做长任务优先用 tmux,需要开机自启和崩溃重启用 systemd。
SSH 端口被封了或者服务器偶尔抽风,怎么兜底? 保留一条备用通道:多数云服务商提供 VNC 或串口控制台,能在网络完全不通时登录进去修配置。配置 SSH 时顺手确认这条备用通道可用,比多配十个参数都管用。
