概述
干了这么多年运维,SSH 相关的问题至少处理过几百次。有时候是登录等三十秒才出现密码提示,有时候是连上没多久就突然断开,有时候是某几台机器能连、某几台连不上,还有时候是从公司内网能连,回到家就卡住。
每种现象的背后原因都不太一样。很多人遇到 SSH 问题时,第一反应就是“网络不好”,然后重启服务了事。这篇文章我把常见的 SSH 问题做了分类整理,附上排查方法和解决方案,下次遇到问题可以直接对症下药。
问题分类
根据经验,SSH 问题大致可以分为以下几类:
- 连接建立慢:输入命令后等待很久才出现密码提示
- 认证慢:输入密码后等待很久才进入 Shell
- 连接中断:正常使用一段时间后突然断开
- 完全无法连接:直接 timeout 或 connection refused
- 间歇性问题:时好时坏,难以复现
环境信息
操作系统:CentOS 7.x / RHEL 8.x / Ubuntu 20.04+
SSH版本:OpenSSH 7.4+
网络环境:内网、跨机房、跨地域、VPN、NAT
连接建立慢的问题
问题一:DNS反向解析
这是最常见的问题。SSH 服务端默认会对客户端 IP 做反向 DNS 查询,如果 DNS 服务器响应慢或者查不到记录,就会等待超时。
现象:输入 ssh user@host 后等待 10-30 秒才出现密码提示。
诊断方法:
# 开启SSH详细日志
ssh -vvv user@host 2>&1 | grep -i dns
# 或者在服务端查看日志
tail -f /var/log/secure | grep sshd
# 典型日志:
# debug1: ssh_exchange_identification: reverse mapping checking getaddrinfo for xxx.xxx failed
解决方案:
# 方法1:修改sshd配置
vim /etc/ssh/sshd_config
# 禁用DNS反向解析
UseDNS no
# 重启sshd
systemctl restart sshd
# 方法2:修复DNS配置
cat /etc/resolv.conf
# 确保nameserver可达且响应快
# 方法3:添加hosts记录
echo "10.0.0.100 client-hostname" >> /etc/hosts
问题二:GSSAPI认证
GSSAPI 是一种认证机制,常用于 Kerberos 环境。如果服务器配置了 GSSAPI 但实际环境不支持,认证过程就会等待超时。
现象:连接过程中卡在 "Authenticating with GSSAPI..."
诊断方法:
ssh -vvv user@host 2>&1 | grep -i gssapi
# 典型输出:
# debug1: Authentications that can continue: gssapi-with-mic,publickey,password
# debug3: Trying to reverse map address xxx
# debug1: Unspecified GSS failure
解决方案:
# 客户端临时禁用
ssh -o GSSAPIAuthentication=no user@host
# 客户端永久禁用
cat >> ~/.ssh/config << EOF
Host *
GSSAPIAuthentication no
EOF
# 服务端禁用
vim /etc/ssh/sshd_config
GSSAPIAuthentication no
systemctl restart sshd
问题三:SSH版本协议协商
老旧的 SSH 客户端或服务端可能导致协议协商缓慢。
诊断方法:
ssh -vvv user@host 2>&1 | head -50
# 查看协商过程耗时
time ssh -o "NumberOfPasswordPrompts=0" user@host 2>&1 | head
解决方案:
# 指定使用SSH2
ssh -2 user@host
# 或升级SSH版本
yum update openssh-server openssh-clients
认证过程慢的问题
问题一:PAM模块问题
PAM 配置不当会导致认证过程缓慢,特别是涉及网络认证的模块(如 LDAP、SSSD)。
现象:输入密码后等待数秒甚至更久。
诊断方法:
# 查看PAM配置
cat /etc/pam.d/sshd
# 检查PAM模块加载时间
time su - testuser -c "echo ok"
# 查看sssd状态(如果使用)
systemctl status sssd
解决方案:
# 检查LDAP/SSSD服务状态
systemctl status sssd
# 检查nsswitch配置
cat /etc/nsswitch.conf
# passwd: files sss # sss响应慢时影响认证
# 临时禁用pam_systemd(可能导致慢的模块之一)
# 在/etc/pam.d/sshd中注释掉
# -session optional pam_systemd.so
问题二:authorized_keys文件过大
公钥认证时,如果 authorized_keys 文件太大,或者存放在慢速存储上,会导致认证变慢。
诊断方法:
# 检查文件大小
ls -la ~/.ssh/authorized_keys
wc -l ~/.ssh/authorized_keys
# 检查文件权限
stat ~/.ssh/authorized_keys
解决方案:
# 清理过期的公钥
# 保持authorized_keys简洁
# 确保目录权限正确
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
问题三:lastlog/wtmp文件过大
SSH 登录时会更新 lastlog 和 wtmp 文件,如果这些文件过大或存放在 NFS 上,登录过程会变慢。
诊断方法:
# 检查文件大小
ls -la /var/log/lastlog /var/log/wtmp
# 查看wtmp记录数
last | wc -l
解决方案:
# 清理wtmp
cat /dev/null > /var/log/wtmp
# 配置logrotate轮转
cat > /etc/logrotate.d/wtmp << EOF
/var/log/wtmp {
monthly
create 0664 root utmp
minsize 1M
rotate 1
}
EOF
# 如果lastlog文件过大(稀疏文件)
cp /var/log/lastlog /var/log/lastlog.bak
> /var/log/lastlog
连接中断问题
问题一:NAT超时
这是家庭网络和云环境中最常见的问题。NAT 设备会跟踪 TCP 连接,如果长时间没有数据传输,NAT 记录就会被删除,导致连接中断。
现象:空闲一段时间后,连接无响应,最终超时断开。
诊断方法:
# 测试连接保持时间
# 建立连接后不操作,记录多久后断开
# 通常NAT超时时间是5-30分钟
# 查看当前的TCP keepalive配置
cat /proc/sys/net/ipv4/tcp_keepalive_time
cat /proc/sys/net/ipv4/tcp_keepalive_intvl
cat /proc/sys/net/ipv4/tcp_keepalive_probes
解决方案:
# 方法1:客户端配置心跳
cat >> ~/.ssh/config << EOF
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
EOF
# 方法2:服务端配置心跳
vim /etc/ssh/sshd_config
ClientAliveInterval 60
ClientAliveCountMax 3
systemctl restart sshd
# 方法3:调整系统TCP keepalive
sysctl -w net.ipv4.tcp_keepalive_time=600
sysctl -w net.ipv4.tcp_keepalive_intvl=60
sysctl -w net.ipv4.tcp_keepalive_probes=3
问题二:网络不稳定
网络抖动、丢包、延迟高都可能导致 SSH 连接中断。
诊断方法:
# 持续ping测试
ping -i 1 target_host | tee ping.log
# 分析丢包和延迟
# 使用mtr进行路由诊断
mtr -r -c 100 target_host
# 抓包分析
tcpdump -i eth0 host target_host and port 22 -w ssh.pcap
解决方案:
# 使用mosh替代ssh(移动网络场景)
yum install mosh
mosh user@host
# 使用tmux/screen保持会话
# 即使连接断开,会话也不会丢失
ssh user@host
tmux new -s work
# 断开重连后
ssh user@host
tmux attach -t work
问题三:服务器资源耗尽
当服务器负载极高或内存耗尽时,sshd 进程可能无法正常响应。
诊断方法:
# 如果还能登录,检查资源
top -bn1 | head -20
free -h
df -h
# 检查sshd进程状态
ps aux | grep sshd
解决方案:
# 保留紧急访问能力
# 配置console访问或IPMI/iLO
# 提高sshd的OOM得分(不容易被kill)
echo -1000 > /proc/$(pgrep -o sshd)/oom_score_adj
# 限制普通用户的资源使用
# /etc/security/limits.conf
完全无法连接
问题一:防火墙规则
诊断方法:
# 客户端测试端口连通性
telnet target_host 22
nc -zv target_host 22
# 服务端检查防火墙
iptables -L -n | grep 22
firewall-cmd --list-all
# 检查SELinux
getenforce
ausearch -c 'sshd' --raw | audit2allow -M my-sshd
解决方案:
# firewalld
firewall-cmd --permanent --add-service=ssh
firewall-cmd --reload
# iptables
iptables -I INPUT -p tcp --dport 22 -j ACCEPT
# 云服务器记得检查安全组
问题二:sshd未运行或配置错误
诊断方法:
# 检查sshd状态
systemctl status sshd
# 检查端口监听
ss -tlnp | grep 22
netstat -tlnp | grep 22
# 测试配置文件
sshd -t
# 查看sshd日志
journalctl -u sshd -f
解决方案:
# 启动sshd
systemctl start sshd
systemctl enable sshd
# 如果配置错误,使用默认配置
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
# 编辑修复配置
# 重新加载
systemctl restart sshd
问题三:Host key问题
现象:连接时提示 "Host key verification failed"
诊断方法:
# 查看known_hosts中的记录
ssh-keygen -l -F target_host
# 错误信息中会显示冲突的key
解决方案:
# 删除旧的host key
ssh-keygen -R target_host
# 或者临时跳过检查(不推荐生产使用)
ssh -o StrictHostKeyChecking=no user@host
# 如果是服务器重装导致,这是正常的
# 确认服务器身份后重新连接即可
问题四:MaxStartups限制
当有大量并发 SSH 连接时,可能触发 MaxStartups 限制。
现象:部分连接被拒绝,日志中出现 "Connection refused"
诊断方法:
# 查看当前未认证的连接数
netstat -ant | grep :22 | grep ESTABLISHED | wc -l
# 查看sshd日志
grep "refused" /var/log/secure
解决方案:
# 修改MaxStartups
vim /etc/ssh/sshd_config
# 格式:开始拒绝的连接数:拒绝概率:最大未认证连接数
MaxStartups 100:30:200
# 或者直接设置一个较大的值
MaxStartups 200
systemctl restart sshd
安全加固配置
在解决连接问题的同时,不能忽视安全性:
# /etc/ssh/sshd_config 安全配置模板
# 协议版本
Protocol 2
# 禁止root直接登录
PermitRootLogin no
# 或者只允许密钥登录
# PermitRootLogin prohibit-password
# 禁用密码认证(仅使用密钥)
PasswordAuthentication no
PubkeyAuthentication yes
# 禁用空密码
PermitEmptyPasswords no
# 限制登录用户/组
AllowUsers admin deploy
# 或 AllowGroups sshusers
# 禁用危险功能
X11Forwarding no
PermitTunnel no
# 登录超时
LoginGraceTime 60
MaxAuthTries 3
# 使用更安全的加密算法
Ciphers aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
KexAlgorithms curve25519-sha256,diffie-hellman-group16-sha512
# 日志级别
LogLevel VERBOSE
fail2ban防护
# 安装fail2ban
yum install fail2ban
# 配置SSH防护
cat > /etc/fail2ban/jail.local << EOF
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/secure
maxretry = 5
bantime = 3600
findtime = 600
EOF
systemctl enable fail2ban
systemctl start fail2ban
# 查看被封禁的IP
fail2ban-client status sshd
SSH性能优化
连接复用
频繁连接同一台服务器时,可以复用已有连接:
# ~/.ssh/config
Host *
ControlMaster auto
ControlPath ~/.ssh/sockets/%r@%h-%p
ControlPersist 600
# 创建socket目录
mkdir -p ~/.ssh/sockets
chmod 700 ~/.ssh/sockets
效果:第一次连接正常握手,后续连接复用已有通道,几乎瞬间连接。
压缩传输
对于慢速网络,启用压缩可以提升传输效率:
# 客户端
ssh -C user@host
# 或在配置中启用
Host slow-network-host
Compression yes
选择更快的加密算法
# 测试不同算法的速度
for cipher in aes128-ctr aes256-ctr aes128-gcm@openssh.com chacha20-poly1305@openssh.com; do
echo "Testing $cipher"
time ssh -c $cipher user@host 'dd if=/dev/zero bs=1M count=100 2>/dev/null' > /dev/null
done
在我的测试中,aes128-gcm@openssh.com 通常是最快的。
快速诊断脚本
把刚才提到的所有调试命令整理成一个诊断脚本,方便快速定位问题:
#!/bin/bash
# ssh_diagnose.sh - SSH问题诊断脚本
TARGET=$1
if [ -z "$TARGET" ]; then
echo "Usage: $0 hostname"
exit 1
fi
echo "=== SSH Diagnosis for $TARGET ==="
# 1. 网络连通性
echo -e "\n[1] Network connectivity:"
ping -c 3 -W 2 $TARGET 2>/dev/null
if [ $? -ne 0 ]; then
echo "FAIL: Cannot reach host"
fi
# 2. 端口开放
echo -e "\n[2] Port 22 status:"
nc -zv -w 3 $TARGET 22 2>&1
# 3. DNS解析
echo -e "\n[3] DNS resolution:"
host $TARGET 2>/dev/null || nslookup $TARGET
# 4. 反向DNS
echo -e "\n[4] Reverse DNS:"
IP=$(dig +short $TARGET | head -1)
if [ -n "$IP" ]; then
dig +short -x $IP
fi
# 5. SSH协商测试
echo -e "\n[5] SSH handshake test:"
timeout 10 ssh -v -o "NumberOfPasswordPrompts=0" -o "ConnectTimeout=5" $TARGET 2>&1 | grep -E "debug1: (Connecting|Connection|Authentications|Next)"
# 6. 路由追踪
echo -e "\n[6] Route trace:"
traceroute -n -w 1 -q 1 $TARGET 2>/dev/null | head -15
echo -e "\n=== Diagnosis Complete ==="
使用方法:
chmod +x ssh_diagnose.sh
./ssh_diagnose.sh target_host
关于 tcpdump 抓包、mtr 路由分析等网络层调试技巧,你也可以参考云栈社区整理的 技术文档 章节,里面有不少现成的 CheatSheet 和实操案例。
总结
问题速查表
| 现象 |
可能原因 |
快速解决 |
| 连接等待30秒 |
DNS反向解析 |
UseDNS no |
| 认证等待10秒 |
GSSAPI认证 |
GSSAPIAuthentication no |
| 空闲断开 |
NAT超时 |
ServerAliveInterval 60 |
| Connection refused |
防火墙/sshd未启动 |
检查iptables/systemctl |
| Permission denied |
密码错误/密钥问题 |
检查认证方式 |
| Host key验证失败 |
服务器重装 |
ssh-keygen -R host |
关键配置文件
- 客户端配置:
~/.ssh/config
- 服务端配置:
/etc/ssh/sshd_config
- 已知主机:
~/.ssh/known_hosts
- 公钥认证:
~/.ssh/authorized_keys
调试命令
# 客户端调试
ssh -vvv user@host
# 服务端调试
sshd -d -p 2222 # 在前台调试模式启动
参考资料