SSH 免密登录配置与排障:密钥登录一次配通的完整指南

一、结论先给

SSH 免密登录(公钥登录)本质上就三步:本地生成密钥对 → 把公钥放进服务器的 ~/.ssh/authorized_keys → 服务端开启 PubkeyAuthentication。90% 的失败不是命令敲错,而是文件权限不对或服务端配置没开。

环节 命令 常见坑
生成密钥 ssh-keygen -t ed25519 -C "备注" 老设备不支持 ed25519,改用 rsa -b 4096
传公钥 ssh-copy-id -i ~/.ssh/xx.pub user@host 没有 ssh-copy-id 时手动追加,别用 > 覆盖
修权限 chmod 700 ~/.ssh; chmod 600 authorized_keys 家目录权限过宽(777)也会被拒
开服务端 PubkeyAuthentication yes 改完必须 sshd -t 验语法再重载
验证 ssh -v user@host -v 是唯一的真相来源

👉 配置前后想确认目标机 22 端口通不通,用 SSH 端口连通检测(在线),不用登机器就能测。

二、本地:生成一对密钥

2.1 算法怎么选

# 首选:ed25519,密钥短、快、安全性高(OpenSSH 6.5+ 支持,2014 年以后基本都有)
ssh-keygen -t ed25519 -C "afei@macbook-2026"

# 兼容老设备(CentOS 6 / 老交换机 / 部分堡垒机)用 RSA 4096
ssh-keygen -t rsa -b 4096 -C "afei@macbook-rsa"

# 指定文件名,避免覆盖默认 id_rsa
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_ops -C "ops"

交互会问两件事:

  • Enter passphrase:给私钥再加一层口令。生产环境建议设,配合 ssh-agent 用;自动化脚本(CI、定时任务)留空。
  • 生成后得到两个文件:id_ed25519(私钥,绝不外传)和 id_ed25519.pub(公钥,放服务器上)。

判断该用哪个:

场景 推荐
服务器是 CentOS 7+/Ubuntu 16+ ed25519
要连网络设备、老交换机、旧堡垒机 RSA 4096
合规要求 FIPS ecdsa 或 RSA

2.2 私钥权限自检

OpenSSH 对私钥权限很敏感,太开放会直接拒绝使用:

chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
ls -l ~/.ssh/

看到 WARNING: UNPROTECTED PRIVATE KEY FILE! 就是这个问题,chmod 600 即可。

三、把公钥送到服务器

3.1 方式一:ssh-copy-id(推荐)

# 默认用 ~/.ssh/id_ed25519.pub
ssh-copy-id root@10.0.0.11

# 指定密钥和端口
ssh-copy-id -i ~/.ssh/id_ed25519_ops.pub -p 2222 ops@10.0.0.11

它做的事:登一次密码 → 在远端创建 .ssh 目录并设 700 → 把公钥追加到 authorized_keys 并设 600。追加语义很重要,多个人/多台机器的公钥能共存。

3.2 方式二:手动追加(没有 ssh-copy-id 时)

# macOS / Linux 本地执行,注意用的是 >> 追加
cat ~/.ssh/id_ed25519.pub | ssh root@10.0.0.11 "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

千万别用 >,那会清空别人已经配好的公钥,导致整台机器的免密集体失效。

3.3 方式三:云厂商控制台注入

阿里云/腾讯云/AWS 都支持创建实例时绑定密钥对,或者停机后"绑定密钥"。这种方式会覆盖 ~/.ssh/authorized_keys,且通常要求先把实例关机,适合开新机器,不适合给正在跑的机器补配。

四、服务端:sshd 配置与权限

4.1 四个关键参数

sudo vim /etc/ssh/sshd_config
PubkeyAuthentication yes                      # 开启公钥登录,默认一般是 yes
AuthorizedKeysFile  .ssh/authorized_keys     # 公钥存放位置
PermitRootLogin prohibit-password            # 禁 root 密码登录,但允许 root 密钥登录
PasswordAuthentication no                    # 彻底关掉密码登录(确认密钥能登录之后再改)

改完先验证语法,再重载,这条顺序不能反:

sudo sshd -t          # 有错会直接报行号;没错不出任何输出
sudo systemctl reload sshd      # CentOS / Ubuntu 通用;Ubuntu 服务名也可能是 ssh
# 老系统:
sudo service sshd reload

用 reload 而不是 restart:reload 不会踢掉当前已建立的连接,配错时至少还能靠现有会话救回来。配 SSH 时永远保留一个已登录的会话窗口别关,这是运维的保命习惯。

4.2 权限矩阵(错一个就登录失败)

路径 正确权限 说明
/home/user 755(不能 777) 家目录被同组/其他用户可写,sshd 直接不信任
/home/user/.ssh 700 目录必须仅本人可读写执行
authorized_keys 600 也可以是 644,但 600 最稳
本地私钥 600 否则 UNPROTECTED PRIVATE KEY FILE
chmod go-w ~
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

4.3 SELinux 环境(CentOS/RHEL)额外一步

手动拷贝文件到 .ssh 后,SELinux 上下文可能是错的,sshd 读不到:

