跳转到内容
严选跨境网络服务与流媒体推荐
实机测速保障 · 专属折扣
声明:以上服务由影迷漫游评测实验室进行晚高峰抽测与流媒体解锁验证。专属链接包含推广支持,不增加您的购买成本。

SSH 密钥登录完全指南:生成、部署与排障 | VPS 安全防护教程 ​

SSH Key Authentication Security

刚买来的 VPS,服务商给的往往是一组 root 账号加密码。密码能用,但它有个结构性的弱点:只要有人能连上你的 SSH 端口,就可以没完没了地试密码。公网上的扫描器从不停歇,它们不针对你个人,只是不停地敲每一台暴露在外的服务器的门,字典里的弱口令、泄露过的口令、常见组合,一轮一轮地过。密码再复杂,也只是一道可以被反复尝试的关卡。

密钥登录换了一种思路:登录凭证不再是一串可以被猜到的字符,而是一对数学上绑定的密钥。没有私钥,任对方算力再强也推不出登录凭证;同时你也不用再把密码记在脑子里、写在便签上、贴进脚本里。本文就按实际操作的顺序走一遍:先讲清密钥对够用的原理,再生成、再部署、再关掉密码登录,最后把多设备管理和排障一次讲透。

密钥对原理:够用的一小节 ​

一对 SSH 密钥由两部分组成。私钥留在你自己的电脑上,相当于钥匙,绝不能离开你的设备;公钥放到服务器上,相当于锁,公开了也没关系。登录时,服务器拿公钥出一道只有对应私钥才能解的题,你的电脑用私钥解开,服务器验证通过就放行。整个过程里私钥本身从不经过网络,密码登录那种“凭证在传输中被截获”的风险也就不存在了。

还有两个概念要在动手前分清。第一是 passphrase,也就是给私钥本身再加的一道口令。设了它,别人即使偷走了你的私钥文件,没有这道口令也用不了;代价是你每次使用私钥都要多输一次口令,除非交给 ssh-agent 托管。第二是密钥算法,现在首选 Ed25519,又短又快又安全;只有连很老系统、对方明确不支持 Ed25519 时,才退回 RSA 并把长度拉到 4096 位。理解了这两点,后面每一步的取舍就都有依据了。

生成密钥对 ​

在你日常用的电脑上打开终端,Windows 用 PowerShell,macOS 用 Terminal,Linux 直接用终端。生成 Ed25519 密钥的命令只有一行:

bash
ssh-keygen -t ed25519 -C "你的邮箱@example.com"

这里的 -t 是算法,-C 后面跟的注释一般写邮箱,纯粹是备注,方便以后认出这把钥匙属于哪台电脑、哪个人。命令跑起来会连问三个问题。第一个问保存路径,直接回车用默认位置,也就是用户目录下的 .ssh 文件夹,文件名默认是 id_ed25519。第二个问 passphrase,按上面说的取舍决定:自己的主力电脑、磁盘本身有加密,可以留空图方便;共用电脑、经常带出门的笔记本、生产环境的密钥,一定要设一个强口令。第三个是重复确认。

跑完之后,.ssh 目录里会多出两个文件:id_ed25519 是私钥,id_ed25519.pub 是公钥。可以用下面两条命令确认它们在不在、长什么样:

bash
ls -la ~/.ssh/
cat ~/.ssh/id_ed25519.pub

公钥内容是一行以 ssh-ed25519 开头的长串字符,后面跟着你写的注释。检查时只看这一行是否完整,千万不要把私钥文件的内容贴到任何聊天窗口、工单系统或者代码仓库里。私钥一旦出现在不属于你的地方,就等于钥匙被复印了,再怎么删都不能保证没有副本,只能作废重做。

如果目标服务器实在太老、不认 Ed25519,再生成一对 RSA 的备用钥匙:

bash
ssh-keygen -t rsa -b 4096 -C "你的邮箱@example.com"

注意不要把两对钥匙混用文件名。生成第二对时用 -f 指定一个新名字,例如 ~/.ssh/id_rsa_old,否则默认路径会把第一对覆盖掉。覆盖没有确认之外的补救办法,旧私钥一旦被覆盖,对应服务器的登录凭证就没了,只能走救援通道重做。

把公钥部署到服务器 ​

公钥生成在本地,还得放到服务器上对应的位置才生效。服务器认的其实就是一句话:某个用户的 ~/.ssh/authorized_keys 文件里列出的公钥,才有资格登录这个用户。所以部署的本质,就是把你的公钥文本追加进那个文件,并且把相关权限收紧。下面三种方法殊途同归,选顺手的即可。

