管过几台 VPS(虚拟专用服务器)的人大概率遇到过:ssh-copy-id 明明执行成功,登录却仍要输密码;或者一直免密的服务器突然拒绝公钥认证。这篇教程教你从 authorized_keys 权限、目录归属到 sshd 配置逐层排查解决,故障九成出在权限上,其余多半是 sshd 配置和 SELinux 上下文,下文每层都给出可直接复制的验证命令。
免密登录的工作原理:先搞清楚谁验证谁
排查前先花两分钟理解公钥认证的验证方向,很多人排查半天失败,根源就是方向搞反了。SSH 免密登录用非对称加密:私钥(id_ed25519 或 id_rsa)留在本地,公钥(.pub 文件)追加到服务器的 ~/.ssh/authorized_keys。登录时服务器用公钥出随机挑战,客户端用私钥签名应答,验签通过就放行——私钥从不离开本地,这是公钥认证比密码安全的核心。因此问题只可能出在三个位置:本地私钥侧、传输过程、服务器端 authorized_keys 及其宿主环境。ssh-copy-id 只负责把公钥写过去,不检查服务器端权限、归属和 sshd 配置,”copy 成功”和”登录免密”之间隔着好几道关卡。
标准配置流程:三步完成免密登录
标准流程只要三步,先走一遍确认基础链路是通的,再谈排错。
第一步:本地生成密钥对。 推荐使用 Ed25519 算法,密钥短、安全性高:
ssh-keygen -t ed25519 -C "johnson@laptop"
# 一路回车即可;若设置了 passphrase,每次登录需要解锁私钥第二步:把公钥写入服务器。 ssh-copy-id 会自动创建 ~/.ssh 目录、设置权限并把公钥追加到 authorized_keys:
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@your-server-ip
# 输入最后一次密码,之后就应该免密了第三步:验证登录。 加 -v 参数能看到公钥认证的详细过程:
ssh -v user@your-server-ip
# 输出中看到 "Server accepts key" 和 "Authenticated ... using publickey" 即成功在我的测试环境中,一台全新的 Ubuntu 22.04 VPS 走完这三步大约 40 秒。如果第三步仍然提示输密码,说明链路中某一层出了问题,进入下一节的逐层排查。
逐层排查:六个最常见的失败原因
免密登录失败的原因集中在权限、归属和配置三类,下面按命中率从高到低排列,逐条给出验证和修复命令,多数人在前三条就能定位问题。
1. .ssh 目录与 authorized_keys 权限错误(命中率最高)
sshd 对权限要求近乎苛刻:组或其他用户有写权限就直接拒绝公钥认证,且通常不在登录提示里报错。这是免密登录失败的第一大原因,占实际案例一半以上。
# 服务器端执行,一次修正所有权限
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
# 验证:.ssh 必须是 drwx------,authorized_keys 必须是 -rw-------
ls -ld ~/.ssh ~/.ssh/authorized_keys另一个细节:若 authorized_keys 由 root 代建,归属可能是 root:root,sshd 同样拒绝,用 chown $USER:$USER ~/.ssh/authorized_keys 修正归属后才算通过。
2. 家目录权限过松
很多人只盯着 .ssh 目录,却忘了 sshd 默认还检查家目录本身:家目录若组可写(如 drwxrwx--x),StrictModes 开启时公钥认证同样被拒:
chmod go-w ~
# 验证:家目录对组和其他用户不能有写权限
ls -ld ~3. SELinux 上下文缺失(CentOS/RHEL 系常见)
CentOS、AlmaLinux、Rocky 这类系统上,若 authorized_keys 经 scp 或重定向创建,即使权限正确,SELinux 上下文也可能不对,sshd 读不到文件。修复:
restorecon -Rv ~/.ssh
# 查看当前上下文,应包含 ssh_home_t
ls -Z ~/.ssh/authorized_keys不确定是否 SELinux 问题时,用 getenforce 确认模式,或在 /var/log/audit/audit.log 搜 avc denied;Debian/Ubuntu 系通常没有这层问题。
4. sshd 配置禁用了公钥认证
少数镜像模板或安全加固脚本会把 PubkeyAuthentication 设为 no,或让 AuthorizedKeysFile 指向非默认路径,检查 /etc/ssh/sshd_config:
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
# 修改后记得重载配置
sudo systemctl reload sshd注意区分:客户端行为看 /etc/ssh/ssh_config,服务端认证看 sshd_config,改错文件是新手常犯的错误。
5. 私钥权限过松,客户端直接拒绝使用
排查不只在服务器端:客户端对私钥权限同样有硬性要求,出现 UNPROTECTED PRIVATE KEY FILE 警告时会直接放弃该私钥、回落密码认证——表面上就像”服务器不认我的公钥”:
# 本地执行
chmod 600 ~/.ssh/id_ed255196. 多把密钥时的匹配问题
本机 ~/.ssh 里积攒了多把密钥时,客户端默认按顺序尝试,服务器达到 MaxAuthTries(默认 6 次)上限后会直接断开。在 ~/.ssh/config 里为指定主机显式绑定私钥即可:
Host myserver
HostName your-server-ip
User user
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yesIdentitiesOnly yes 强制客户端只使用指定的密钥,避免 ssh-agent 里的其他密钥干扰认证顺序。管理大量服务器时建议把这个配置作为默认习惯。