restorecon -R -v ~/.ssh
# 临时排查可以用 setenforce 0 确认是不是 SELinux 的锅,验完记得 setenforce 1

五、多密钥与 SSH Config

管理多台机器、多个身份(公司/个人/客户)时,靠 ~/.ssh/config 而不是每次 -i:

Host ops-prod
    HostName 10.0.0.11
    User ops
    Port 2222
    IdentityFile ~/.ssh/id_ed25519_ops
    IdentitiesOnly yes          # 只试这一把钥匙

Host *
    ServerAliveInterval 30      # 每 30 秒发心跳,防 NAT/防火墙掐断
    ServerAliveCountMax 3
    AddKeysToAgent yes

配完直接 ssh ops-prod。

IdentitiesOnly yes 是解决 "Too many authentication failures" 的关键——不加它,本地 5 把钥匙会被依次尝试,很多服务端默认 MaxAuthTries 6,轮到正确的那把之前就被踢了。

六、ssh-agent:私钥带口令又不想到处输

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519_ops      # 输入一次 passphrase
ssh-add -l                          # 列出已加载的钥匙

# 跳板机场景:A → B → C,不想把私钥放 B 上
ssh -A user@B        # 或配置里 ForwardAgent yes

-A(Agent Forwarding)的安全提醒:B 机器上的 root 能通过你的 agent socket 冒充你登录 C。只在可信机器上使用,不可信环境改用 ProxyJump:

ssh -J user@B user@C
# 或 config 里
Host C
    ProxyJump user@B

ProxyJump 的流量从本地加密直通 C,B 只做转发,看不到明文也拿不到你的私钥。

七、8 类失败与定位方法

报错 / 现象 根因 处理
Permissions 0644 for 'id_rsa' are too open 私钥权限 chmod 600
Server refused our key 服务端没开 Pubkey / 公钥没写进去 / 权限 查 sshd_config 与 authorized_keys 权限
Permission denied (publickey) 密钥不匹配或 StrictModes 拒绝 ssh -vvv 看服务端接受哪些方法
Too many authentication failures 本地试了太多钥匙 config 加 IdentitiesOnly yes
REMOTE HOST IDENTIFICATION HAS CHANGED 服务器重装/换 IP,known_hosts 旧指纹冲突 ssh-keygen -R 10.0.0.11 删旧记录
能密码登录,密钥登录仍要密码 PasswordAuthentication 关了但 PubkeyAuthentication 也没生效 sshd -T | grep -i pubkey 看实际生效值
root 密钥登录被拒 PermitRootLogin no 改成 prohibit-password
登录卡住十几秒才出提示 UseDNS yes 反查 DNS / GSSAPI 认证 UseDNS no、GSSAPIAuthentication no

排障万能命令:

ssh -vvv -i ~/.ssh/id_ed25519_ops ops@10.0.0.11 2>&1 | grep -iE "offering|authentications|denied|accepted|trying"

# 服务端实时看日志
sudo tail -f /var/log/secure        # CentOS / RHEL
sudo tail -f /var/log/auth.log      # Ubuntu / Debian

-vvv 输出里的三行是关键:Offering public key(本地有没有送)、Server accepts key(服务端认不认)、Authentication succeeded。卡在哪一行,问题就在哪一层。

👉 服务器日志里的报错太多看不过来,可以把日志段粘进 日志分析工具(浏览器内分析),直接标出错误点和异常 Top。日常命令记不全就查 Linux 命令速查。

八、加固:配通之后还要做的几件事

免密登录本身已经比密码安全得多,但还可以更严:

# /etc/ssh/sshd_config
Port 2222                          # 改端口,噪声扫描能少九成
PermitEmptyPasswords no
MaxAuthTries 3
LoginGraceTime 30
AllowUsers ops deploy              # 白名单,只有这几个用户能登
X11Forwarding no
ClientAliveInterval 300
ClientAliveCountMax 2

再配 fail2ban 拦暴力破解:

sudo yum install -y fail2ban        # Ubuntu: apt install -y fail2ban
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd

改端口的正确顺序:新端口开防火墙 → sshd -t → reload → 新开一个窗口用新端口连 → 连上了再关旧端口。顺序反了就再也进不去了。

九、几条纪律

  1. 改 sshd 配置前先留一个已登录会话,改完用 sshd -t 验语法,用 reload 不用 restart。
  2. 确认密钥能登录之后再关 PasswordAuthentication,不然就把自己锁在门外。
  3. 追加公钥一律用 >>,永远不要用 >。
  4. 私钥 = 身份证,不进 Git、不进镜像、不传网盘;要传给别人让他把公钥给你。
  5. 自动化用的密钥单独一把、不带 passphrase,并在服务端用 command= 前缀限制它只能执行固定命令。
  6. 每台机器、每个人用不同密钥,出事时能精确定位是哪一把泄露。

十、延伸阅读

👉 相关在线工具:SSH 连通检测 · Linux 命令速查 · 网络延迟测试,全部免登录、数据不上传服务器。

还有 65 个免费在线工具

纯前端实现,不用注册,数据不上传服务器。

浏览全部工具