用 ssh-copy-id,一条命令搞定 ​

macOS、Linux 和较新的 Windows 都自带 ssh-copy-id,这是最省事的办法:

bash
ssh-copy-id 用户名@服务器地址

它会先让你输一次服务器密码,然后自动完成建目录、追加公钥、改权限三件事。第一次用它的人常犯的错是把用户名写错,比如服务器上只有普通用户,却往 root 账号下写,结果登录时用的用户和授权的用户对不上,自然被拒绝。部署前先确认你要用哪个用户日常登录,就往哪个用户的家目录里写。

如果你一次要管好几台服务器,可以把地址写进一个列表文件,循环跑 ssh-copy-id。跑之前先确认列表里的每一台都通、密码都对,否则中途卡住,后面的也就没跑成,事后还得一台台核对。

手动粘贴,适合命令不好使的时候 ​

有些 Windows 环境或者精简过的系统上没有 ssh-copy-id,那就手动来。先在本地把公钥文件内容完整复制出来,注意必须是一整行,中间不能断、两头不能多空格。然后用密码正常登录服务器,依次做三件事:建 .ssh 目录并收紧权限,用编辑器打开 authorized_keys,把公钥粘贴进去保存,最后把这个文件的权限也收紧:

bash
mkdir -p ~/.ssh
chmod 700 ~/.ssh
nano ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

手动粘贴最常见的翻车点是换行。公钥被从终端里复制出来时,有的终端会在长行中间自动折行,粘贴后就变成了两行,服务器读到断开的公钥会直接忽略。粘贴完先用 cat 看一眼,确认公钥确实占一整行,再退出。另一个坑是编辑器自动加的尾巴空格,同样会让整行失效,粘贴时尽量用纯文本方式,不要经过富文本编辑器中转。

用 scp 中转,适合批量习惯 ​

第三种办法是把公钥文件先传到服务器的临时目录,再在服务器上追加进 authorized_keys,最后删掉临时文件:

bash
scp ~/.ssh/id_ed25519.pub 用户名@服务器地址:/tmp/
ssh 用户名@服务器地址
mkdir -p ~/.ssh
cat /tmp/id_ed25519.pub >> ~/.ssh/authorized_keys
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
rm /tmp/id_ed25519.pub

这里有个细节值得强调:追加用的是 >>,不是 >。前者是追加,后者是覆盖。如果你服务器上已经有别的设备、别的同事的公钥,一个 > 就会把它们全清空,别人当场就登不上来了。临时文件用完要删,虽然公钥本身可以公开,但留在 /tmp 里既不整洁,万一之后有人误操作拿它当私钥用,又会生出新的麻烦。

先测通,再关密码登录 ​

这一步的顺序绝对不能反。部署完公钥,先不要动任何配置,另开一个终端窗口,用密钥试登一次:

bash
ssh 用户名@服务器地址

如果这次没有问你要密码就直接进去了,说明密钥链路已经通了。这时候再去关密码登录。关的方法是编辑服务器上的 SSH 服务配置,把密码认证关掉,同时把空密码也禁掉:

text
PasswordAuthentication no
PermitEmptyPasswords no

改之前先确认这两行前面没有 # 注释符,有的话要删掉,否则改了等于没改。保存后重启 SSH 服务让配置生效,Debian 和 Ubuntu 上服务名一般叫 ssh,其他发行版多叫 sshd,哪个名字能用就用哪个:

bash
systemctl restart sshd

重启之前务必保证手头有一个已经登录着的旧会话不要断开,万一新配置有问题,还能在这个会话里改回去。另一个保底手段是服务商的网页控制台,也就是常说的 VNC 救援通道,它不走 SSH,专门用来在你把自己锁在外面时翻盘。确认这两样都在,再重启服务。

关于要不要顺手做其他加固,这里给一个分寸感。禁掉 root 直接登录、只放行指定用户、关掉用不上的转发,这些都值得做,但前提是先建好一个普通用户并确认它能用密钥登录,否则禁 root 等于自断后路。改 SSH 端口这件事经常被神化,其实它防不住定向扫描,只能减少日志里无意义的敲门记录,属于降噪音而非真安全,想改可以改,但别把它当成替代密钥登录的方案。至于 Fail2ban 这类自动封禁工具和双因素认证,都是在密钥登录之上的加层,等密钥链路稳定了再上也不迟。

