新买的 VPS,厂商给你一个 root 密码,你 SSH 上去开始装东西。用密码登录能跑通,但只要这台机器暴露在公网,几小时内就会开始被人试密码 —— 看看 /var/log/auth.log 里的失败登录次数就知道了。
换成密钥登录之后,暴力破解这条路直接断掉:私钥不在服务器上,攻击者猜一万年也没用。这篇把完整流程走一遍,重点讲清楚怎么改才不会被自己锁在门外。
先把这个搞明白,后面所有步骤都顺了。
- 私钥:留在你自己电脑上,永远不要发给任何人、不要上传到服务器。
- 公钥:可以随便给别人,就是要放到服务器上。
登录时服务器拿你手上的私钥出一道题,只有配对的私钥能解 —— 私钥本身从来不会通过网络传输。所以哪怕有人抓走了全部流量,也拿不到你的私钥。
对比一下两种方式:
| 密码登录 | 密钥登录 | |
|---|---|---|
| 能否被暴力破解 | 能,且一直在被尝试 | 不能 |
| 密码复用风险 | 有,别处泄露就完蛋 | 无 |
| 自动化脚本登录 | 要交互输入 | 天然支持 |
| 泄露后的影响 | 对方拿到全部 | 只泄露了这一把 |
注意:密钥不是"更长的密码"。 常见的误解是"我把密码设复杂点就行了"—— 复杂密码防的是猜测,防不住服务器被拿下后读取 /etc/shadow,也防不住你在别处用了同一个密码。
在你自己的电脑上执行,不是服务器上。
ssh-keygen -t ed25519 -C "[email protected]"
一路回车就行,会生成两个文件:
~/.ssh/id_ed25519—— 私钥(不带.pub)~/.ssh/id_ed25519.pub—— 公钥
为什么是 ed25519 而不是 rsa?
Ed25519 从 OpenSSH 6.5(2014 年)就支持了,到现在十来年,客户端兼容性早就不是问题。它的密钥短(公钥只有 68 个字符)、签名快、安全性足够。
RSA 的问题在于:OpenSSH 8.8 起默认禁用了 ssh-rsa 的 SHA-1 签名,因为 SHA-1 在密码学上已经算破了(构造选择前缀碰撞的成本不到 5 万美元)。RSA 密钥本身还能用(会走 SHA-256/512),但如果你要连的设备比较老可能报错。
什么时候才用 RSA:
ssh-keygen -t rsa -b 4096 -C "[email protected]"
只有在目标设备太老、不支持 ed25519 时才需要。比如某些老旧的网络设备、嵌入式系统。普通 Linux VPS 一律用 ed25519。
关于 passphrase(密码短语)
生成时会问你 Enter passphrase。这一步建议不要留空:
- 留空:私钥文件泄露 = 直接被人拿走用,没有第二道防线
- 设了:私钥文件被偷,对方还要破解密码短语
代价是每次用都要输一遍。嫌烦的话后面用 ssh-agent 解决(见下文),别为了省事留空。
-C 后面的注释只是个标签,方便你有多个密钥时区分用途,写邮箱或者 工作本-2026 都行。
最简单的方式:
ssh-copy-id -i ~/.ssh/id_ed25519.pub root@你的服务器IP
它会提示你输一次服务器密码(这是最后一次用密码),然后自动把公钥追加到服务器的 ~/.ssh/authorized_keys。
不是默认端口的话:
ssh-copy-id -i ~/.ssh/id_ed25519.pub -p 2222 root@你的服务器IP
Windows 或 ssh-copy-id 不好使的时候,手动来(先在服务器上执行):
mkdir -p ~/.ssh && chmod 700 ~/.ssh
echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... [email protected]" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
公钥内容用 cat ~/.ssh/id_ed25519.pub 在你本地电脑上取,注意是 .pub 那个文件。搞混了把私钥传上去,等于把钥匙插在门上。
云厂商控制台大多也能直接加公钥 —— 创建实例时粘贴,或者在实例详情页里添加。这样做的好处是重建实例时密钥还在。
SSH 对权限极其严格,这是为了防"同机器上的其他用户偷看你的私钥"。权限不对会直接拒绝登录,而且报错信息有点绕。
正确的权限:
chmod 700 ~/.ssh # 只有你能进这个目录
chmod 600 ~/.ssh/authorized_keys # 只有你能读写
chmod 600 ~/.ssh/id_ed25519 # 本地私钥
chmod 644 ~/.ssh/id_ed25519.pub # 公钥无所谓
还有一个常被忽略的:家目录本身不能对 group 或 other 可写。
ls -ld ~
# 应该是 drwxr-xr-x,不能是 drwxrwxrwx
chmod g-w,o-w ~
家目录要是 777,别人能往你的 ~/.ssh 里塞东西,SSH 会拒绝使用这个密钥。
这一步的顺序是整篇文章最关键的。 顺序错了就是把自己锁在门外,只能开工单或者进 VNC 控制台救。
保持当前这个 SSH 会话不要关,然后新开一个终端窗口测试:
ssh -i ~/.ssh/id_ed25519 root@你的服务器IP
能进去,才继续往下。进不去的话回头检查权限和公钥内容,当前那个会话还开着,你还有退路。
# 想看详细的连接过程,加上 -v
ssh -v -i ~/.ssh/id_ed25519 root@你的服务器IP
看到 Offering public key 和 Server accepts key 就说明密钥认证成功了。
确认密钥能用之后再改服务器配置。先备份原配置:
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%F)
然后改这几项:
sudo sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/^#\?KbdInteractiveAuthentication.*/KbdInteractiveAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/^#\?ChallengeResponseAuthentication.*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/^#\?PubkeyAuthentication.*/PubkeyAuthentication yes/' /etc/ssh/sshd_config
KbdInteractiveAuthentication 那行别漏。 很多人只改了 PasswordAuthentication no,结果发现密码还是能登 —— 因为 Ubuntu 默认开了键盘交互认证,密码走的是 PAM 那条路,跟 PasswordAuthentication 是两扇门。
如果是 root 用户,还要决定要不要允许 root 登录:
# 允许 root 用密钥登录,但禁止用密码(推荐)
sudo sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config
比 no 灵活:还能用 root 密钥登录应急,但密码这条路彻底封死。
云镜像经常在 /etc/ssh/sshd_config.d/ 下放额外的配置文件,它们会覆盖主配置。 这是改了没生效的头号原因。
grep -r "PasswordAuthentication\|PermitRootLogin" /etc/ssh/sshd_config.d/ 2>/dev/null
看到 50-cloud-init.conf 里写着 PasswordAuthentication yes 就很典型 —— 你在主配置里改成 no,它一覆盖,等于白改。要么改这个文件,要么确认主配置里的 Include 顺序在它之后。
主配置里通常有这一行,注意顺序:
Include /etc/ssh/sshd_config.d/*.conf
Include 之后的设置才会覆盖前面的。 所以你要么直接改 sshd_config.d/ 里的文件,要么把自定义配置也放进那个目录(命名成 99-custom.conf 保证最后加载)。
sudo sshd -t
这条命令必须跑。 配置有语法错误的话,重载会失败 —— 运气好旧配置还在,运气不好 sshd 直接停了,你就进不去了。
sshd -t 没输出就是没问题。然后:
# Ubuntu / Debian
sudo systemctl reload ssh
# RHEL / Rocky / AlmaLinux
sudo systemctl reload sshd
用 reload 而不是 restart —— reload 不中断现有连接,restart 会。你现在这个会话就是现有连接,断了就麻烦了。
当前会话继续保持,再新开一个终端:
ssh root@你的服务器IP
能免密进去,说明成功。然后故意试试密码登录,确认它真的被拒了:
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no root@你的服务器IP
# 应该直接报 Permission denied (publickey)
两个测试都过了,才可以关掉最开始那个旧会话。
连的机器一多,ssh -i ~/.ssh/xxx -p 2222 [email protected] 这种命令就记不住了。
在本地 ~/.ssh/config 里配置别名:
Host vps1
HostName 203.0.113.10
User root
Port 22
IdentityFile ~/.ssh/id_ed25519
Host blog
HostName 203.0.113.20
User deploy
Port 2222
IdentityFile ~/.ssh/id_ed25519_blog
之后直接 ssh vps1 就能连上。这个文件也支持通配符,比如给一批机器统一配置保活:
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
AddKeysToAgent yes
ServerAliveInterval 60 每 60 秒发一个保活包,能有效缓解"闲置几分钟就断线"的问题(有些 NAT 设备会清理闲置连接)。还是断的话看 SSH 总是断开怎么办。
注意 ~/.ssh/config 的权限,太开放同样会被拒:
chmod 600 ~/.ssh/config
两种情况,处理方式不一样。
一台电脑连多台服务器:给每台(或每组)生成一把独立的密钥,用 -f 指定文件名:
ssh-keygen -t ed25519 -C "blog-server" -f ~/.ssh/id_ed25519_blog
然后在 config 里用 IdentityFile 指过去。不要所有服务器共用一把钥匙 —— 一台机器被拿下,等于所有机器都暴露。
多台电脑连同一台服务器:每台电脑生成自己的密钥,把各自的公钥都追加到服务器的 authorized_keys 里(一个文件可以放多把公钥,一行一把)。
好处是每台设备独立:笔记本丢了,只删掉那一行就行,其他设备不受影响。
# 服务器上查看当前有哪些公钥
cat ~/.ssh/authorized_keys
# 删掉某一台设备的那行之后,这台设备立刻失去访问权
每行末尾的注释(-C 那个)这时候就有用了 —— 用 工作本-2026 这种能看懂的标签,比一堆 user@localhost 强得多。
设了密码短语之后,每次连接都要输一遍很烦。ssh-agent 可以把解密后的私钥缓存在内存里:
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
输一次密码短语,之后这个会话里就不用再输了。重启电脑后要重新加。
macOS 用户可以直接写进 ~/.ssh/config,让它自动加:
Host *
AddKeysToAgent yes
UseKeychain yes
Windows 用户(Win10 1809+ / Win11 自带了 OpenSSH):
# 以管理员身份运行,设置 ssh-agent 开机自启
Set-Service -Name ssh-agent -StartupType Automatic
Start-Service ssh-agent
# 然后添加密钥
ssh-add $env:USERPROFILE\.ssh\id_ed25519
方式一:系统自带(推荐)
Windows 10 1809 之后的版本都自带了 OpenSSH 客户端,直接在 PowerShell 或 CMD 里敲 ssh 就行,用法和 Linux 完全一样。
如果提示找不到命令,去「设置 → 应用 → 可选功能」里添加「OpenSSH 客户端」。
方式二:PuTTY
老牌工具,优点是图形化、能保存会话。注意它用的是自己的 .ppk 密钥格式,OpenSSH 的私钥要先用 puttygen 转换:
puttygen → Conversions → Import key → 选择 id_ed25519 → Save private key
新版 PuTTY 支持 ed25519,直接转换就行。
方式三:图形客户端
Termius、MobaXterm、FinalShell 这类。好处是内置文件传输和端口转发。用第三方客户端要注意密钥存哪 —— 存在云端账号里的,等于把私钥交给了第三方。
Permissions 0644 for 'xxx' are too open / UNPROTECTED PRIVATE KEY FILE
本地私钥权限太松。Windows 上遇到这个(一般是 WSL),执行 chmod 600 ~/.ssh/id_ed25519。
Permission denied (publickey)
服务器拒绝了你的密钥。按顺序排查:
ssh -v user@host # 看详细过程
看输出里的关键行:
- 没有
Offering public key—— 本地没找到对应密钥,检查-i路径或 config - 有
Offering但被拒 —— 服务器上的authorized_keys内容不对,或者权限问题 - 服务器端看日志:
sudo tail -f /var/log/auth.log
完整排查清单见 SSH Permission denied 怎么办。
改完配置连不上了
别慌,先看是哪种情况:
- 当前旧会话还开着 —— 直接改回去,
sudo sshd -t && sudo systemctl reload ssh - 全断了但有 VNC 控制台 —— 进控制台改回来
- 都没有 —— 进救援模式,见 VPS 救援模式怎么用
如果是防火墙或者 Fail2Ban 造成的,看 开启 UFW 后 SSH 进不去怎么办 和 被 Fail2Ban 误封怎么办。
Host key verification failed
服务器重装过,主机密钥变了。清掉本地记录:
ssh-keygen -R 你的服务器IP
警告:如果你没有重装系统却看到这个消息,要当成安全事件处理 —— 可能是中间人攻击。
改了端口之后连不上
ssh 要加 -p 新端口,scp 要用 -P(大写)。另外防火墙要放行新端口,fail2ban 的配置也要跟着改。
私钥丢了(电脑坏了、误删了):
只要还有一台设备能登进去,把新设备的公钥加进 authorized_keys 就行。如果所有设备都进不去 —— 走 VNC 控制台或者厂商的救援模式,重新加公钥或者临时开一次密码登录。
这也是为什么要保留至少一台备用设备或者把私钥备份在安全的地方(加密的密码管理器、加密 U 盘)。
私钥泄露了(电脑丢了、误传了):
立刻登录服务器,把那把公钥从 authorized_keys 里删掉。这是一行的事,删掉之后那把私钥立刻失效。
# 先备份
cp ~/.ssh/authorized_keys ~/.ssh/authorized_keys.bak
# 编辑,删掉泄露的那行
vim ~/.ssh/authorized_keys
顺手检查一下有没有异常的密钥被人加进来:
cat ~/.ssh/authorized_keys
# 或者看最近的修改时间
stat ~/.ssh/authorized_keys
authorized_keys 里出现了你不认识的公钥,说明机器已经被入侵了 —— 这不是改配置能解决的,处置流程见 VPS 被入侵后的 24 小时处置清单。
密钥登录解决了"猜密码",但安全加固不止这一件事:
- 改 SSH 端口 —— 降低被扫描的概率(不是真正的安全措施,但能大幅减少日志噪音)
- 防火墙 —— 只放行需要的端口,见 VPS 安全加固指南
- Fail2Ban —— 装了密钥登录之后,它对 SSH 的意义下降,但保护其他服务还有用
- 自动安全更新 —— 见 自动安全更新和重启计划
- 禁止 root 直接登录 —— 建普通用户 + sudo,出问题时审计更清楚
别在 SSH 上暴露的服务:数据库、Redis、Docker socket。要远程访问走 SSH 隧道,不要直接把端口开出去,见 VPS 数据库不要直接暴露公网。
禁用密码登录之后,厂商的控制台还能进吗?
能。VNC / Console 是走另一条路的,不受 sshd 配置影响。这也是为什么买机器时一定要确认有控制台。
要不要把 root 登录完全禁掉?
建议 PermitRootLogin prohibit-password 而不是 no。建普通用户用 sudo 是更好的实践,但保留 root 密钥登录在应急时很有用 —— 比如 sudo 配置被改坏了,普通用户提不了权。
密钥能设有效期吗?
OpenSSH 原生不支持。要做到这点得用证书认证(SSH CA)或者集中式方案(比如 Keycloak 单点登录 那种),个人和小团队用不上。
多台机器共用一把密钥行不行?
技术上可以,安全上不建议。一台机器被拿下,所有机器一起失守。而且想撤销时只能到处改。
Windows 自带的 ssh 和 Git Bash 的 ssh 冲突怎么办?
会冲突。用 where ssh 看实际调用的是哪个,或者统一用其中一个,把另一个从 PATH 里调整顺序。
换了新电脑,旧电脑的密钥要删吗?
要。旧设备不再用了就把那行从 authorized_keys 删掉。留着等于多一把不知道在谁手上的钥匙。
用密码管理器存私钥安全吗?
比自己随手放桌面安全得多。至少 1Password、Bitwarden 这类是加密存储的。但最稳妥的还是物理隔离 —— 私钥只存在你常用的那台设备上,另配一把备用密钥存在加密介质里。
- VPS 安全加固指南 — 密钥之后还要做防火墙、Fail2Ban、自动更新
- SSH Permission denied 怎么办 — 密钥配好了还是进不去
- SSH 总是断开怎么办 — 连接不稳定、空闲就掉线
- VPS 连接不上怎么办 — 完全连不上的排查顺序
- 域名怎么解析到 VPS — 用域名替代 IP 连接,配上 ssh config 更好记
