ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

SSH免密登录配置指南:从密钥原理到多服务器管理

2026/10/8 15:12:37 拓冰建站 浏览量
SSH免密登录配置指南:从密钥原理到多服务器管理 我记得刚入行那阵子每天要连好几台服务器做部署终端里反反复复敲 ssh rootip然后等系统跳出 password 提示再输一遍又长又难记的密码。服务器一多密码分了好几套记不住就成了日常输错两次还要担心被安全策略临时封掉。后来把登录方式改成 SSH 密钥免密把输密码这一步从流程里彻底拿掉才真正体会到什么叫省心。这篇内容就围绕 SSH 免密连接服务器 这件事把认证原理、配置步骤、常见报错排查以及多服务器场景下的管理技巧完整过一遍。不管你是刚接触云服务器的新手还是每天和生产环境打交道的开发、运维都能在这里找到可直接照做的操作也能理解每一步背后的设计逻辑。1. 为什么一定要做 SSH 免密从每次输密码的痛点说起先聊聊我自己的真实感受。不带免密的情况下每开一个新终端、每重启一次连接都要重新认证一次。听起来只是一次密码输入但累积起来非常消耗耐心。尤其是部署脚本、定时任务、CI/CD 流水线这类非交互场景根本没法弹个提示框让你输密码。1.1 密码登录的真正问题很多人觉得我用的是强密码不怕暴力破解这句话是对的但只答对了一半。服务器上的 SSH 端口一暴露出去每天都会有扫描器在尝试登录。密码再强只要你还在用密码认证就意味着密码会经过网络传输虽然 SSH 本身加密了传输通道但服务器端需要拿到密码去做比对一旦服务器上某个日志或审计组件被植入恶意代码密码就有泄露风险运维人员多、服务器多的时候密码的轮换和回收非常困难离职员工的密码权限经常变成历史遗留问题自动化场景完全被堵死脚本里总不能硬编码密码那样反而更不安全。所以我在项目初期就会把密钥认证 免密登录作为基础设施的一部分来搭而不是等出了问题再补。1.2 密钥登录和密码登录的核心差异用一张表格把两者区别列出来会更直观对比维度密码登录密钥登录免密认证材料一串可被记忆/猜测的字符私钥公钥组成的非对称密钥对材料是否上网络密码明文到达服务器做比较私钥只在本地网络传输的是签名结果自动化支持需要伪终端交互难自动化天然支持脚本、CI/CD暴力破解难度依赖密码强度与次数限制没有私钥爆破公钥不现实日常体验每次连接都要输入配置一次长期免密这里要澄清一个常见误解免密登录不是说这台服务器不要密码了恰恰相反你的私钥就是你最强的凭证。整个登录过程依然有身份验证只是把我知道什么换成了我拥有什么。1.3 什么场景最需要做免密以我接触过的使用场景下面这几类人一定跑不掉开发工程师本地 IDE 的 Remote-SSH、VS Code Remote 插件、服务器上调试代码免密能省掉大量重复认证运维人员批量管理几十台机器巡检、发布、改配置全靠脚本批量执行自动化流水线Jenkins、GitLab CI、GitHub Actions 要登录服务器执行部署个人学习环境的搭建频繁重启云主机、重建镜像一把密钥解决多台机器的访问。如果你发现自己每天要花几分钟在输密码和找密码上做一次免密配置一次性投入非常划算。2. 免密登录的底层机制公钥、私钥和 authorized_keys 的三角关系很多教程只教命令不解释原理。结果就是一旦命令执行不顺利完全不知道问题出在哪一环。所以我先把机制讲明白后面排查方向的思路也就清晰了。2.1 免密不是什么后门首先要确信SSH 密钥登录是一种比密码更可靠的身份认证方式。它依赖一对密钥私钥id_ed25519 或 id_rsa留在你本机相当于你的身份证原件绝不能外传公钥id_ed25519.pub 或 id_rsa.pub可以公开相当于身份证复印件部署到服务器上。所谓免密就是你在本机持有私钥服务器的 ~/.ssh/authorized_keys 文件里存了你的公钥。登录时服务器会验证持有对应私钥的人验证通过就放行。2.2 一次完整的密钥认证握手实际握手过程可以简化成四步客户端发起 SSH 连接并告知服务器自己希望用公钥认证服务器从 authorized_keys 里找到候选公钥向客户端发一个随机挑战客户端用私钥对这个挑战签名把签名结果返回服务器用公钥验证签名如果匹配认证通过。这里的关键点是私钥自始至终没有离开你的本地机器网络上只传输签名结果。这比密码登录少了服务器必须接收并比对密码这个环节安全性高很多。打个比方密码登录像你对暗号对方知道暗号就能进门密钥登录像把印章留在自己手里每次给别人看盖出来的章是否和备案一致印章本体永远不交给对方。2.3 authorized_keys 文件和它的一行行公钥服务器上每个用户的家目录下都可能有一个 .ssh/authorized_keys 文件。里面的每一行对应一个允许登录该用户的公钥。创建服务器配置时我强烈建议用下面的命令生成密钥对ssh-keygen -t ed25519 -C thinkpad-x1-2024-C 参数是给这把密钥加注释方便以后在 authorized_keys 里分辨哪一行是哪台机器、哪个人的。生成的公钥打开后通常长这样ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN5nYb1... thinkpad-x1-20242.4 为什么推荐 Ed25519 而不是 RSA很多老教程还在教你 ssh-keygen -t rsa -b 4096。实际项目中除非要连接的服务器 SSH 版本太老我基本都用 Ed25519。原因有三密钥长度更短生成的公钥、私钥文件很精简部署和备份都方便签名和验证速度更快尤其在批量连接时体感明显安全性足够强现代 OpenSSH 都原生支持。如果你确实需要兼容十年前的老系统那就退而求其次用 RSA 4096。这里顺带提一下服务器端版本可以通过命令查看一般 ssh -V 就能看到。新装系统的服务器都不存在兼容问题。3. 手把手配置流程从生成密钥到第一次免密登录原理清楚了配置其实就三大步生成密钥、部署公钥到服务器、验证登录。下面每一步我都给出命令和背后的理由。3.1 第一步生成本机密钥对先查看本机是否已经有密钥避免重复生成覆盖掉旧密钥ls -la ~/.ssh/如果没有 id_ed25519 和 id_ed25519.pub继续生成ssh-keygen -t ed25519 -C my-laptop执行后会问两件事保存路径直接回车用默认路径 ~/.ssh/id_ed25519 即可passphrase是否给私钥加口令。这里要重点解释一下 passphrase。如果你设置了 passphrase那登录时会要求输入它表面上看不是免密。但这是一个重要的安全选择。实际操作中我会设置 passphrase然后用后面讲的 ssh-agent 把它缓存起来。这样既享受免密体验又避免私钥丢失后直接被人冒用。3.2 第二步把公钥部署到服务器部署公钥最顺手的命令是 ssh-copy-idssh-copy-id -i ~/.ssh/id_ed25519.pub ubuntu你的服务器IP这个命令会远程连接一次输入一次当前密码然后自动把你的公钥追加到服务器的 authorized_keys 文件里。为什么这里还要输密码因为这时服务器还没有你的公钥只能先用密码完成第一次认证。如果你的本机没有 ssh-copy-id比如部分 Windows PowerShell 环境手动部署也很简单一条命令完成cat ~/.ssh/id_ed25519.pub | ssh ubuntu你的服务器IP mkdir -p ~/.ssh chmod 700 ~/.ssh cat ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys这条命令同时完成了三件重要的事建目录、追加公钥、设置权限。权限这一环很重要下一章详细讲。提示部署时建议先以普通用户登录不要直接用 root 做日常操作。很多服务初始化时用 ubuntu、admin 这类默认账号把密钥加到该用户下即可。3.3 第三步验证免密登录部署完成后直接测试ssh ubuntu你的服务器IP如果不再提示输入密码说明免密配置成功。如果还提示密码先不用急着怀疑服务器按第 4 章的排查链路走一遍。3.4 不同客户端下的配置差异考虑到很多读者不一定都在 macOS/Linux 终端下操作我补充几个高频客户端的差异Windows 10/11系统自带 OpenSSHPowerShell 里同样能执行 ssh-keygen 和 ssh。微软商店安装的 Windows Terminal 搭配起来体验和 Mac 差不多MobaXterm流行的图形化 SSH 工具。连接 Session 时在 Advanced SSH settings 里勾选 Use private key选择你的私钥文件即可VS Code Remote-SSH在 .ssh/config 里写清楚 Host、HostName、User、IdentityFile 后点连接就直接用密钥认证手机 Termux同样支持 ssh-keygen在包管理器里安装 openssh 后命令行操作和 Linux 一致。很多人只在 MobaXterm 里配好了密钥结果换 VS Code 又需要重新配置就是不清楚这些工具本质上读的都是同一套 SSH 认证机制只要落在 .ssh/config 里所有客户端都会自动读取。4. 最容易翻车的权限问题与典型报错排查免密配置本身不难真正让人头疼的是权限和报错。我把高频问题整理出来结合排查链路讲。4.1 sshd 为什么对权限这么敏感首次配置免密时最常遇到的报错是 Permission denied (publickey)。我排查过的案例里一大半源于服务器上 .ssh 或 authorized_keys 的权限过宽。SSH 守护进程有一个安全准则如果认证相关文件可以被其他用户写入它会直接不给面子地忽略掉。道理很简单如果 ~/.ssh 目录任何人可写攻击者就可以往你的 authorized_keys 里追加自己的公钥那样免密认证就成了摆设。权限标准如下用户主目录 ~ 本身不能让 group 或 other 有写权限通常保持 755 或 700~/.ssh 目录应该为 700只有自己可读写执行authorized_keys 文件应该为 600只有自己可读写。数字权限的含义是7 代表读写执行6 代表读写。chmod 700 就是把目录设置为仅属主可访问。修复命令chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys4.2 Permission denied (publickey) 的完整排查链路如果你遇到的是这个报错我建议按下面的顺序排查而不是乱改文件第一步确认客户端用的私钥路径正确。在命令里加 -v 参数看详细输出ssh -v ubuntu服务器IP看 debug1 输出里的 identity file 是否指向你期望的私钥。第二步直接到服务器上看日志。Debian/Ubuntu 日志在 /var/log/auth.logCentOS/RHEL 在 /var/log/secure新版系统大多可以用sudo journalctl -u ssh -f日志会明确写到Authentication refused: bad ownership or modes之类的原因权限问题一眼可见。第三步修正权限按上面说的 chmod。第四步检查 SELinux。在部分 CentOS 环境下即便权限对了SELinux 标签异常也会拒绝执行restorecon -Rv ~/.ssh第五步检查服务端 sshd_config。确认 PubkeyAuthentication 没有设为 noAuthorizedKeysFile 指向默认的 .ssh/authorized_keys 或你自定义的路径。修改完 sshd 配置后需要重启服务两个系统命令有些差异sudo systemctl restart ssh # Debian/Ubuntu sudo systemctl restart sshd # CentOS/RHEL这也是很多刚配完服务端策略的读者搜sudo systemctl restart ssh的原因。注意修改配置前最好保留当前连接这能避免你把自己锁在门外。4.3 passphrase 和 ssh-agent免密并不等于裸奔如果你按 3.1 设置了 passphrase会发现第一次连接时依然要输入私钥口令此时侧面看并没有做到完全的免密。解决方式是使用 ssh-agent把私钥暂时缓存在内存里。启动并添加私钥eval $(ssh-agent -s) ssh-add ~/.ssh/id_ed25519执行后后续在本次会话里的 SSH 连接都不再询问 passphrase。还可以指定缓存时长ssh-add -t 3600 ~/.ssh/id_ed25519这样 3600 秒后私钥自动从 agent 中移除。我在公司电脑上就这么做既不用反复输口令私钥也不会长期留在内存里。顺便提一句macOS 会把 passphrase 存在钥匙串里Windows 的 OpenSSH 也有 agent 服务可以根据系统习惯启用对应的自动缓存机制。4.4 被拒绝和连不上服务端配置与网络问题除了权限还有几个热搜里高频出现的情况我合并说明ssh服务器拒绝了密码这类消息通常出现在使用密码登录的会话中。如果你刚在服务端把 PasswordAuthentication 改成 no就已经完全关闭了密码通道反过来如果还想保留密码登录备用可以维持 yesUbuntu ssh 无法连接 或 连接超时优先检查服务是否启动、防火墙、云厂商安全组端口是否放行。Ubuntu 下可以先运行 systemctl status ssh 确认服务状态connection closed by 127.0.0.1常在端口转发或代理类场景下出现需要检查服务端监听地址和客户端配置的转发端口是否冲突。注意排查顺序永远是从客户端到网络再到服务端。先看私钥文件是否存在、路径是否正确再看端口通不通最后看服务端日志。这样能少走很多弯路。5. 多服务器场景下的批量配置config 文件与自动化免密只解决了一次认证的问题当你管理的主机多起来新的痛点变成记不住 IP、记不住用户名、每次都要指定私钥。5.1 用 config 文件给服务器起别名~/.ssh/config 是我最推荐优先配置的文件。没有它你连一台机器要写全ssh -i ~/.ssh/awesome_key ubuntu203.0.113.10 -p 2222有了 config可以写成Host web1 HostName 203.0.113.10 User ubuntu Port 2222 IdentityFile ~/.ssh/awesome_key Host web2 HostName example.com User admin IdentityFile ~/.ssh/other_key之后连接只要ssh web1这个配置不仅对 ssh 生效scp、rsync、sftp 这些工具同样识别命令立刻变得清爽scp ./index.html web1:/var/www/如果你经常通过跳板机访问内网机器config 里还可以配 ProxyJump例如Host internal-server HostName 10.10.0.10 User root ProxyJump web1这样 ssh internal-server 时会自动借道 web1跳板过程完全不感知。5.2 批量分发公钥到多台机器几十台机器一台台执行 ssh-copy-id 同样低效。一个最轻量的思路是写循环for host in 10.0.0.1 10.0.0.2 10.0.0.3; do ssh-copy-id -i ~/.ssh/id_ed25519.pub root$host done前提是这些机器有统一的初始密码循环执行时会依次要求输密码。如果你希望彻底自动化可以考虑用 expect 或 Ansible。我的建议是生产环境直接上 Ansible 的 authorized_key 模块既不需要预置密码又能统一管理所有机器的 authorized_keys 内容。临时环境用循环脚本即可不要为了图省事把密码硬编码进脚本sshpass 这类工具用起来一时爽密码很容易埋在 shell 历史或进程参数里。5.3 从 SSH 免密到 Git 免密很多人配置完服务器又在 GitHub/GitLab/Gitee 上遇到ssh认证失败 git的报错。这里要提醒一下Git 平台的密钥免密和服务器免密逻辑一样但你上传的应该是公钥不是私钥并且和服务器登录一样公钥需要明确添加到账号的 SSH Keys 列表中。测试 Git 平台连接用ssh -T gitgithub.com输出里会显示用户名说明认证成功。如果提示 Permission denied优先检查你 clone 远程仓库时用的地址是不是 SSH 格式而不是 HTTPS 格式。对于服务器上要拉取私有仓库的场景做法是把服务器的公钥加入到 Git 平台账号或 Deploy Keys 里。这样服务器执行 git pull 时不弹密码自动化部署链路就通了。这块踩过坑的朋友应该都明白报错里最容易被忽视的就是add the host key to the known_hosts file这句话第一次连接陌生主机时的指纹确认环节千万别直接忽略。6. 密钥登录的安全红线加固的正确姿势做免密不等于可以放松安全。我把自己的加固习惯和踩过的教训放在这一章。6.1 私钥文件的本机权限公钥随便发私钥必须锁好。Linux/macOS 下私钥文件权限应为 600可以检查ls -l ~/.ssh/id_ed25519如果权限为 644 甚至 777SSH 客户端会直接拒绝使用这把私钥。这也是另一种明明配好了却连不上的原因。Windows 下私钥存放在用户目录时要注意不要把私钥同步进网盘、云盘同步等于把家门钥匙复制出去。6.2 authorized_keys 的生命周期管理服务器上的 authorized_keys 需要定期清理。数据到期、同事离职、测试机下线都可能导致一行公钥变成遗留项。我建议每次扩容或人员变动时都要执行cat ~/.ssh/authorized_keys逐行确认公钥后面的注释是否还能对上当事人和机器。这也是我为什么强调生成密钥时用 -C 加注释没有注释的公钥就像没有标签的钥匙几年后想清理都无从查起。生产环境可以设置告警把 authorized_keys 的文件内容纳入配置管理任何变更通过部署流程统一发放和回收避免有人在服务器上手动追加。6.3 关闭密码登录前先确保密钥真的能用很多安全加固文章会建议把 PasswordAuthentication 设为 no把密码通道彻底关掉。这个方向没问题但操作顺序上我必须提醒几点确认服务器上至少有一把可用密钥确认你本机能通过这把密钥正常登录再修改 sshd_config 并重启服务。哪怕中间一步出错你都会发现自己已经被锁在门外。我在测试环境就干过这种事改了 no 后重启结果本机私钥路径写错最后只能通过云厂商的 VNC 控制台登录修复。不要重蹈这个覆辙。如果还想进一步防暴力破解可以引入 Fail2ban对多次认证失败的 IP 做临时封禁。对于公网开放的服务这是性价比相当高的手段。6.4 密钥加口令还是不带口令的私钥回到生成密钥时的问题私钥到底要不要加 passphrase我个人的实践是加。日常使用通过 ssh-agent 缓存重启电脑后重新添加一次。这样私钥即使被人拷贝走没有口令依旧无法使用。对安全性要求更高的场景可以再加 TOTP 二次验证把 SSH 免密升级成密钥动态码的双因子体系。提示免密登录和安全加固不是对立关系。正确的组合是密钥认证 私钥口令 agent 会话管理 服务端关闭密码登录/限制来源 IP。少敲一次密码多留一分安全。最后分享一个我在多机场景下的习惯每台电脑生成独立的密钥而不是把同一把私钥复制到所有设备。同时定期轮换密钥重新生成密钥对后从服务器的 authorized_keys 里移除旧公钥。这个过程看似繁琐实际上因为流程已经脚本化十分钟就能完成。如果你也正在被 SSH 连接问题折磨先把密钥生成、部署、权限这三件事理顺后面的自动化工作才能真正跑起来。