多设备、多密钥怎么管 ​

一台电脑一把钥匙,是管理密钥最省心的一条纪律。主力电脑、备用笔记本、家里的台式机各生成各的,服务器上只是多几行公钥,谁的设备丢了就删哪一行,不用牵连其他设备。反过来,把同一份私钥文件拷到所有设备上,看似省事,实则任何一台设备出事,所有服务器都要换钥匙,代价大得多。

钥匙一多,登录命令就会变长,这时就该用客户端配置文件来收纳。在本地的 ~/.ssh/config 里给每台服务器起个别名,把用户、端口、私钥路径写进去:

text
Host 我的服务器
    HostName 服务器地址
    User 用户名
    Port 22
    IdentityFile ~/.ssh/id_ed25519

Host 工作机
    HostName 另一台服务器地址
    User 用户名
    IdentityFile ~/.ssh/work_key

写好之后,登录就简化成 ssh 我的服务器,不用每次都背地址和参数。配置文件的权限同样要收紧到只有自己可读写,否则 SSH 客户端会因为权限过松而拒绝使用它。别名里的主机名可以起中文以外的任意名字,关键是自己一眼能认出来,多年以后回看也不至于猜。

ssh-agent 是另一件值得配好的工具。它的作用是把解锁后的私钥缓存在内存里,设了 passphrase 的人不用每次连接都重复输入。启动并添加私钥只要两条命令:

bash
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519

macOS 用户还可以把钥匙串集成进来,让系统在登录时自动解锁,省去每次手动启动。需要提醒的是,agent 缓存的是解锁状态,电脑离开视线时最好养成锁屏的习惯,否则别人坐到你的电脑前就等于拿到了你的钥匙。

密钥的退役和轮换也要有节奏。员工离职、项目结束、设备出售、怀疑泄露,任何一种情况发生时,第一时间删掉服务器上对应的公钥行,而不是等到“有空再说”。日常可以每隔一段时间打开 authorized_keys 看一眼,每一行后面的注释就是当初写下的备注,对不上号的、想不起来的,一律先核实再保留。轮换没有硬性的周期表,关键节点换一次,远比定个一年期限却从不执行要实在。

权限收尾:为什么总卡在权限上 ​

密钥登录最常见的失败原因不是密钥本身,而是权限。SSH 服务端有一条硬性检查:用户家目录、.ssh 目录和 authorized_keys 文件的权限必须收得足够紧,否则它会认为这些文件可能被别人动过,宁可拒绝登录也不冒险。标准收法是三条:

bash
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod 600 ~/.ssh/id_ed25519

目录 700 表示只有所有者能进,文件 600 表示只有所有者能读写。私钥文件同样是 600,公钥文件可以放宽到 644,因为它本来就是公开的。很多人用图形界面传文件或者用 root 解压备份,都会把权限带偏,部署完第一件事就是核对这三处。另外家目录本身的权限如果被放得太开,服务端同样可能拒绝,这一点在排查时经常被忽略,值得单独记一笔。

私钥的保管是另一条底线。备份要做,但要备份到加密的地方:加密 U 盘、支持附件的密码管理器、或者同样加密的离线存储,至少两处,互相独立。千万不要把私钥放进代码仓库,哪怕是私有仓库,仓库的访问面一旦扩大,私钥就等于公开了;也不要用聊天工具、邮件附件、网盘直链传私钥,传一次就多一次失控的风险。重装电脑、换硬盘之前,先确认私钥备份能用,再动原机器,否则新机器装好才发现钥匙没了,服务器就只能走救援通道。

排障:按现象查,不要乱试 ​

连不上,报 Permission denied (publickey) ​

这是最常见的报错,意思是服务器不接受你给的任何公钥,排查按这个顺序来,查到哪一步通了就停。

先在服务器端核对权限链:.ssh 是不是 700,authorized_keys 是不是 600,家目录权限有没有被放开。权限错是最常见的原因,修好不用重启服务,下一条登录立刻生效。再看公钥本身:是不是一整行、有没有被折断、有没有首尾空格、有没有把私钥内容误粘进去。私钥和公钥长得很像,粘错了服务器是认不出来的。

然后看服务端的配置有没有把密钥登录关掉,或者把登录用户限制住了。有些加固教程会顺手写上只允许某个用户登录,之后换用户就登不上了,排查时把这条也算进去。如果是 CentOS、RHEL 这类带 SELinux 的系统,还要考虑安全上下文被改乱的情况,用恢复上下文的命令把 .ssh 目录刷一遍往往就好了。

