记一次 OpenSSH 连接问题的排查记录

2025-11-18 21:01:00
丁国栋
原创 3
摘要:本文记录一次 SSH 无法连接的排查记录。

背景:今天有个服务器做了下架处理,里面的数据需要备份到备份服务器。打算使用 rsync 将数据同步到备份服务器,结果测试发现无法建立 SSH 连接。

现在有机器A和机器B两个 ubuntu linux(版本号都是 20.04.6 LTS (Focal Fossa) ),在机器A上ssh机器B,机器A提示 root@10.0.7.223: Permission denied (publickey) ,如何排查这个问题?

排查步骤

这个错误表示 SSH 公钥认证失败。

1. 检查基础连接性

当我读到 AI 的这个回答时,我起初感到有点好笑,网络是通的、端口号也是通的,但后来找到原因后发现这一步骤确实也是有用的一个验证和排查方法。

# 确认网络可达性和端口开放
ping 10.0.7.223
telnet 10.0.7.223 22
nc -zv 10.0.7.223 22

2. 检查机器B的SSH服务配置

在机器B上检查:

# 查看SSH服务状态: 这一步骤的目的一方面是确认服务在运行,另一方面,是要我们检查和确认SSH服务监听的端口号,例如:Server listening on 0.0.0.0 port 22
sudo systemctl status ssh
# 检查SSH配置
sudo grep -E "(PermitRootLogin|PubkeyAuthentication|PasswordAuthentication)" /etc/ssh/sshd_config
# 重启SSH服务(修改配置后)
sudo systemctl restart ssh

关键配置项应该为:

PermitRootLogin yes
PubkeyAuthentication yes

3. 检查机器A的密钥文件

在机器A上检查:

# 检查密钥文件权限和存在性
ls -la ~/.ssh/
# 正确的权限应该是:
# -rw------- id_rsa (私钥)
# -rw-r--r-- id_rsa.pub (公钥)

4. 检查公钥是否正确添加到机器B

在机器B上确认:

# 检查authorized_keys文件
sudo cat /root/.ssh/authorized_keys
# 检查文件权限
sudo ls -la /root/.ssh/authorized_keys
# 应该为 -rw------- 或 -rw-r--r--

5. 使用详细模式诊断

在机器A上使用详细输出:

ssh -v root@10.0.7.223
# 或更详细的调试
ssh -vvv root@10.0.7.223

这个方法我也使用过,但在发现根本原因之前,它总是提示 root@10.0.7.223: Permission denied (publickey).

6. 临时启用密码登录测试

当我读到 AI 的这个回答时,我起初感到有点好笑,为什么我要启用密码登录呢。后来当我找到问题时,发现这一步骤确实也是有用的一个验证和排查方法。

如果上述步骤都无法解决,临时在机器B上启用密码登录:

# 修改/etc/ssh/sshd_config
PasswordAuthentication yes
# 重启SSH服务
sudo systemctl restart ssh

常见解决方案

修复文件权限

在机器A上:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_rsa
chmod 644 ~/.ssh/id_rsa.pub

或者执行:

find ~/.ssh/ -type f -exec chmod 600 {} \;

在机器B上:

sudo chmod 700 /root/.ssh
sudo chmod 600 /root/.ssh/authorized_keys

重新生成并添加密钥

# 在机器A上生成新密钥
ssh-keygen -t rsa -b 4096
# 复制公钥到机器B
ssh-copy-id root@10.0.7.223

查看日志

在 Ubuntu 20.04.6 LTS 上查看 SSH 连接日志的方法如下:

1. 查看系统日志(主要方式)

查看 SSH 服务端日志(机器B)

# 查看最近的SSH日志
sudo tail -f /var/log/auth.log
# 查看特定时间的SSH日志
sudo grep "sshd" /var/log/auth.log
# 查看包含IP地址的SSH连接记录
sudo grep "sshd.*10.0." /var/log/auth.log
# 查看今天的SSH日志
sudo grep "sshd" /var/log/auth.log | grep "$(date '+%b %d')"

查看详细的连接尝试

# 查看失败的身份验证尝试
sudo grep "Failed password" /var/log/auth.log
# 查看公钥认证相关的日志
sudo grep "publickey" /var/log/auth.log
# 查看root登录尝试
sudo grep "sshd.*root" /var/log/auth.log

2. 增加 SSH 日志详细级别

临时增加日志详细程度

在机器B上修改 SSH 配置:

sudo vim /etc/ssh/sshd_config

添加或修改:

LogLevel VERBOSE
# 或者更详细的调试信息
LogLevel DEBUG3

重启 SSH 服务:

sudo systemctl restart ssh

3. 查看客户端连接日志(机器A)

在机器A上使用详细模式连接:

# 基本详细模式
ssh -v root@10.0.7.223
# 更详细的调试信息
ssh -vvv root@10.0.7.223
# 将详细输出保存到文件
ssh -vvv root@10.0.7.223 > ssh_debug.log 2>&1

4. 实时监控日志

实时监控机器B的SSH连接

# 实时查看所有SSH相关日志
sudo tail -f /var/log/auth.log | grep sshd
# 实时查看特定IP的连接
sudo tail -f /var/log/auth.log | grep "10.0.7."
# 实时查看认证失败日志
sudo tail -f /var/log/auth.log | grep -i "permission denied\|failed\|error"

5. 分析日志的实用命令

# 查看SSH连接统计
sudo grep "Accepted" /var/log/auth.log | wc -l
sudo grep "Failed" /var/log/auth.log | wc -l
# 查看最近的成功连接
sudo grep "Accepted" /var/log/auth.log | tail -10
# 查看最近的失败连接
sudo grep "Failed\|Permission denied" /var/log/auth.log | tail -10

