判断一台服务器能否通过SSH连接,最稳妥的办法是写一个脚本,同时探测端口开放情况和认证是否可行。脚本不仅能替你省去反复敲命令的麻烦,还能在服务器数量较多时一次性给出结论,下面直接进入正题,从原理到实操,给你一套能直接用的检测思路。
如何用脚本检测SSH端口连通状态
SSH服务默认监听在22端口,脚本检测的第一步永远是确认这个端口有没有开放,这里说的“连通状态”指网络层面能建立TCP连接,不涉及账号密码是否正确,端口通了,说明服务在跑;端口不通,后续认证测试也就没有意义。
用bash内置特性实现基础探测
在不安装额外工具的前提下,bash自身就能完成这项工作,核心思路是尝试建立一条TCP连接,根据连接结果判断端口状态,看这段代码:
#!/bin/bash
HOST="192.168.1.10"
PORT=22
TIMEOUT=3
if timeout $TIMEOUT bash -c "echo >/dev/tcp/$HOST/$PORT" 2>/dev/null; then
echo "端口开放,SSH服务可达"
else
echo "端口无响应,请检查防火墙或服务状态"
fi
这段脚本利用/dev/tcp这个特殊文件触发一次实际连接。timeout命令保证探测不会卡死,执行后,屏幕上会直接给出结论,如果你是第一次写这类脚本,建议先跑一遍看看效果。
借助nc命令做更精细的检测
不少服务器自带nc工具,它的优势在于能控制等待时间,并明确报告端口状态,命令格式如下:
nc -zv -w 3 192.168.1.10 22
-z表示只扫描不发送数据,-v显示详细过程,-w 3指定超时时间为3秒,把这条命令放进脚本,配合返回值判断即可,脚本里可以这样写:
#!/bin/bash
nc -zv -w 3 $1 22
if [ $? -eq 0 ]; then
echo "$1 可连接"
else
echo "$1 连接失败"
fi
这里的$1表示把服务器IP作为参数传给脚本,方便重复使用。
批量检查服务器SSH连通性脚本的编写思路
当手头有十几台甚至几十台服务器时,一台台去执行命令显然不现实,批量检测脚本的核心在于循环和并发,循环负责遍历IP列表,并发负责提升效率。
准备主机列表文件
先创建一个文本文件,每行写一个IP地址或域名,文件名随意,比如hosts.txt:
168.1.11
192.168.1.12
192.168.1.13
脚本读取这个文件,逐行进行探测,常见做法是用while read循环,这比for循环更能准确处理文件内容:
#!/bin/bash
while read ip; do
nc -zv -w 2 "$ip" 22 &> /dev/null
if [ $? -eq 0 ]; then
echo "$ip SSH可达"
else
echo "$ip SSH不可达"
fi
done < hosts.txt
这段脚本会依次检测文件里的每个地址,输出格式清晰,哪台通、哪台不通一眼就能看出。
提高批量检测速度的并发写法
串行检测的缺点是速度慢,服务器特别多时,时间成本会明显上升,改进思路是把检测任务放到后台并行执行,最后统一收集结果,业内专家指出,这种并行探测方式在中小规模运维场景中能显著缩短整体耗时。
#!/bin/bash
while read ip; do
(
if nc -zv -w 2 "$ip" 22 &> /dev/null; then
echo "$ip SSH可达"
else
echo "$ip SSH不可达"
fi
) &
done < hosts.txt
wait
&把每个检测动作丢到后台,wait等所有后台任务跑完再结束脚本,这个写法需要留意并发数量,如果机器特别多,可以分批处理,避免瞬时连接数过大。
加一层SSH认证检测更靠谱
端口通只能说明SSH服务在工作,不能证明你能登进去,要想同时验证认证是否可行,可以使用ssh命令自带的非交互模式,OpenSSH提供了BatchMode选项,它会禁止交互式密码输入,从而让脚本自动判断公钥认证是否有效,代码段如下:
ssh -o BatchMode=yes -o ConnectTimeout=3 -o StrictHostKeyChecking=no root@$ip "exit"
ConnectTimeout是连接超时时间,StrictHostKeyChecking=no避免首次连接时的指纹确认提示,这条命令如果执行成功,说明公钥认证可用;如果返回错误码255,则说明认证失败或网络不通,整合进批量检测脚本里,逻辑会更完整:
#!/bin/bash while read ip; do if ssh -o BatchMode=yes -o ConnectTimeout=3 -o StrictHostKeyChecking=no root@"$ip" "exit" &> /dev/null; then echo "$ip SSH可连接且认证成功" else echo "$ip SSH不可用" fi done < hosts.txt
不过要提醒一下:这种检测方式要求你已经配置好了密钥登录,如果平时习惯用密码登录,BatchMode=yes会导致所有机器都返回失败,需要根据实际情况调整。
脚本结果无法连接时的排查方法
脚本反馈“不可达”只说明检测失败,原因可能是网络、防火墙、服务异常等多种因素,按下面顺序逐一排查,能快速定位问题。
先分清是本机还是对端的问题
在运行检测脚本的机器上执行:
ping -c 3 目标IP
如果ping不通,大概率是网络层面不通,可以接着查路由或对端防火墙;如果ping得通但脚本仍报失败,那就要考虑对端防火墙是否拦截了22端口。
对端服务器上可以执行:
systemctl status sshd
或者:
ss -tlnp | grep 22
这两条命令能确认SSH服务是否在运行、有没有监听在正确的地址上。
防火墙规则要单独检查
云服务器通常涉及两层防火墙:安全组和系统内部防火墙,安全组的规则在云控制台里查看,系统防火墙在机器上查看。
以CentOS为例,检查命令是:
firewall-cmd --list-all
如果发现22端口没有被放行,执行:
firewall-cmd --permanent --add-port=22/tcp firewall-cmd --reload
Ubuntu系统则可能是ufw status,配合ufw allow 22/tcp来放行,检测脚本报失败,相当一部分情况出在防火墙配置上,而不是服务本身崩溃。
密钥和权限问题容易被忽略
如果端口通了但认证失败,报错信息里常见的是Permission denied (publickey),这种情况多数是密钥放错了位置或者权限过宽,记住两点:公钥要放在对端~/.ssh/authorized_keys里,私钥在本地的权限不能超过600,检查本地私钥权限用:
ls -l ~/.ssh/id_rsa
权限显示为-rw-------才是正确的,其他人可读就会导致客户端拒绝使用该密钥。
定时巡检脚本的落地实践
你可以把检测脚本放到crontab里,实现自动化巡检,比如每天早上九点执行一次:
0 9 /root/ssh_check.sh >> /var/log/ssh_check.log 2>&1
日志会记录每次检测的情况,后续排查问题时有据可查,推送功能也可以做进脚本里,比如检测到失败时向群里发条消息,不过这超出了纯SSH检测的范围,属于更大的自动化体系,后续可以基于检测结果再做扩展。
在现有检测逻辑下,脚本对服务器数量和检测频率都比较敏感,数量大、频率高的情况下,建议把并发数量限制住,可以在脚本里增加一个简单的计速逻辑,每轮最多同时检测50台,避免对源机器造成额外负担。
常见问题速查
脚本返回“连接成功”但登录服务器时仍然卡住?
端口成功只能证明TCP握手完成,不代表SSH握手正常,网络延迟高、DNS解析慢、服务端UseDNS yes配置都可能导致登录卡顿,在客户端执行ssh -v查看详细交互过程,能发现卡在哪个阶段。
检测脚本和直接执行ssh命令有什么区别?
脚本的价值在于批量、可复用、可定时,面对单台服务器时,直接执行ssh或nc完全没有问题,但机器数量一多,手敲命令就不现实,脚本可以把判断逻辑固定下来,每次跑一遍就出结果,避免临时决定造成的疏漏,大规模资产盘点或日常巡检时,数据一致性比手动敲出来的结果可靠得多。
检测主机上的脚本能否指定不同端口?
可以,只需把脚本里的22换成变量,比如从hosts.txt里读取“IP 端口”两列数据,对应修改nc或ssh命令的目标端口参数,修改后脚本依然保持原有的判断逻辑,却适用于非标准端口场景。
脚本检测SSH连接,本质上就是“端口探测 + 认证探测”的组合,先确认网络可达,再确认服务在跑,最后确认认证方式有效,三步走完就能给出一台服务器的准确结论,把这套逻辑固化到脚本里,日常排查和维护能省下不少重复操作的时间。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/764701.html





