服务器SSH连接不上怎么办

结论: 服务器 SSH 连接不上按六个层次排查:网络层(ping、nc -zv IP 22)→ 安全组/防火墙(云平台安全组与 ufw/firewalld 是否放行 22)→ 服务状态(systemctl status sshd 是否在跑)→ 配置错误(Port、PermitRootLogin、PasswordAuthentication)→ 密钥权限(chmod 600)→ 日志定位(journalctl -u sshd、/var/log/secure)。90% 的问题在前三层,按此顺序 10 分钟内可定位。

SSH 连不上是运维遇到频率最高的故障,也是最容易被慌乱处理的故障。它的难点不在技术深度,而在于报错信息往往指向不清:Connection timed out 可能是安全组,Connection refused 可能是服务没起,而 Permission denied (publickey) 才轮到密钥问题。很多人一上来就重装系统,代价远大于收益。

本文给出的是一条从外到内、从粗到细的标准化排查链路。无论你用的是 Ubuntu 24.04 LTS、Debian 12、Rocky Linux 9 还是 CentOS 7,这套顺序都适用——因为 SSH 连接的建立过程本身就是分层的,每一层失败都会阻断后续层。

先看报错:六种提示对应的故障定位

结论:不同的报错文本直接指向不同的故障层,先读懂报错能省掉一半排查时间。 下面这张表是本文的核心,建议直接对照执行。

报错信息最可能原因排查层级
Connection timed out安全组/防火墙丢包、IP 错误、路由不通网络层 + 防火墙层
Connection refused22 端口无进程监听,sshd 未启动或改了端口服务层 + 配置层
Permission denied (publickey)密钥不匹配、authorized_keys 未生效认证层
Permission denied (publickey,password)用户被 AllowUsers/DenyUsers 拒绝,或密码错误认证层 + 配置层
No route to host本机网关/路由问题,或目标 IP 不存在网络层
REMOTE HOST IDENTIFICATION HAS CHANGED服务器重装密钥变更,本地 known_hosts 冲突客户端层
Permission too open / bad permissions私钥或 authorized_keys 权限过宽认证层
卡住无任何输出中间网络丢包、ICMP 被禁、运营商拦截网络层

SSH 连接建立的完整过程

理解这五步,你就明白为什么要按这个顺序排查:

  1. TCP 三次握手:客户端向 IP:22 发起连接。失败 → 超时或拒绝。
  2. 协议版本协商:服务端返回 SSH 版本串。失败 → 协议不匹配。
  3. 算法与密钥交换:协商加密算法。失败 → 客户端与服务端算法无交集(老客户端连新服务器常见)。
  4. 用户认证:公钥比对或密码校验。失败 → Permission denied。
  5. 会话建立:分配伪终端,登录成功。

第 1 层:网络连通性排查

结论:先用 ping 判断主机是否存活,再用 nc -zv 精确测试 22 端口是否可达,两者含义完全不同。 ping 不通不代表机器挂了(很多服务器禁用 ICMP),而 ping 通但 22 端口不通才是真正需要处理的信号。

bash
# 1. 基础连通性测试(ICMP,可能被禁用,仅作参考)
ping -c 4 <你的公网IP>

# 2. 精确测试 22 端口是否开放(-z 只扫描不发送数据,-v 显示详情,-w 超时秒数)
nc -zv -w 3 <你的公网IP> 22
# 成功输出:Connection to xxx 22 port [tcp/ssh] succeeded!
# 失败输出:Connection timed out 或 Connection refused

# 3. telnet 备选方案(没有 nc 时)
telnet <你的公网IP> 22
# 成功会显示 SSH-2.0-OpenSSH_9.6 之类的版本串

# 4. 追踪路由,定位在哪一跳丢包
traceroute -T -p 22 <你的公网IP>
# Windows 上用 tracert

# 5. 检查本机的 DNS 与网关是否正常
ip route show
cat /etc/resolv.conf

如果 ping 不通但 nc -zv 成功,说明 SSH 可用,只是 ICMP 被禁,这不是故障。如果两者都不通,继续下一步。

bash
# 从服务器侧反向检查出网是否正常(需要能通过控制台登录)
curl -s -o /dev/null -w "%{http_code}\n" https://www.baidu.com
ip addr show          # 确认网卡已拿到 IP
ip link show          # 确认网卡处于 UP 状态

