☰
报错排查 05|SSH 连不上怎么办?从网络层到认证层的 12 步分层排查法
2026/10/3 6:51:06 网站建设 项目流程

我第一台云服务器的第一课,就是 SSH 连不上。

当时我的反应,跟大多数人一样:重启。重启完还是连不上,然后开始在网上乱搜,改sshd_config、重装 ssh、甚至重装了系统——折腾三个小时,最后发现是防火墙把 22 端口关了。

重启这个动作最坑的地方在于:它会把现场擦掉。你之后再想查「刚才到底为什么连不上」,日志已经翻篇了。

这篇我按「分层」来讲。SSH 连不上只有四种可能,按这四层一层层往下走,最多十分钟能定位。

〇、先花两分钟:SSH 连接的四层结构

把 SSH 想成打电话:

层打电话的对应出问题的表现
1. 网络层号码拨得通吗Connection timed out
2. 端口层对方有这条线吗Connection refused
3. 服务层有人接吗连上就断、卡在登录前
4. 认证层能确认身份吗Permission denied、Host key verification failed

注意报错信息的区别——它其实在告诉你卡在第几层:

  • Connection timed out:包发出去了,没人应答→ 第 1 或第 2 层(防火墙拦了、机器没开、IP 错了);

  • Connection refused:有人应答,但明确拒绝→ 机器活着,端口上没有服务在听(服务没起、端口改了);

  • 能连上但登不进去 → 第 4 层(认证)。

这一层区分能省掉一半时间:refused是「服务的问题」,timed out是「网络或被拦的问题」。

一、第 1~3 步:网络层(先证明机器活着)

第 1 步:ping 一下

$ ping -c 3 192.168.1.50 3 packets transmitted, 3 received, 0% packet loss

怎么读:有回包说明机器活着、网络通。没回包别急着下结论——很多云服务器和防火墙默认丢弃 ICMP,ping 不通但 SSH 是好的。所以 ping 只当辅助证据。

第 2 步:确认 IP 和端口没记错

这一步听着傻,但真的有人(包括我)连了半天发现连的是另一个环境的机器。确认:

# 本机 IP(在服务器上执行) $ ip -br addr ens33 UP 192.168.1.50/24

第 3 步:换一条路径试

从另一台机器试,或者用手机热点试。如果能从别的地方连上,问题就在你这条网络路径上(本地网络、公司出口、VPN 分流),不在服务器。

$ nc -vz 192.168.1.50 22 Connection to 192.168.1.50 22 port [tcp/ssh] succeeded!

怎么读:succeeded说明端口是开着的,可以直接跳到第 9 步去查认证。Connection refused说明机器活着但没服务在听——直接看第 4 步。

(nc是 netcat,Ubuntu 上可能需要sudo apt install netcat-openbsd。不方便装的话,第 5 步的ss命令也能起到类似作用。)

二、第 4~6 步:端口层(服务在不在)

第 4 步:服务起了吗?注意 Ubuntu 上它叫ssh不叫sshd

$ systemctl status ssh ● ssh.service - OpenBSD Secure Shell server Loaded: loaded (/usr/lib/systemd/system/ssh.service; enabled; preset: enabled) Active: active (running) since Sat 2026-09-26 09:12:03 CST; 1 day 3h ago

怎么读:Active: active (running)才算正常。

⚠️ 这一步有个大坑:Ubuntu / Debian 系的服务名叫ssh,RHEL / CentOS 系叫sshd。在 Ubuntu 上敲systemctl status sshd会告诉你「找不到这个单元」,很容易被误判成「服务没装」。

更绕的是,桌面版上你搜ssh也搜不到它——因为服务端压根没装,能搜出来的全是别的东西:

$ systemctl list-unit-files | grep -iE 'ssh|sshd' sssd-ssh.service indirect enabled sssd-ssh.socket enabled enabled ssh-access.target static -

怎么读:sssd-ssh是「SSSD(企业账号认证服务)的一个组件」,ssh-access.target是个目标单元——三个都不是 SSH 服务端。搜不到ssh.service,就是没装。

服务没起就拉起来:

sudo systemctl start ssh && sudo systemctl enable ssh

(enable是设开机自启——服务「起过」和「会自动起」是两件事,这个坑在Linux避坑 02里详细讲过。)

第 5 步:服务端到底装了没有

这是最容易被忽略的一种情况,而且在 Ubuntu 桌面版上是默认状态。

Ubuntu 桌面版默认不安装 OpenSSH 服务端(只有客户端)。也就是说:

  • 你能从这台机器ssh去连别人(客户端装了);

  • 但别人连不进来——因为压根没有服务端。

$ dpkg -l | grep -E 'openssh|ssh' ii libssh2-1t64:amd64 1.11.1-1ubuntu0.26.04.4 amd64 SSH2 client-side library ii openssh-client 1:10.2p1-2ubuntu3.6 amd64 secure shell (SSH) client ​ $ ss -tlnp | grep :22 (无输出)

