当Notebook实例上的SSH连接数超过10个时,服务端会主动关闭新连接,报错ssh_exchange_identification: Connection closed by remote host,这个报错通常不是密钥或密码问题,而是并发连接数触顶,先清理闲置连接,再调整连接数限制参数,就能恢复登录。
ssh连接数超过限制,为什么偏偏是connection closed by remote host
SSH连接建立时,客户端与服务端要先完成协议握手,这一步在ssh_exchange_identification阶段进行,服务端在这个阶段发现自己的连接槽位已经被占满,会直接断开连接,客户端看到的就是Connection closed by remote host。
Notebook实例默认的SSH服务有两个关键参数控制连接数:MaxStartups(限制未认证并发连接)和MaxSessions(限制已认证会话数),前者默认值是10:30:100,意思是并发未认证连接超过10个后,服务端按30%的概率随机拒绝新连接,拒绝率逐步提高到100%,后者默认是10,限制单个SSH连接最多复用的会话数,两个参数任何一个触顶,表现方式都类似,但用户感知最强的场景就是超过10个连接同时存在时报错。
| 参数 | 默认值 | 作用范围 | 触顶表现 |
|---|---|---|---|
| MaxStartups | 10:30:100 | 未完成认证的连接 | 握手阶段直接断开,报ssh_exchange_identification错误 |
| MaxSessions | 10 | 已认证的会话 | 多路复用会话被拒绝,新会话无法建立 |
行业共识认为,这个数值不是随意定的,它是在安全性和可用性之间的折中,10个并发连接对个人开发完全够用,但对协作型Notebook实例来说,几个同事各开几个终端窗口,再加上自动化任务脚本,很容易就触顶,需要搞清楚的是,报错只出现在新连接上,已有的连接不会受影响,所以排查时要先看哪些连接还在占着位置。
如何排查当前ssh连接数是否已经打满
排查分两步:第一步看当前连接状态,第二步看服务端日志确认服务端确实拒绝过连接。
先在本地或服务端执行以下命令查看活动连接:
ss -tnp | grep :22
这条命令会列出所有到22端口的TCP连接,Established状态的就是活跃SSH连接,统计数量:
ss -tnp | grep ':22' | grep ESTAB | wc -l
如果数量大于等于10,问题就定位了,继续用who命令看具体是哪些用户占用了连接:
who
输出结果里每一行代表一个登录会话,包括登录时间、来源IP,空闲很久的会话就是清理对象。
如果连接数看似没超,但依然报错,需要看服务端日志确认原因,CentOS、Ubuntu等系统日志路径不同:
tail -f /var/log/secure | grep sshd
或
tail -f /var/log/auth.log | grep sshd
日志里出现Maximum authentication attempts或Connection closed by ...的记录,就能直接证明服务端主动断开,这一步很关键,它能区分是连接数限制、防火墙拦截还是密钥问题。不要只盯客户端排查,服务端日志才是最终判断依据。
ssh_exchange_identification报错的解决步骤
确认连接数打满后,按以下顺序处理。
关闭闲置连接释放槽位
先找出最老的空闲连接。w命令会展示每个会话的空闲时间:
w
重点关注IDLE列时间长的会话,用ps -ef | grep sshd找到对应进程PID,然后逐个结束:
kill -9 PID
如果确认真的是残留僵尸连接且不影响自己,也可以批量清理,但不要盲杀,很多Notebook实例上正跑着训练任务或Jupyter Kernel,断开SSH后这些进程不一定终止(取决于是否用了nohup、tmux),但胡乱kill会误伤正在交互调试的同事。
清理完成后,新开一个SSH连接验证:
ssh user@你的实例IP
连接通畅后,复制一份sshd配置文件作为备份,再修改服务端连接数限制:
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak vim /etc/ssh/sshd_config
找到以下两行,将数值调大:
MaxStartups 30:30:100
MaxSessions 30
MaxStartups的第一项是阈值,第二项是拒绝概率,第三项是达到多少连接后100%拒绝,调整后重载SSH服务:
systemctl reload sshd
在客户端配置连接复用,从源头降低连接数
服务端调整只是扩大了容量,要让10个连接不再轻易被占满,客户端配合设置连接复用效果更明显,在~/.ssh/config里写上:
Host your-notebook
HostName 你的实例IP
User root
ControlMaster auto
ControlPath ~/.ssh/controlmux/%r@%h:%p
ControlPersist 10m
这段配置的效果是:同一台实例的多个SSH窗口共享一个TCP连接,后续新开窗口不再占用新的连接数,而是在已有连接上复用会话。ControlPersist 10m表示关闭最后一个窗口后,后台连接保留10分钟,期间再次连接直接复用,既不占新连接,也加速了登录速度。
修改配置后记得创建ControlPath目录:
mkdir -p ~/.ssh/controlmux
如何预防ssh连接数再次被打满
根因不是连接数上限太小,而是大量闲置连接没有被释放,多数情况下,开发者连上实例后忘记退出,直接关闭终端窗口,服务端要等TCP保活超时才会回收连接,这个超时时间通常长达数小时,期间连接一直占着槽位。
配置客户端自动断开空闲连接
在~/.ssh/config中追加:
Host your-notebook ServerAliveInterval 60 ServerAliveCountMax 3
含义是每60秒发送一次心跳,连续3次没有响应就自动断开连接,这样长时间空闲的终端不会一直挂着占连接数。
统一走跳板机或堡垒机
团队协作使用同一个Notebook实例时,让所有人先SSH登录跳板机,再从跳板机连接Notebook实例,跳板机上的连接是可控的,配合MaxStartups调整,避免每个人直接对实例发起大量原始连接。
用tmux复用会话,减少反复建连
在Notebook实例上安装tmux,每个任务在独立的tmux会话里跑,断开SSH后重新连上,tmux attach恢复之前的会话,这样不仅连接数少,操作也顺手得多。
Q&A:Notebook实例ssh连接数限制与报错排查
服务端日志显示connection closed by remote host,但连接数没有超过10,为什么?
连接数上限不是唯一原因,服务端/var/log/secure里如果出现pam_unix(sshd:auth): authentication failure,属于密钥或密码错误;出现Connection reset by peer,多为网络防火墙或安全组拦截,连接数日志和认证失败日志能对上号,才能确定是超限问题。
修改MaxStartups,相当于放宽了一部分安全策略,会影响Notebook实例的稳定性吗?
风险集中在暴力破解防护上,MaxStartups调高后,未认证并发连接空间变大,攻击者可以同时挂更多尝试认证的会话,建议同时开启sshd的Fail2ban服务,或者设置云安全组只放行办公网IP,大多数使用场景下,把MaxStartups调到20到30之间不会对实例稳定性产生可感知的影响。
断开本地SSH客户端后,jupyter notebook ssh连接为什么还挂在那里?
本地客户端退出时,TCP断连消息没有及时送达服务端,服务端认为连接还活着,会话被保留到超时自动回收,使用ControlPersist配置后,退出终端也不会立即释放连接,这是故意保留的复用机制,如果确认不需要了,在服务端手工杀掉对应sshd进程即可释放。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/589429.html