最后看日志。客户端用详细模式跑一次,日志里会写清它试了哪些钥匙、服务器为什么拒绝:

bash
ssh -vvv 用户名@服务器地址

服务端则看认证日志,Debian 系一般在 /var/log/auth.log,新一点的系统用 journalctl -u sshd。两边的日志对照着看,原因基本藏不住。

根本连不上:拒绝、超时分开看 ​

Connection refused 和 Connection timed out 是两种完全不同的病。前者说明包到了服务器但没有服务在听,查 SSH 服务有没有跑起来、端口有没有改、配置里的端口和你连的端口是不是同一个。后者说明包根本没到,查防火墙、安全组、服务器地址有没有写错、本地网络有没有出墙限制。把两种报错混在一起试,换端口、重启服务、重装密钥全上一遍,只会越查越乱。

端口问题还有个变种:你改了服务端口却忘了改客户端的连接参数,或者客户端配置里还写着旧端口。排查时先在服务器本地用默认方式连一次,确认服务本身是好的,再一层层往外查网络和配置。

密钥格式问题:多半出在复制和系统差异上 ​

从 Windows 复制出来的密钥文本有时会带上回车符,服务器读到会把它当成非法字符,表现就是密钥明明在文件里却始终不被接受。处理办法是重新用纯文本方式复制,或者在服务器上用工具去掉回车符。私钥文件本身如果被 Windows 编辑器改写过格式,也会出现类似问题,尽量不要用图形编辑器去动密钥文件。

另一种格式问题来自新旧系统混用。很老的服务器可能不支持 Ed25519,这时客户端会直接跳过这把钥匙,日志里能看到它试了又放弃。解决办法是按前面说的,单独生成一对 RSA 备用钥匙,在客户端配置里给这台老服务器指定走那把钥匙,而不是把所有服务器的默认钥匙都换成 RSA。

还有一种情况是 passphrase 忘了。私钥本身没有“找回密码”的机制,忘了解决办法只有一个:作废这把钥匙,生成新的,重新部署公钥。所以 passphrase 最好记在密码管理器里,而不是只记在脑子里,更不要写在和私钥同一个目录的文本文件里,那等于把锁和钥匙放在同一个抽屉里。

把自己锁在外面了,怎么翻盘 ​

先别慌,按代价从小到大试。第一是服务商的 VNC 网页控制台,它不依赖 SSH,能直接给你一个本地终端,在里面把密码登录临时打开,或者把新的公钥写进去,修好后再关回去。第二是其他已经配好密钥的设备,换一台能登录的机器进去修。第三是服务商提供的密码重置或者救援模式,大多数厂商都有,只是流程慢一点,需要身份验证。

翻盘之后要做两件事复盘:第一,确认到底是哪一步把自己锁住的,是关密码登录太早,还是改配置时手滑;第二,补一个备用登录路径,比如第二把密钥、第二个管理员用户,或者至少保证 VNC 通道一直可用。没有备用路径的服务器,等于只有一把钥匙的房子,丢一次就得砸门。

日常习惯:让密钥登录一直可靠 ​

密钥登录配好不是一劳永逸,它需要一点日常维护。每个季度花几分钟做三件事:打开各台服务器的 authorized_keys,删掉已经没人用的行;确认自己的私钥备份还能解密、还能用;看一眼最近的登录记录,有没有不认识的来源。这三件事做下来,密钥体系就不会在不知不觉中烂掉。

还有一个容易被忽略的习惯:给每把钥匙留一份用途记录。哪把钥匙在哪台电脑上生成、对应哪几台服务器、什么时候部署的,记在密码管理器的一条笔记里。半年后回看,你能立刻分清哪一行公钥可以删、哪一把私钥必须留着,而不是对着一堆以日期命名的文件猜。服务器一多,这份记录省下的排查时间,远比写它花的时间多。

回过头看,密钥登录的全部要领其实可以浓缩成几句话:私钥不出本机,公钥只进 authorized_keys,权限收紧到 700 和 600,先测通再关密码登录,一机一钥、离职即删。把这几条做扎实,公网上那些没日没夜的扫描器,对你的服务器就只剩下敲门声了。


延伸阅读 ​

免责声明

本文仅供技术交流和学习参考。涉及第三方服务的链接可能包含 sponsored 标记,请自行核实服务条款、价格和可用性,并遵守当地法律法规。