怎么读(这是我在自己那台 26.04.1 上跑的真实结果):

  • dpkg -l里只有openssh-client(客户端),没有openssh-server(服务端)→ 你能连出去,别人连不进来;

  • ss -tlnp里没有任何:22→ 没有程序在监听 22 端口。

两条合起来,就是「服务端不存在」的铁证。

(顺便留意第一行那个libssh2-1t64——它是客户端用的库,名字里有 ssh,但不是服务端,别被带跑。)

要装:

sudo apt install openssh-server

第 6 步:服务在听,但只听本机

有些配置(尤其容器镜像、加固过的系统)会把监听地址限制成127.0.0.1——只接受本机连接,外面永远连不上。

$ ss -tlnp | grep :22 LISTEN 0 128 127.0.0.1:22 0.0.0.0:* users:(("sshd",pid=812,fd=3))

怎么读:关键看:22前面那一段地址。

显示含义
0.0.0.0:22所有网卡都听——外部可以连(正确状态)
[::]:22同上,走 IPv6
127.0.0.1:22只听本机——外部连不上,问题就在这

对应的配置在/etc/ssh/sshd_config里的ListenAddress。

对照一下就知道「地址」这一列有多关键——这是我机器上全部在监听的端口,一个 22 都没有:

$ ss -tlnp LISTEN 0 4096 127.0.0.1:631 0.0.0.0:* ← 打印服务,只听本机 LISTEN 0 50 0.0.0.0:445 0.0.0.0:* ← Samba,所有网卡都听 LISTEN 0 50 0.0.0.0:139 0.0.0.0:* ← Samba,同上 LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:* ← systemd-resolved,只听本机

怎么读:0.0.0.0:445= 外面连得进来;127.0.0.1:631= 只有本机能连。同样是「在监听」,地址不同,含义完全相反——这就是第 6 步要教你的判断。

三、第 7~8 步:防火墙(最常见的元凶)

第 7 步:本机防火墙

$ sudo ufw status 状态:不活动

怎么读:不活动= ufw 没在拦(此时去看看 nftables / iptables 有没有别的规则);活动就要看规则里有没有放行 22:

⚠️ 这里有个特别容易误判的地方,我在自己机器上就撞到了:

$ systemctl is-active ufw active $ systemctl show -p ActiveState -p SubState -p Type -p RemainAfterExit ufw.service ActiveState=active SubState=exited Type=oneshot RemainAfterExit=yes

看到active就以为防火墙开着?不是。把后一条命令的四行连起来读就懂了:Type=oneshot(跑一遍就退)+RemainAfterExit=yes(跑完别退,停在 active 上)+SubState=exited(进程其实已经结束了)——这个active只表示「启动脚本执行过」,跟「防火墙有没有启用」是两件事。

那真正的开关在哪?在这个文件里:

$ cat /etc/ufw/ufw.conf ENABLED=no LOGLEVEL=low

ENABLED=no—— 这才是权威答案,和sudo ufw status报的「不活动」完全一致。

判断防火墙,永远以sudo ufw status的输出为准,别看systemctl is-active。

顺便说下verbose版长什么样——没启用时它只回一句(我机器上就是这样):

$ sudo ufw status verbose 状态:不活动

启用之后才会列出规则表,格式如下(这台机器上没启用,所以下面是格式参考):

状态:活动 日志记录:on (low) 默认:deny (incoming), allow (outgoing), disabled (routed) 新配置文件:skip To Action From -- ------ ---- 22/tcp ALLOW Anywhere

RHEL 系用firewall-cmd --list-all,看ports或services里有没有ssh。

⚠️第一句提醒:如果你正通过 SSH 连着服务器,在敲sudo ufw enable之前,先确认 22 端口已经放行:

sudo ufw allow 22/tcp # 先放行 sudo ufw enable # 再启用

顺序反了,你会当场把自己锁在门外——这个教训值得单独记一条。

第 8 步:云安全组 / 机房设备

如果你用的是云服务器,安全组是最常见的拦路虎,而且在服务器里怎么查都查不出来——因为规则在云平台的控制台上。

排查方式:打开云控制台,看这台实例绑定的安全组入方向规则里有没有放行 22(很多默认策略只放 80/443,或者只允许特定来源 IP)。

不要把「服务器内部一切正常」等同于「网络是通的」——云安全组、机房 ACL、公司出口设备,都在你看不见的地方。

四、第 9~12 步:认证层(能连上,但登不进去)

到这里连接已经建立,问题在身份认证。

第 9 步:看服务端的拒绝日志

$ sudo journalctl -u ssh -n 30 Sep 27 11:02:31 host sshd[2311]: Failed password for alice from 192.168.1.9 port 51234 ssh2 Sep 27 11:02:33 host sshd[2311]: Connection closed by authenticating user alice 192.168.1.9 port 51234 [preauth]

怎么读:Failed password= 密码不对;Connection closed by authenticating user ... [preauth]= 认证阶段被断开(多半是密钥或配置问题);如果什么都没有,说明请求根本没到达服务(回到第 7、8 步)。

日志位置:Ubuntu 在 journald(上面这条命令),也能在/var/log/auth.log里找到;RHEL 系在/var/log/secure。

