常见SSH错误排查:连接被拒绝与权限拒绝
通过掌握诊断“连接被拒绝”和“权限拒绝”错误,解决令人沮丧的SSH连接问题。本实用指南详细介绍了系统化的排查步骤,包括验证sshd服务状态、调试防火墙规则(UFW)、纠正基于密钥的身份验证权限以及解读服务器身份验证日志,以实现快速解决。
常见SSH错误排查:连接被拒绝与权限拒绝
当你能区分传输问题和身份验证问题时,SSH故障更容易修复。连接被拒绝意味着你的SSH客户端到达了主机,但该端口上没有接受TCP连接的服务。权限拒绝意味着SSH服务器已响应,但拒绝了你的登录。尽管两者都感觉像是“我无法登录”,但它们是不同的事件。
在更改服务器设置时,请保持一个活动的SSH会话。大多数痛苦的SSH中断发生在有人编辑/etc/ssh/sshd_config、重启服务、断开连接,然后才发现新配置阻止了所有登录路径。
理解错误:拒绝 vs. 拒绝
在更改任何内容之前,请仔细阅读确切的客户端消息:
连接被拒绝:主机主动拒绝了TCP连接,通常是因为sshd没有在该端口上监听,或者防火墙正在拒绝它。连接超时:数据包被丢弃或网络路径中断。这更可能是防火墙、路由、VPN、安全组或错误的IP地址导致的。权限拒绝(公钥):服务器可达,但未接受你的密钥。权限拒绝(公钥,密码):服务器尝试了一种或多种身份验证方法并拒绝了它们。主机密钥验证失败:你的客户端不信任当前为该主机名或IP地址呈现的服务器身份。
第一部分:排查连接被拒绝
ssh: connect to host example port 22: Connection refused 通常指向远程主机或端口。机器已响应,但SSH未在该处接受连接。
1. 验证SSH守护进程(sshd)状态
拒绝的最常见原因是SSH服务器进程未运行或已崩溃。
可操作步骤(在远程服务器上):
在许多Linux发行版中,服务称为sshd;在Debian和Ubuntu上,通常称为ssh。尝试你的系统使用的那个:
systemctl status sshd
systemctl status ssh
如果服务处于非活动或失败状态,请启动它:
sudo systemctl start sshd
sudo systemctl enable sshd
如果sshd在配置更改后无法启动,请验证配置:
sudo sshd -t
该命令是在重启SSH之前可以运行的最安全的检查之一。
2. 检查监听端口和配置
默认情况下,SSH使用TCP端口22,但许多服务器使用不同的端口。如果服务器监听2222,客户端命令必须包含它:
ssh -p 2222 [email protected]
A. 查看sshd_config
检查SSH配置文件,通常位于/etc/ssh/sshd_config。查找Port指令:
# /etc/ssh/sshd_config 示例
Port 2222 # 如果不是22,则需要在客户端指定
编辑文件后,在重新加载之前运行sudo sshd -t。如果语法有效,则重新加载或重启服务。重新加载通常破坏性较小:
sudo systemctl reload sshd
B. 验证监听套接字
使用ss确认sshd正在监听:
sudo ss -tuln | grep 22
# 预期输出显示监听状态:
# LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
如果SSH仅监听127.0.0.1:22,则远程客户端无法连接。如果它监听0.0.0.0:22或特定的私有接口地址,则根据防火墙规则,远程访问可能可行。
3. 防火墙和网络检查
丢弃数据包的防火墙通常会导致超时。拒绝数据包的防火墙可能导致拒绝。检查主机防火墙和主机外部的任何网络防火墙。
常见防火墙命令(Ubuntu/Debian上的UFW):
确保允许SSH流量:
# 检查当前状态
sudo ufw status
# 允许默认端口22的流量
sudo ufw allow ssh
# 或按端口号
sudo ufw allow 22/tcp
# 重新加载防火墙规则
sudo ufw reload
云安全组、网络ACL、VPN路由和办公室防火墙可以在流量到达服务器之前阻止SSH。如果sshd正在监听且主机防火墙已打开,请从同一私有网络内的机器进行测试。这可以告诉你问题是服务器本地问题还是外部路径上的问题。
第二部分:排查权限拒绝
如果服务器回复权限拒绝,则网络路径正常工作。专注于用户名、允许的身份验证方法、密钥、账户状态和文件权限。
1. 检查用户名和密码
这是最简单的检查,但经常被忽视:
- 用户名: 云镜像通常使用特定用户,如
ubuntu、ec2-user、admin、debian或rocky。root可能被禁用。 - 密码: 如果启用了密码身份验证,请检查拼写错误、账户锁定、密码过期和PAM规则。
- 端口和主机: 大量身份验证失败是由于连接到恰好运行SSH的错误服务器引起的。
客户端检查: 要查看详细的调试输出,请使用详细标志运行客户端:
ssh -vvv user@hostname
此输出将清楚地显示客户端尝试了哪些身份验证方法以及服务器拒绝了哪些。
2. 基于密钥的身份验证失败
当客户端提供错误的私钥、服务器没有匹配的公钥、权限过于开放或sshd_config阻止登录时,密钥身份验证会失败。
A. .ssh目录权限不正确
出于安全原因,SSH对文件权限非常严格。如果权限过于开放,服务器将完全忽略密钥文件。
在远程服务器上(修复权限):
# 用户主目录权限通常没问题,但检查.ssh文件夹
chmod 700 ~/.ssh
# authorized_keys文件必须只能由所有者写入
chmod 600 ~/.ssh/authorized_keys
还要检查所有权:
chown -R "$USER:$USER" ~/.ssh
在服务器上,StrictModes通常已启用。如果主目录、.ssh目录或authorized_keys文件可被其他用户写入,sshd可能会忽略该密钥。
B. 密钥不存在或格式不正确
确保公钥位于目标用户的~/.ssh/authorized_keys中,每行一个密钥。私钥保留在客户端。不要将私钥粘贴到authorized_keys中。
从客户端,在调试时强制使用特定密钥:
ssh -i ~/.ssh/id_ed25519 -vvv [email protected]
在详细输出中,查找显示提供了哪些密钥以及服务器接受或拒绝它们的原因的行。
C. 服务器配置禁用密钥
检查服务器上的/etc/ssh/sshd_config以确保允许密钥身份验证:
PubkeyAuthentication yes
# 如果你依赖密码,请确保密码身份验证未被禁用
PasswordAuthentication yes
如果存在AllowUsers、AllowGroups、DenyUsers或DenyGroups,它们可能会覆盖看似有效的密钥设置。具有正确密钥的用户仍可能被这些指令阻止。
3. 服务器端日志调查
服务器日志通常会告诉你拒绝的真正原因。在服务器上保持一个终端打开,并在从客户端尝试登录时观察日志。
常见日志位置:
- Debian/Ubuntu:
/var/log/auth.log - RHEL/CentOS/Fedora:
/var/log/secure
使用grep过滤最近的连接尝试:
# 在RHEL/CentOS系统上
sudo grep 'Failed password' /var/log/secure
# 或查找常规SSH活动
sudo tail -f /var/log/secure
在使用systemd日志的系统上,这通常更容易:
sudo journalctl -u sshd -f
sudo journalctl -u ssh -f
日志消息可能显示“bad ownership or modes”、“user not allowed”、“invalid user”、“authentication refused”或PAM账户失败。这些消息比仅从客户端猜测更可靠。
主机密钥验证失败
主机密钥验证失败与错误的密码或密钥不同。这意味着你的客户端保存了该主机名或IP的服务器身份,而服务器现在呈现了不同的身份。这可能在重建、IP重用、负载均衡器更改或真正的中间人攻击风险后发生。
不要在生产环境中盲目删除警告。通过云控制台、配置管理或现有的可信渠道验证服务器指纹。一旦你确定更改是预期的,删除旧条目:
ssh-keygen -R example.com
ssh-keygen -R 192.0.2.10
然后重新连接,并且仅当指纹与你期望的匹配时才接受新的主机密钥。
可靠SSH访问的最佳实践总结
- 使用密钥对: 仅在第二个会话中测试密钥访问后,才禁用密码身份验证。
- 限制谁可以登录: 在适当时使用
AllowUsers或AllowGroups,但记录下来,以便未来的操作员不会追逐错误的权限问题。 - 使用
PermitRootLogin no: 优先使用具有sudo权限的普通用户。 - 备份配置: 在更改
/etc/ssh/sshd_config之前,复制它:
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%F)
```
5. 重新加载前验证: 运行sudo sshd -t。
6. 保留紧急通道: 对于云服务器,如果SSH中断,请知道如何使用串行控制台、救援模式、实例连接功能或配置管理。
SSH故障排查的最短路径是:识别确切的错误,证明服务器是否在监听,证明网络路径是否到达该端口,然后读取服务器日志以了解身份验证失败。猜测通常比按顺序运行这些检查花费的时间更长。