第 2 层:安全组与系统防火墙

结论:云服务器的端口放行有"两道门"——云平台安全组和系统防火墙(ufw/firewalld),必须同时放行才有效。 这是 SSH 连不上最常见的原因,尤其是刚重装系统或更换IP之后。

云平台安全组检查清单

登录云控制台 → 实例详情 → 安全组,确认入站规则包含:

协议类型端口范围授权对象说明
TCP22你的办公网出口 IP/32生产环境强烈建议限定来源
TCP220.0.0.0/0临时调试用,长期开放有风险
ICMP-0.0.0.0/0允许 ping,便于排错
TCP80 / 4430.0.0.0/0Web 服务端口
注意:如果你改过 SSH 端口(如 2222),安全组必须放行新端口。另外部分厂商的安全组区分"入站"与"出站",SSH 只需放行入站方向即可。

系统防火墙检查与放行

bash
# ===== Ubuntu 24.04 / Debian 12:ufw =====
sudo ufw status verbose              # 查看规则与默认策略
sudo ufw allow 22/tcp comment 'SSH'  # 放行 SSH
sudo ufw reload

# 若怀疑是 ufw 拦截,临时关闭验证(验证后务必重新开启)
sudo ufw disable
# 确认是防火墙问题后再开启并正确放行
sudo ufw enable

# ===== Rocky Linux 9 / AlmaLinux 9:firewalld =====
sudo firewall-cmd --state
sudo firewall-cmd --list-all
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --permanent --add-port=2222/tcp   # 自定义端口写法
sudo firewall-cmd --reload

# ===== CentOS 7:iptables / firewalld =====
sudo iptables -L INPUT -n -v | grep -E "22|ACCEPT|DROP"
sudo systemctl status firewalld

# ===== 通用:直接看内核 netfilter 规则数 =====
sudo iptables -S | head -50

还有一种容易被忽略的情况:云厂商的"网络 ACL"或"子网 ACL"。它位于安全组之外,属于无状态访问控制,忘记配置回包规则会导致单向不通。

第 3 层:sshd 服务状态与端口监听

结论:确认 sshd 进程在运行且正在监听正确端口。服务没启动表现为 Connection refused,这是与"超时"最本质的区别。

bash
# 通过控制台 VNC 登录后检查服务状态(Ubuntu / Debian 服务名是 ssh)
sudo systemctl status ssh --no-pager
# Rocky Linux 9 / CentOS 7 服务名是 sshd
sudo systemctl status sshd --no-pager

# 启动并设置开机自启
sudo systemctl enable --now ssh        # Ubuntu / Debian
# sudo systemctl enable --now sshd     # Rocky / CentOS

# 确认端口监听情况(重点看 Local Address 列)
sudo ss -lntup | grep -E ':22|sshd'
# 正常输出示例:LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1234,fd=3))

# 如果 sshd 没监听,检查是否装了 openssh-server 而不仅是 client
sudo apt list --installed | grep openssh
sudo apt install -y openssh-server     # Ubuntu / Debian
# sudo dnf install -y openssh-server   # Rocky Linux 9

抢救:sshd 起不来的常见情形

如果 systemctl start ssh 失败,按顺序做三件事:

bash
# 1. 前台运行 sshd 直接看报错(最准确的失败原因)
sudo /usr/sbin/sshd -D -d -p 2222
# -d 表示 debug 模式输出到终端,常见的错误是配置文件指令写错或缺失 host key

# 2. 校验配置文件语法
sudo sshd -t
# 有错误会精确显示行号,如:/etc/ssh/sshd_config line 45: Bad configuration option

# 3. 若提示 host key 缺失,重新生成
sudo ssh-keygen -A
sudo systemctl restart ssh

第 4 层:配置文件错误排查

结论:五大配置项最容易导致登录失败——Port、PermitRootLogin、PasswordAuthentication、AllowUsers、ListenAddress。 修改前必须备份,sshd -t 校验通过再重启。

bash
# 备份当前配置
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%F)

# 查看实际生效的配置(去掉注释行)
sudo sshd -T | grep -E "^(port|permitrootlogin|passwordauthentication|pubkeyauthentication|allowusers|denyusers|listenaddress)"