用日志做最终定位:两分钟看到真实原因
如果上面六条都对过还是有问题,直接看服务端日志,sshd 会把拒绝公钥认证的真实原因写出来,前面的权限问题几乎都会在这里留下明确记录。
Debian/Ubuntu 系看认证日志,CentOS 系看 secure 日志:
# Debian/Ubuntu
sudo tail -20 /var/log/auth.log | grep -i ssh
# CentOS/RHEL
sudo tail -20 /var/log/secure | grep -i ssh日志信息不够时,把 sshd 调到 debug 级别复现一次。不建议改线上 sshd_config 的 LogLevel,更安全的做法是临时起一个 2222 端口调试实例:
sudo /usr/sbin/sshd -d -p 2222
# 另开终端执行
ssh -p 2222 -v user@your-server-ip调试模式下,Authentication refused: bad ownership or modes ... 这类关键日志会直接打印到前台,看到它就回到第一节的权限修复命令,当场闭环。
预防措施:让免密登录保持长期可用
排错只是止损,下面几条习惯能让公钥认证长期稳定,成本低但收益明显:
- 禁用密码登录前先验证免密通道:写入
PasswordAuthentication no前,务必新开终端确认免密成功,否则可能把自己锁在外面,恢复成本很高。 - 用
sshd -t检查语法再 reload:先执行sudo sshd -t,无输出说明语法正确,再systemctl reload sshd,避免 sshd 起不来。 - 定期审计
authorized_keys:定期清理离职人员与旧设备公钥,awk '{print $3}' ~/.ssh/authorized_keys可快速列出所有公钥备注核对来源。 - 多机场景用
~/.ssh/config统一管理:配合IdentitiesOnly和明确IdentityFile,避免密钥顺序问题,批量迁移时也方便核对。
总结:免密登录排错核心是权限与归属、SELinux 上下文、sshd 配置三层,配合 ssh -v 和服务端日志,几乎所有”还在输密码”的问题都能在十分钟内定位。如果你需要生产环境的 SSH 加固方案,建议先在测试机演练上述流程;选购服务器时,Hostease 这类提供中文工单支持的商家在排查权限类问题时沟通成本更低;多机环境可以考虑把 ~/.ssh/config 与公钥审计纳入标准运维规范。
延伸阅读
如果你需要继续深入,建议阅读:
- 美国VPS速度优化指南,排查线路对 SSH 体验的影响
- 跨境访问CN2实测,大陆方向稳定性参考
- 海外VPS部署WordPress全流程,新服务器上线推荐路径




