SSH 免密登录:从生成到关掉密码登录
免密登录本身五分钟就能配好,麻烦的是配完之后偶尔失效,而报错信息又只有一句
Permission denied (publickey)。这篇把能想到的原因都列一遍。
一、生成一对密钥
ssh-keygen -t ed25519 -C "alin@laptop"
-t ed25519:现在的默认推荐,密钥短、签名快,兼容性已经足够。- 老系统不支持 ed25519 时退回
-t rsa -b 3072;2048位也还能用,但没必要再新建。 -C是注释,会附在公钥末尾,用来区分「这把钥匙是哪台机器的」,不影响认证。- 口令(passphrase)建议设。设了之后可以用
ssh-agent免去反复输入。
生成后目录里有两个文件:
~/.ssh/id_ed25519私钥,任何情况下不外传。~/.ssh/id_ed25519.pub公钥,这一行文本就是可以随便给出去的部分。
二、把公钥放到服务器上
# 最简单的方式
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@host
# 没有 ssh-copy-id 时手动追加
cat ~/.ssh/id_ed25519.pub | ssh user@host \
'mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys'
三、权限:90% 的「密钥没生效」都在这里
sshd 有一套严格检查(StrictModes,默认开启),不满足就静默忽略这把密钥,只回一句 publickey 失败:
~/.ssh权限必须是 700。~/.ssh/authorized_keys必须是 600。- 家目录本身不能被 group 或其他用户写:
755、750都行,777不行。 - SELinux 开启的系统上,文件的安全上下文也要对,否则同样被拒。
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod go-w ~ # 去掉家目录的组写和其他人写权限
查失败原因最快的办法是让 sshd 说出细节:
# 服务端(需要 root)
sshd -T | grep -E "strictmodes|pubkeyauthentication|authorizedkeysfile"
tail -f /var/log/auth.log # Debian/Ubuntu
tail -f /var/log/secure # RHEL/CentOS
# 客户端
ssh -vvv user@host # 看它到底试了哪把钥匙
四、关掉密码登录
确认密钥能正常登录之后,再改 /etc/ssh/sshd_config 这三项:
PubkeyAuthentication yes
PasswordAuthentication no
PermitRootLogin prohibit-password
PermitRootLogin prohibit-password 的意思是「root 只能用密钥登录,不能用密码」,
比直接 no 宽松一点,救急时还能进。
改完不要立刻断开当前的连接。先
systemctl reload sshd, 然后另开一个窗口试登录,成功了再关旧窗口。 直接改完退出是把自己锁在门外最经典的方式。
五、客户端 config:把长命令变成别名
~/.ssh/config(权限 600)里可以写:
Host db
HostName 10.0.0.12
User alin
Port 2222
IdentityFile ~/.ssh/id_ed25519
Host *
ServerAliveInterval 30
ServerAliveCountMax 3
之后 ssh db 就够了。ServerAliveInterval 那两行是给容易断线的网络用的:
每 30 秒发一个保活包,连续 3 次没回应才判定断线。
六、host key 变了怎么办
重装系统或换机器后首次连接会看到一大段警告:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
这是 SSH 在提醒你「对面这台机器的身份变了」,可能是正常的重装, 也可能是中间人。确认是前者之后再删掉旧记录:
ssh-keygen -R host # 按主机名删
ssh-keygen -R 10.0.0.12 # 按 IP 删,known_hosts 里两者是分开的两条
七、ssh-agent 与转发
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519 # 输入一次口令,本次会话内不再问
ssh-add -l # 列出已加载的钥匙
ssh-add -t 2h ~/.ssh/id_ed25519 # 2 小时后自动失效
ssh -A(Agent 转发)能让你从跳板机继续往内网跳而不用把私钥传过去,
但它把 agent 暴露给了远端主机——只在受控的跳板机上用。
一句话总结:公钥进 authorized_keys,权限必须 700 / 600,家目录不能给别人写;改完 sshd_config 先另开一个窗口试,别把自己锁在外面。