一、适用场景
本文适用于以下场景:
Linux 云服务器无法通过 SSH 登录
SSH 端口连接失败或 Connection refused
云控制台无法直接登录,或没有系统密码
系统盘可以从故障服务器卸载并挂载到救援机
系统为 Ubuntu / Debian 系列
SSH 服务为 ssh / sshd
常见故障表现:
nc -vz <目标服务器IP> <SSH端口>
返回:
Connection refused
说明网络能到达目标服务器,但目标端口没有服务监听。
如果检查 sshd 配置时报错:
sudo chroot /mnt/rescue sshd -t
返回:
Missing privilege separation directory: /run/sshd
说明 sshd 启动依赖的 /run/sshd 目录不存在,可能导致 SSH 服务无法正常启动。
二、处理思路
整体流程如下:
1. 给故障服务器创建快照或镜像备份
2. 停止故障服务器
3. 卸载故障服务器系统盘
4. 将系统盘挂载到一台正常救援机
5. 在救援机上挂载故障系统盘
6. 检查 SSH 配置
7. 修复 /run/sshd 缺失问题
8. 增加 systemd 和 tmpfiles 兜底配置
9. 启用 SSH 服务
10. 卸载系统盘
11. 挂回原服务器
12. 启动原服务器并验证 SSH
三、云平台控制台操作
不同云厂商界面名称略有差异,例如 AWS、腾讯云、阿里云、华为云,但思路一致。
1. 创建备份
操作系统盘前,建议先做快照或镜像。
通用操作路径:
云服务器控制台 → 选择故障实例 → 系统盘 / 云硬盘 → 创建快照
或者:
云服务器控制台 → 选择故障实例 → 创建镜像
建议命名格式:
<服务器名称>-before-ssh-fix-YYYYMMDD
例如:
app-prod-01-before-ssh-fix-20260508
2. 停止故障服务器
注意是 停止 / Stop,不是 销毁 / Terminate / Delete。
云服务器控制台 → 选择故障实例 → 停止实例
等待实例状态变为:
Stopped / 已停止
3. 卸载系统盘
在故障实例详情中记录以下信息:
实例 ID
系统盘 ID
系统盘原挂载设备名
可用区 / Availability Zone
然后卸载系统盘:
云硬盘 / Volumes → 选择故障服务器系统盘 → 卸载
4. 挂载系统盘到救援机
救援机要求:
与故障服务器在同一个可用区
系统正常
可以 SSH 登录
建议使用同类 Linux 系统,例如 Ubuntu
将故障系统盘挂载到救援机。
设备名可以使用类似:
/dev/sdf
/dev/vdb
在部分云平台或 Nitro 架构实例中,进入系统后可能显示为:
/dev/nvme1n1
这是正常现象。
四、救援机上挂载故障系统盘
SSH 登录救援机后,查看磁盘:
lsblk
再查看文件系统:
lsblk -f
一般可以看到类似:
nvme0n1 救援机自己的系统盘
nvme1n1 挂载过来的故障系统盘
└─nvme1n1p1 故障系统盘分区
创建挂载目录:
sudo mkdir -p /mnt/rescue
挂载故障系统盘分区:
sudo mount <故障盘分区> /mnt/rescue
示例:
sudo mount /dev/nvme1n1p1 /mnt/rescue
如果不是 nvme1n1p1,需要根据 lsblk -f 的结果选择正确分区。
确认挂载成功:
ls /mnt/rescue
正常应该能看到类似目录:
bin boot dev etc home lib opt proc root run usr var
五、检查 SSH 配置
1. 检查主配置文件
sudo grep -nE '^(Port|ListenAddress|PubkeyAuthentication|PasswordAuthentication|UsePAM)' /mnt/rescue/etc/ssh/sshd_config
重点关注:
Port <SSH端口>
PubkeyAuthentication
PasswordAuthentication
UsePAM
例如:
Port 22
或者:
Port 2222
如果服务器使用了非标准端口,要确认这里配置的是实际 SSH 登录端口。
2. 检查 sshd_config.d 覆盖配置
Ubuntu 云镜像经常会在下面目录放额外配置:
sudo ls -l /mnt/rescue/etc/ssh/sshd_config.d/
继续检查是否有覆盖配置:
sudo grep -RniE '^(Port|ListenAddress|PubkeyAuthentication|PasswordAuthentication|DenyUsers|AllowUsers|AllowGroups|MaxStartups)' /mnt/rescue/etc/ssh/sshd_config.d/ 2>/dev/null
如果看到:
PasswordAuthentication no
一般表示禁止 SSH 密码登录,只允许密钥登录。
这通常是云服务器默认安全配置,不一定是问题。
六、进入 chroot 检查 sshd
挂载 chroot 所需目录:
sudo mount --bind /dev /mnt/rescue/dev
sudo mount --bind /proc /mnt/rescue/proc
sudo mount --bind /sys /mnt/rescue/sys
检查 sshd 配置:
sudo chroot /mnt/rescue sshd -t
echo $?
如果正常,通常没有输出,并返回:
0
如果返回:
Missing privilege separation directory: /run/sshd
说明 /run/sshd 缺失,需要继续修复。
七、修复 /run/sshd 缺失问题
1. 临时创建 /run/sshd
sudo mkdir -p /mnt/rescue/run/sshd
sudo chmod 755 /mnt/rescue/run/sshd
再次检查:
sudo chroot /mnt/rescue sshd -t
echo $?
期望返回:
0
2. 增加 systemd 启动兜底配置
因为 /run 是临时目录,系统重启后 /run/sshd 不会永久保留,所以需要让 systemd 每次启动 SSH 服务前自动创建该目录。
创建 override 目录:
sudo mkdir -p /mnt/rescue/etc/systemd/system/ssh.service.d
写入配置:
sudo tee /mnt/rescue/etc/systemd/system/ssh.service.d/override.conf >/dev/null <<'EOF'
[Service]
RuntimeDirectory=sshd
RuntimeDirectoryMode=0755
EOF
作用:
启动 ssh 服务前自动创建 /run/sshd
目录权限为 0755
3. 增加 tmpfiles 兜底配置
创建 tmpfiles 配置目录:
sudo mkdir -p /mnt/rescue/etc/tmpfiles.d
写入配置:
echo 'd /run/sshd 0755 root root -' | sudo tee /mnt/rescue/etc/tmpfiles.d/sshd.conf
作用:
系统启动时通过 systemd-tmpfiles 自动创建 /run/sshd
八、启用 SSH 服务并最终检查
启用 SSH 服务开机自启:
sudo chroot /mnt/rescue systemctl enable ssh
再次检查 sshd 配置:
sudo chroot /mnt/rescue sshd -t
echo $?
期望返回:
0
如果返回 0,说明 SSH 配置正常。
九、卸载故障系统盘
先切换到根目录,避免挂载目录被占用:
cd /
卸载所有挂载:
sudo umount -R /mnt/rescue
确认没有挂载残留:
lsblk
如果提示 busy,可以检查是否还有进程占用:
sudo lsof +f -- /mnt/rescue
或重新执行:
cd /
sudo umount -R /mnt/rescue
十、挂回原服务器
在云平台控制台中操作:
云硬盘 / Volumes → 选择故障系统盘 → 从救援机卸载
等待磁盘状态变为空闲或可挂载。
然后挂回原服务器:
云硬盘 / Volumes → 选择故障系统盘 → 挂载到原服务器
注意:
设备名必须使用原来的系统盘设备名
常见设备名:
/dev/sda1
/dev/xvda
/dev/vda
具体以云平台原实例详情中记录的 Root device name 为准。
十一、启动原服务器并验证
启动原服务器:
云服务器控制台 → 选择原实例 → 启动实例
启动完成后,在跳板机或同网络服务器上测试 SSH 端口:
nc -vz <目标服务器IP> <SSH端口>
正常结果:
Connection to <目标服务器IP> <SSH端口> port [tcp/*] succeeded!
测试 SSH 登录:
chmod 400 <密钥文件>
ssh -i <密钥文件> -p <SSH端口> <用户名>@<目标服务器IP>
示例:
chmod 400 /tmp/server.pem
ssh -i /tmp/server.pem -p 22 ubuntu@<目标服务器IP>
如果使用非标准端口:
ssh -i /tmp/server.pem -p <SSH端口> ubuntu@<目标服务器IP>
登录成功后,检查 SSH 服务状态:
sudo systemctl status ssh
检查监听端口:
sudo ss -lntp | grep <SSH端口>
检查 sshd 配置:
sudo sshd -t
echo $?
期望返回:
0
十二、恢复后建议加固
1. 设置 VNC / 控制台备用登录密码
为了避免下次 SSH 异常时完全无法进入系统,建议给普通运维用户设置系统密码。
例如 Ubuntu 默认用户:
sudo passwd ubuntu
检查用户状态:
sudo passwd -S ubuntu
如果看到类似:
ubuntu P ...
说明密码可用。
以后通过云控制台 VNC 登录:
login: ubuntu
Password: 输入设置的系统密码
登录后提权:
sudo -i
注意:这不等于开启 SSH 密码登录。
SSH 仍然可以保持密钥登录。
2. 不建议长期开启 root SSH 密码登录
如果只是为了 VNC 兜底,建议设置普通用户密码,不建议开启 root SSH 密码登录。
SSH 推荐配置:
PasswordAuthentication no
PermitRootLogin prohibit-password
PubkeyAuthentication yes
十三、故障原因说明
/run 是运行时临时目录,通常由 tmpfs 提供:
mount | grep ' /run '
正常情况下:
/run 目录会在系统启动后生成
/run/sshd 不会永久保存在磁盘上
SSH 服务启动时需要 /run/sshd
正常应由 systemd 或 systemd-tmpfiles 自动创建
如果系统启动时没有正确创建 /run/sshd,sshd 可能启动失败,最终导致 SSH 端口没有监听。
典型表现:
SSH 端口 Connection refused
sshd -t 报 Missing privilege separation directory: /run/sshd
最终修复方式:
临时创建 /run/sshd
增加 systemd RuntimeDirectory=sshd
增加 tmpfiles 兜底配置
启用 ssh 服务
重新挂回系统盘并启动服务器
十四、完整命令汇总
# 1. 查看磁盘
lsblk
lsblk -f
# 2. 创建挂载目录
sudo mkdir -p /mnt/rescue
# 3. 挂载故障系统盘
sudo mount <故障盘分区> /mnt/rescue
# 示例:
# sudo mount /dev/nvme1n1p1 /mnt/rescue
# 4. 检查 ssh 主配置
sudo grep -nE '^(Port|ListenAddress|PubkeyAuthentication|PasswordAuthentication|UsePAM)' /mnt/rescue/etc/ssh/sshd_config
# 5. 检查 sshd_config.d 覆盖配置
sudo ls -l /mnt/rescue/etc/ssh/sshd_config.d/
sudo grep -RniE '^(Port|ListenAddress|PubkeyAuthentication|PasswordAuthentication|DenyUsers|AllowUsers|AllowGroups|MaxStartups)' /mnt/rescue/etc/ssh/sshd_config.d/ 2>/dev/null
# 6. 准备 chroot 环境
sudo mount --bind /dev /mnt/rescue/dev
sudo mount --bind /proc /mnt/rescue/proc
sudo mount --bind /sys /mnt/rescue/sys
# 7. 检查 sshd 配置
sudo chroot /mnt/rescue sshd -t
echo $?
# 8. 如果报 Missing privilege separation directory: /run/sshd,则创建目录
sudo mkdir -p /mnt/rescue/run/sshd
sudo chmod 755 /mnt/rescue/run/sshd
# 9. 再次检查 sshd
sudo chroot /mnt/rescue sshd -t
echo $?
# 10. 增加 systemd override
sudo mkdir -p /mnt/rescue/etc/systemd/system/ssh.service.d
sudo tee /mnt/rescue/etc/systemd/system/ssh.service.d/override.conf >/dev/null <<'EOF'
[Service]
RuntimeDirectory=sshd
RuntimeDirectoryMode=0755
EOF
# 11. 增加 tmpfiles 兜底配置
sudo mkdir -p /mnt/rescue/etc/tmpfiles.d
echo 'd /run/sshd 0755 root root -' | sudo tee /mnt/rescue/etc/tmpfiles.d/sshd.conf
# 12. 启用 ssh 服务
sudo chroot /mnt/rescue systemctl enable ssh
# 13. 最终检查
sudo chroot /mnt/rescue sshd -t
echo $?
# 14. 卸载故障系统盘
cd /
sudo umount -R /mnt/rescue
# 15. 挂回原服务器后验证
nc -vz <目标服务器IP> <SSH端口>
ssh -i <密钥文件> -p <SSH端口> <用户名>@<目标服务器IP>
十五、注意事项
- 操作系统盘前必须先做快照或镜像备份。
- 停止实例时不要误点销毁、终止、删除。
- 救援机必须和故障盘在同一个可用区。
- 挂回原服务器时,系统盘设备名要使用原来的 Root device name。
/run/sshd是运行时目录,不能只依赖手工创建,必须增加 systemd 或 tmpfiles 兜底配置。- 修复完成后建议测试云控制台 VNC 登录,设置普通用户密码作为保底。
- 不建议长期开放 SSH 密码登录和 root 密码登录。