
1. 为什么放弃密码登录转向密钥认证如果你手里管着几台甚至几十台 Linux 服务器还在用ssh userhost然后手动敲密码的方式登录那大概率经历过下面这些场景密码太长记不住只好所有机器用同一个团队里有人离职第一反应是挨个改密码半夜收到告警说某台机器有大量失败登录记录心里一紧。这些问题归根结底都指向同一个原因——密码这种认证方式天生就不适合用在自动化、规模化的远程管理场景里。SSH 密钥登录解决的正是这个核心痛点。它的原理不复杂你生成一对数学上关联的密钥一把叫私钥自己保管绝不外传另一把叫公钥放到目标服务器的指定位置。登录时服务器用公钥出一道“题”只有持有对应私钥的客户端才能解出来解对了就放行。整个过程私钥从不在网络上传输也不存在被暴力猜解的可能。相比密码它的优势是压倒性的抗暴力破解2048 位以上的密钥穷举在算力上不可行、可自动化脚本、CI/CD 流程无需人工干预、易撤销删掉公钥即可收回权限不影响其他人。这篇文章面向的是刚接触 Linux 服务器运维的开发者、需要管理多台主机的后端工程师以及任何想让自己远程登录更安全、更省事的人。我会从密钥生成一路讲到服务端配置、权限设置、常见报错排查把每一步背后的“为什么”都讲清楚。你跟着走一遍基本就能在自己的 Ubuntu 机器上把密钥登录跑通并且知道出了问题该往哪个方向查。2. 动手前的整体思路与方案选型2.1 密钥登录的完整链路拆解很多人照着教程敲命令成功了也不知道为什么成功失败了更不知道怎么查。所以动手之前先把整条链路在脑子里过一遍。一次密钥登录实际上经历了这么几个阶段客户端生成密钥对在本地机器上执行ssh-keygen得到私钥如id_ed25519和公钥如id_ed25519.pub。公钥上传到服务器把公钥内容追加到服务器上目标用户的~/.ssh/authorized_keys文件里。客户端发起连接ssh命令带上私钥或使用默认路径向服务器请求认证。服务器校验服务器读取authorized_keys用其中的公钥验证客户端是否持有匹配的私钥。权限检查服务器会检查.ssh目录和authorized_keys文件的权限权限不对直接拒绝这是新手最容易踩的坑。服务端配置放行sshd_config里必须允许公钥认证PubkeyAuthentication yes否则前面全白搭。理解这条链路的意义在于任何一步出问题登录都会失败而报错信息往往只给一个笼统的“Permission denied”。知道链路你就能逐段排查而不是盲目重试。2.2 密钥算法怎么选RSA、ECDSA 还是 Ed25519ssh-keygen默认可能生成 RSA 密钥但现在我更推荐Ed25519。原因有三点。第一安全性Ed25519 基于椭圆曲线同等安全强度下密钥短得多且没有 RSA 那些历史遗留的实现陷阱。第二性能签名和验证速度更快连接建立更迅速。第三密钥长度Ed25519 公钥只有短短一行复制粘贴到authorized_keys里不容易出错而 RSA 4096 的公钥是一大坨。如果你有兼容性顾虑——比如要连一些非常老的设备——那 RSA 仍然是保底选择但请至少用 4096 位。ECDSA 介于两者之间兼容性比 Ed25519 好一些但不如 RSA 通用。我的建议很直接新部署一律用 Ed25519遇到连不上的老古董再退回 RSA 4096。算法推荐密钥长度兼容性相对优势Ed25519固定 256 位较新系统良好短、快、安全RSA4096 位极好通用性最强ECDSA521 位中等折中方案2.3 是覆盖默认密钥还是新建专用密钥ssh-keygen不加参数会生成~/.ssh/id_ed25519这是默认密钥ssh连接时会自动尝试。方便但有个隐患如果你用同一把默认密钥登录所有服务器一旦某台机器被攻破、私钥泄露所有机器都危险。更稳妥的做法是按用途或按环境生成专用密钥比如~/.ssh/id_ed25519_work、~/.ssh/id_ed25519_personal然后在~/.ssh/config里为不同主机指定不同密钥。这样即使一把泄露影响范围也可控。对于个人练手用默认密钥没问题但只要涉及生产环境我强烈建议走专用密钥这条路。3. 客户端密钥生成与上传实操3.1 生成密钥对的具体命令与参数解读在本地机器你用来发起连接的那台上打开终端执行ssh-keygen -t ed25519 -C your_emailexample.com逐个参数说清楚。-t ed25519指定算法类型这是核心。-C后面跟的是注释通常写邮箱或用途标识它会被附加在公钥末尾方便你在authorized_keys里一眼认出这把钥匙是谁的、干什么用的——机器多了以后这个注释非常有用。执行后会有三段交互保存路径默认~/.ssh/id_ed25519直接回车即可要专用密钥就输入完整路径比如/home/you/.ssh/id_ed25519_work。设置密码短语passphrase这里很多人图省事直接回车留空。留空意味着私钥文件一旦被人拿到就能直接用没有任何二次保护。我的建议是设一个哪怕简单点。设了之后可以用ssh-agent缓存日常使用并不会每次都让你输。确认密码短语再输一遍。生成完成后~/.ssh/下会多出两个文件id_ed25519私钥权限应为 600和id_ed25519.pub公钥权限 644。私钥文件绝对不能改权限、绝对不能外传、绝对不能提交到代码仓库这是铁律。3.2 用 ssh-copy-id 一键上传公钥公钥生成后要放到服务器上。最省事的方式是ssh-copy-idssh-copy-id -i ~/.ssh/id_ed25519.pub userserver_ip这条命令会自动帮你做几件事通过密码登录一次服务器创建~/.ssh目录如果不存在把公钥内容追加到authorized_keys并设置好正确的权限。-i指定要上传的公钥文件不指定的话默认找~/.ssh/id_ed25519.pub。注意ssh-copy-id需要你先能用密码登录一次服务器。如果你已经禁用了密码登录那就得用别的方式传公钥比如通过已有的密钥登录后手动追加或者用带外的方式如控制台操作。3.3 手动上传公钥的完整步骤有些环境没有ssh-copy-id比如某些精简系统或者你想完全掌控过程那就手动来。先在本地查看公钥内容cat ~/.ssh/id_ed25519.pub复制输出的那一整行。然后登录服务器执行mkdir -p ~/.ssh chmod 700 ~/.ssh echo 粘贴刚才复制的公钥内容 ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys这四步的顺序和权限都不能错。mkdir -p保证目录存在且不报错chmod 700让只有属主能进入该目录是追加而不是覆盖避免把已有的公钥冲掉chmod 600让只有属主能读写。权限设置是密钥登录里最容易被忽略、也最容易导致失败的一环后面排查章节会专门讲。3.4 验证密钥登录是否生效上传完先别急着禁用密码登录先验证密钥能不能用。新开一个终端窗口保留当前会话万一失败还有退路执行ssh -i ~/.ssh/id_ed25519 userserver_ip如果没让你输密码就直接进去了说明密钥登录成功。如果还让你输密码说明密钥没生效服务器退回到了密码认证。这时候别慌先看下一节的排查思路。验证通过后再考虑禁用密码登录。4. 服务端 sshd 配置与安全加固4.1 关键配置项逐条说明服务端的配置文件是/etc/ssh/sshd_config。修改前务必备份sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak然后编辑找到并确认以下几项。注意很多配置项在文件里是被注释掉的注释掉意味着使用默认值你需要取消注释并改成想要的值PubkeyAuthentication yes AuthorizedKeysFile .ssh/authorized_keys PasswordAuthentication no PermitRootLogin prohibit-password ChallengeResponseAuthentication no UsePAM yes逐条解释。PubkeyAuthentication yes是开启公钥认证的总开关必须为 yes。AuthorizedKeysFile指定公钥文件的位置默认就是.ssh/authorized_keys一般不用改。PasswordAuthentication no是禁用密码登录这是安全加固的关键一步但一定要在确认密钥登录可用之后再改。PermitRootLogin prohibit-password表示 root 用户只能用密钥登录、不能用密码比直接yes安全得多。ChallengeResponseAuthentication no关掉键盘交互认证堵住另一条可能被利用的密码通道。4.2 修改配置后的重载与验证改完配置不要直接重启服务先用sshd -t检查语法sudo sshd -t没有输出就说明语法没问题。然后重载配置sudo systemctl reload sshd用reload而不是restart因为 reload 不会断开现有连接万一新配置有问题你当前这个会话还在可以改回去。这是运维的基本素养永远给自己留一条退路。重载后再新开一个终端测试密钥登录确认无误后才算真正完成。4.3 禁用密码登录的正确时机我见过太多人一上来就把PasswordAuthentication改成 no结果密钥没配好直接把自己锁在门外只能去云控制台走 VNC 救援。正确的顺序是生成密钥、上传公钥。验证密钥登录成功新开终端测试。确认PubkeyAuthentication yes已生效。再改PasswordAuthentication no。reload 后再次用新终端验证。提示在云服务器上操作时改配置期间始终保持一个已登录的 SSH 会话不要关闭。这个会话就是你的“安全绳”新配置出问题也能通过它改回来。4.4 进一步收紧限制用户与来源密钥登录跑通后如果还想更严可以加几道限制。AllowUsers可以白名单指定哪些用户能登录AllowUsers deploy admin这样即使系统里有其他账户也无法通过 SSH 登录。还可以用Match块针对特定用户或组做更细的策略比如只允许某个用户从特定网段登录。这些属于进阶加固按需使用但思路是一致的默认拒绝按需放行。5. 权限、属主与常见报错排查5.1 权限问题是密钥登录失败的头号原因SSH 对权限的检查近乎偏执这是有道理的如果authorized_keys或.ssh目录对其他人可写那任何人都能往里塞公钥密钥认证就形同虚设。所以服务器会严格校验权限不对直接拒绝而且报错信息往往很含糊。正确的权限组合是路径权限属主~家目录755 或 700用户本人~/.ssh700用户本人~/.ssh/authorized_keys600用户本人私钥客户端600用户本人家目录权限也常被忽略。如果家目录是 777 或属主不对SSH 同样会拒绝。用ls -ld ~ ~/.ssh ~/.ssh/authorized_keys一眼就能看出问题。5.2 用 -v 参数定位失败环节密钥登录失败时最有效的排查手段是加-vverbose参数ssh -v -i ~/.ssh/id_ed25519 userserver_ip它会打印整个握手过程。重点看这几行Offering public key表示客户端把公钥发过去了Server accepts key表示服务器认可这把钥匙Authentication succeeded才是真正成功。如果卡在Offering public key之后没有Server accepts key多半是服务器端authorized_keys里没有这把公钥或者权限不对。如果连Offering都没有可能是客户端没找到私钥检查-i路径。想看更详细的服务端日志可以在服务器上查/var/log/auth.logUbuntu 默认位置里面会明确写出拒绝原因。5.3 常见问题速查表现象可能原因解决方向仍提示输入密码公钥未生效回退到密码认证检查 authorized_keys 内容与权限Permission denied (publickey)权限不对或公钥不匹配核对权限、比对公钥指纹连接被拒绝sshd 未运行或端口不对systemctl status sshd检查服务改了配置后连不上配置语法错误或禁用了唯一可用方式用保留会话改回sshd -t查语法提示私钥权限过于开放私钥权限不是 600chmod 600私钥文件5.4 几个容易忽略的细节第一公钥要整行复制包括开头的ssh-ed25519和结尾的注释少一个字符都不行。第二换行问题手动追加时确保公钥独占一行不要和已有内容挤在一起。第三多把公钥authorized_keys里可以放多行每行一把公钥方便多台客户端登录同一账户。第四SELinuxUbuntu 默认不开 SELinux但如果你在别的发行版上操作SELinux 的上下文也可能导致失败需要用restorecon修复。这些细节平时不显眼出问题时却能折腾你半天。6. 多主机管理与密钥生命周期维护6.1 用 ssh config 简化日常连接密钥多了、主机多了以后每次敲ssh -i ~/.ssh/id_ed25519_work user192.168.1.100太累。在本地~/.ssh/config里配置别名Host work-server HostName 192.168.1.100 User deploy IdentityFile ~/.ssh/id_ed25519_work Port 22配好之后直接ssh work-server就能连密钥、用户、端口全自动匹配。这个文件支持通配符和Host *全局配置机器一多效率提升非常明显。我自己的习惯是每台常用主机都配一个别名几个月不用的机器也能靠别名快速回忆起来是干什么的。6.2 密钥轮换与撤销的正确做法密钥不是配一次就一劳永逸。人员变动、设备更换、怀疑泄露都需要处理。撤销很简单登录服务器编辑authorized_keys删掉对应那一行即可不影响其他密钥。轮换则是定期更换密钥对尤其是长期使用的密钥。做法是生成新密钥、上传、验证、再删除旧公钥全程不影响服务。建议给密钥注释里写上生成日期或用途方便日后判断哪把该退休了。6.3 ssh-agent 与密码短语的配合前面建议给私钥设密码短语但每次连接都输一遍确实烦。ssh-agent就是解决这个矛盾的它把解密后的私钥缓存在内存里一次输入会话内多次使用。启动并添加eval $(ssh-agent -s) ssh-add ~/.ssh/id_ed25519之后同一终端会话里再连接就不需要重复输入了。这样既保留了密码短语的安全价值又兼顾了使用便利。安全和便利从来不是非此即彼关键是找到合适的平衡点ssh-agent 就是密钥登录场景下的那个平衡点。6.4 备份策略私钥丢了怎么办私钥一旦丢失且没有备份就只能重新生成、重新上传服务器本身不受影响但如果你禁用了密码登录又没有其他可用密钥那就麻烦了。所以私钥需要备份但备份方式要讲究加密后存放在离线介质或密码管理器里绝不能明文丢在网盘或聊天记录里。我个人的做法是把私钥用强密码加密打包放在一个只有自己知道的离线位置同时确保至少有一台服务器保留着可用的备用登录方式作为最后的保险。7. 我在实际配置中踩过的坑说几个真实踩过的坑都是文档里不会写、但实际会遇到的。有一次帮朋友配服务器密钥怎么都不生效-v看到Server accepts key都出来了最后还是失败查了半天发现是家目录权限被之前某次操作改成了 777SSH 直接拒绝。改回 755 立刻就好。还有一次是复制公钥时终端自动换行把一行公钥拆成了两行authorized_keys里就成了两条无效记录肉眼根本看不出来用ssh-keygen -l -f比对指纹才发现对不上。另一个高频坑是改完sshd_config直接restart结果配置里有个拼写错误服务起不来当前会话也断了只能去云控制台救援。从那以后我养成了两个习惯改配置前备份改完先sshd -t再reload并且永远保留一个活动会话。这些习惯看起来啰嗦但关键时刻能省下大量折腾时间。最后一个体会是关于密码短语的。早期我图省事全部留空后来意识到私钥文件一旦因为误操作泄露比如不小心同步到了公共位置留空的私钥等于把钥匙直接插在门上。现在我的做法是所有私钥都设密码短语配合 ssh-agent 使用安全性和便利性都不牺牲。这个转变花不了多少时间但安全等级完全不一样。