6. 日志文件说明

  • /var/log/auth.log:主要的认证日志文件
  • /var/log/syslog:系统日志,也包含部分SSH信息

针对这个问题的具体排查命令

在机器B上执行:

# 实时监控SSH连接尝试
sudo tail -f /var/log/auth.log | grep -E "(sshd|10.0.)"
# 查看具体的公钥认证错误
sudo grep -E "publickey|Permission denied" /var/log/auth.log
# 查看root用户的SSH连接记录
sudo grep "sshd.*root.*10.0" /var/log/auth.log

通过这些日志查看方法,你可以详细了解 SSH 连接过程中发生了什么问题,从而更准确地定位 Permission denied (publickey) 错误的原因。

如果遇到日志文件没有内容或者没有输出的情况

如果 sudo tail -f /var/log/auth.log 没有输出,可能是日志文件路径问题或服务配置问题。

后来被证实,原来是因为根本没有访问过来,所以日志才是空的。所以假设日志内容是空的,说明根本没有达到这里。

以下是排查和解决方法:

1. 检查日志文件是否存在

# 检查auth.log文件是否存在
ls -la /var/log/auth.log
# 检查是否有其他认证日志文件
ls -la /var/log/ | grep -E "(auth|secure)"
# 检查系统日志文件
ls -la /var/log/syslog

2. 查看系统日志文件

# 尝试查看syslog文件
sudo tail -f /var/log/syslog
# 查看系统日志中的SSH信息
sudo grep "sshd" /var/log/syslog
# 查看所有日志文件
sudo find /var/log -name "*.log" -type f

3. 检查rsyslog服务状态

# 检查rsyslog服务是否运行
sudo systemctl status rsyslog
# 如果未运行,启动服务
sudo systemctl start rsyslog
sudo systemctl enable rsyslog
# 重启rsyslog服务
sudo systemctl restart rsyslog

4. 检查SSH服务日志配置

检查SSH的日志配置

# 查看SSH配置中的日志级别
sudo grep "LogLevel" /etc/ssh/sshd_config
# 如果没有设置,默认是INFO,可以设置为更详细
sudo vim /etc/ssh/sshd_config

确保有以下配置:

LogLevel VERBOSE
# 或者
LogLevel INFO

重启SSH服务应用配置

sudo systemctl restart ssh

5. 手动测试日志记录

在机器A上尝试SSH连接,然后在机器B上检查:

# 在机器B上实时监控多个日志文件
sudo tail -f /var/log/syslog /var/log/auth.log 2>/dev/null
# 或者使用多文件监控
sudo tail -f /var/log/*.log | grep -i ssh

6. 检查journalctl日志

Ubuntu 20.04 也使用 systemd journal:

# 查看systemd的SSH日志
sudo journalctl -u ssh
# 实时监控SSH服务日志
sudo journalctl -u ssh -f
# 查看所有与SSH相关的日志
sudo journalctl | grep sshd
# 查看特定时间的日志
sudo journalctl --since "5 minutes ago" | grep sshd

7. 创建auth.log文件(如果不存在)

如果 /var/log/auth.log 不存在:

# 检查目录权限
ls -la /var/log/
# 重启rsyslog服务,它会自动创建日志文件
sudo systemctl restart rsyslog
# 手动创建文件(如果需要)
sudo touch /var/log/auth.log
sudo chown syslog:adm /var/log/auth.log
sudo chmod 640 /var/log/auth.log

8. 完整的排查命令组合

# 1. 检查服务状态
sudo systemctl status rsyslog
sudo systemctl status ssh
# 2. 检查日志文件
sudo ls -la /var/log/auth.log /var/log/syslog
# 3. 使用journalctl查看实时日志
sudo journalctl -f -u ssh
# 4. 在另一个终端尝试SSH连接测试
# 在机器A上执行:ssh root@10.0.7.223
# 5. 同时监控所有可能的日志源
sudo tail -f /var/log/syslog | grep ssh &
sudo journalctl -f -u ssh &

推荐的首选排查方法

对于 Ubuntu 20.04,建议直接使用:

# 方法1:使用journalctl实时监控
sudo journalctl -u ssh -f
# 方法2:同时监控系统日志
sudo tail -f /var/log/syslog | grep sshd
# 方法3:检查SSH服务状态和配置
sudo systemctl status ssh
sudo sshd -t  # 测试SSH配置语法

通常,在 Ubuntu 20.04 上,sudo journalctl -u ssh -f 是最可靠的实时查看SSH连接日志的方法。

揭晓本次问题的根本原因

如果你看到了这里,那我也该揭晓这个问题的根本原因了。

请看这里:

root@s750:~# telnet 10.0.7.223 22
Trying 10.0.7.223...
Connected to 10.0.7.223.
Escape character is '^]'.
SSH-2.0-Go
^]
telnet> Connection closed.
root@s750:~# telnet 10.0.7.223 58888
Trying 10.0.7.223...
Connected to 10.0.7.223.
Escape character is '^]'.
SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.13
}
Invalid SSH identification string.
Connection closed by foreign host.
root@s750:~# nc -zv 10.0.7.223 22
Connection to 10.0.7.223 22 port [tcp/ssh] succeeded!
root@s750:~#

很明显,22端口并不是我们要使用的SSH端口,而58888才是,因为 58888 这个端口显示了 OpenSSH 版本和 Ubuntu 字样。而这个22端口的背后是 Go 语言写的用于实现 SSH 协议克隆 Git 代码库的服务。

注:SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.13 中 SSH-2.0 是协议版本号,OpenSSH_8.2p1 是版本, Ubuntu 是发行版本,4ubuntu0.13 是 Ubuntu 软件包维护者设置的版本号。

--

发表评论
博客分类