第 10 步:密钥登录失败?九成是权限问题

SSH 对密钥文件的权限极其挑剔——只要它觉得别人有可能读到你的私钥,就直接拒绝使用。

服务端的检查清单(下面是我机器上的真实状态):

$ ls -ld ~/.ssh ~/.ssh/authorized_keys drwx------ 2 rainbow rainbow 4096 Sep 16 15:24 /home/rainbow/.ssh -rw------- 1 rainbow rainbow 0 Sep 16 15:24 /home/rainbow/.ssh/authorized_keys

怎么读:drwx------(700)和-rw-------(600)是对的,权限没问题。但注意那个0——文件大小是 0,里面一个公钥都没写。这种「文件在、内容空」的状态最容易被忽略:登录当然失败,而日志里只会干巴巴地说一句「认证失败」。

怎么读:.ssh目录必须是700(drwx------),authorized_keys必须是600(-rw-------),而且属主必须是你自己。多一个组读权限,SSH 都可能不认。

一条命令修好:

chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys && chown -R $USER:$USER ~/.ssh

还有一条隐蔽的:家目录本身不能是 777。/home/alice权限过于宽松时,SSH 同样会拒绝——因为它认为别人可以替换你的.ssh。

第 11 步:服务端配置在"故意"拦你

/etc/ssh/sshd_config里几个常见开关:

配置项效果
PermitRootLogin noroot 不允许直接登录(默认值,很多人不知道)
PasswordAuthentication no禁用密码,只认密钥
AllowUsers alice白名单,只有列出的用户能登
DenyUsers黑名单
MaxAuthTries 3认证失败 3 次就断开
Port 2222改了端口,客户端要用-p 2222

改完配置一定要做两件事:

sudo sshd -t # 先检查语法(错了它会告诉你哪一行) sudo systemctl reload ssh # 再让服务重读配置

sshd -t这步千万别省。配置写错了直接 reload 服务,结果服务起不来——而你正通过 SSH 连着,下一次连接就再也进不去了。

第 12 步:主机密钥变了(Host key verification failed)

WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!

这不是故障,是安全机制在工作:你以前连过这台机器,它当时的「指纹」记录在~/.ssh/known_hosts里;现在指纹变了,客户端就报警——因为它无法区分「服务器重装了」和「有人在中间冒充服务器」。

服务器重装过、或者你换了台机器复用同一个 IP,都会触发这个警告。

确认是自己的机器变了,清掉旧记录即可:

ssh-keygen -R 192.168.1.50

反过来说,如果你没重装过系统却看到这个警告,别急着清——先确认机器是不是被人动过。

顺便提一个 2026 年的新情况:新版 OpenSSH 已经不再支持 DSA 密钥(我机器上是OpenSSH_10.2p1),所以那些老教程里ssh-keygen -t dsa的做法现在会直接被拒。现在该用的是ed25519:

ssh-keygen -t ed25519 -C "备注信息"

五、客户端自查:三条命令看清"我这里发生了什么"

如果服务器那边一切正常,用客户端的详细模式看:

$ ssh -v alice@192.168.1.50 debug1: Connecting to 192.168.1.50 [192.168.1.50] port 22. debug1: Connection established. debug1: Authentications that can continue: publickey,password

怎么读:-v会把每一步都打出来。

  • 卡在Connecting to ...不动 → 网络层(第 1~3 步);

  • Connection established之后卡住 → 服务层;

  • Authentications that can continue:这行很有用——它列出服务端允许的认证方式。如果里面有publickey但你只有密码,就知道该配密钥了。

嫌不够详细可以叠-vvv。

速查表(文末收藏版)

先分清报错 → timed out=网络/防火墙 refused=端口没服务 机器活着吗 → ping -c 3 IP 端口通吗 → nc -vz IP 22 服务状态(Ubuntu) → systemctl status ssh ← 服务名是 ssh,不是 sshd 服务状态(RHEL 系) → systemctl status sshd 服务端装了吗 → dpkg -l | grep -E 'openssh|ssh' (桌面版默认只有 -client) 别用这个判断防火墙 → systemctl is-active ufw ← active 不代表防火墙开着(它是 oneshot) 防火墙真正的开关 → /etc/ufw/ufw.conf 里的 ENABLED= 谁在听 22 → ss -tlnp | grep :22 (看是 0.0.0.0 还是 127.0.0.1) 本机防火墙 → sudo ufw status verbose (RHEL:firewall-cmd --list-all) 启用防火墙前先放行 → sudo ufw allow 22/tcp && sudo ufw enable 云服务器 → 控制台看安全组入方向规则 服务端拒绝日志 → sudo journalctl -u ssh -n 30 密钥权限 → chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys 配置语法检查 → sudo sshd -t 重读配置(不断连接) → sudo systemctl reload ssh 主机密钥变了 → ssh-keygen -R IP 客户端详细排查 → ssh -v 用户名@IP 生成新密钥(用这个) → ssh-keygen -t ed25519 -C "备注"

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询