# 编辑主配置文件
sudo vim /etc/ssh/sshd_config

典型故障项速查:

bash
# 场景:想用密钥登录却被拒绝
PubkeyAuthentication yes          # 必须是 yes
AuthorizedKeysFile .ssh/authorized_keys

# 场景:想用密码登录但提示 publickey-only
PasswordAuthentication yes        # 需要临时开启时用

# 场景:root 登录总失败
PermitRootLogin yes               # 或 prohibit-password(允许密钥root登录)

# 场景:换了端口后连不上
Port 2222                         # 记得同步改防火墙与安全组

# 场景:某用户怎么都登不进
AllowUsers opsuser admin          # 白名单里必须包含你的用户名,注意 Linux 用户名大小写敏感
DenyUsers test guest

# 场景:只允许内网 SSH
ListenAddress 10.0.0.5            # 绑定内网地址,公网将无法直连

第 5 层:密钥与文件权限

结论:Permission denied (publickey) 的头号原因是文件权限不正确。OpenSSH 要求私钥 600、~/.ssh 目录 700、authorized_keys 600,且所有者必须是登录用户本人。

bash
# 在服务器上修正权限(假设用户为 opsuser,家目录 /home/opsuser)
sudo chown -R opsuser:opsuser /home/opsuser/.ssh
chmod 700 /home/opsuser/.ssh
chmod 600 /home/opsuser/.ssh/authorized_keys
chmod 600 /home/opsuser/.ssh/id_rsa          # 若该目录放了私钥

# 家目录本身权限也不能过宽
chmod 755 /home/opsuser

# 检查公钥内容是否完整(一行一个密钥,不能有换行断裂)
wc -l /home/opsuser/.ssh/authorized_keys
cat /home/opsuser/.ssh/authorized_keys

# 追加新公钥时务必用 >> 追加而非 > 覆盖
cat >> /home/opsuser/.ssh/authorized_keys <<'EOF'
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExampleKeyDataHere ops@example.com
EOF

客户端侧的私钥权限同样重要:

bash
# 本地修正私钥权限
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
chmod 600 ~/.ssh/config

# 修复 known_hosts 冲突(服务器重装或换 IP 后常见)
ssh-keygen -R <服务器IP>
# 重新连接并接受新指纹

# 指定私钥强制连接测试(-v 显示详细握手过程)
ssh -v -i ~/.ssh/id_ed25519 -p 22 opsuser@<服务器IP>

第 6 层:日志精确定位

结论:前五层都查不出问题时,日志是唯一的真相来源。Ubuntu/Debian 看 /var/log/auth.log,Rocky/CentOS 看 /var/log/secure,优先用 journalctl -u sshd 实时跟踪。

bash
# ===== systemd 系统统一入口(推荐)=====
sudo journalctl -u ssh -n 100 --no-pager       # Ubuntu / Debian
sudo journalctl -u sshd -n 100 --no-pager      # Rocky / CentOS

# 实时跟踪新日志,一边看一边让同事重新连接
sudo journalctl -u sshd -f

# ===== 传统日志文件 =====
sudo tail -100 /var/log/auth.log               # Ubuntu 24.04 / Debian 12
sudo tail -100 /var/log/secure                 # Rocky Linux 9 / CentOS 7

# 过滤认证失败记录
sudo grep "Failed password" /var/log/auth.log | tail -20
sudo grep "Invalid user" /var/log/auth.log | awk '{print $8}' | sort | uniq -c | sort -nr

# 查看被 SELinux 拦截的审计信息(Rocky Linux 9 改 SSH 端口必看)
sudo ausearch -m AVC -ts recent
sudo sealert -a /var/log/audit/audit.log

Rocky Linux 9 修改 SSH 端口后连不上,几乎都是 SELinux 没放行,解决办法:

bash
# 查询 SELinux 允许的 SSH 端口
sudo semanage port -l | grep ssh

# 添加新端口到 SELinux 策略
sudo semanage port -a -t ssh_port_t -p tcp 2222

# 若提示已存在则改用修改
sudo semanage port -m -t ssh_port_t -p tcp 2222

# 放行后重启服务
sudo systemctl restart sshd