ARTICLE DETAIL

建站实战干货

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

SSH密钥登录实战:从原理到批量运维的完整配置指南

2026/9/7 18:37:29 拓冰建站 浏览量
SSH密钥登录实战:从原理到批量运维的完整配置指南 1. 从密码到密钥SSH免密登录究竟解决什么问题先说一个我自己的真实经历。早些年维护一批服务器每天要登录几十台机器巡检每台机器的密码还不一样有的复杂到根本记不住只能存在密码管理器里。那时候偷懒就想着能不能用一套办法让我从客户机登录服务器的过程完全不用敲密码。后来终于把 SSH 密钥登录彻底跑通了从那以后我再也没为登录服务器这件事烦过心。可能有人会说密码登录不是挺方便的吗敲一次密码也就几秒钟。这话在只管理三五台服务器的时候确实成立可一旦规模上来问题全暴露了密码复杂度要求高记忆力跟不上每台机器改密码要同步改好几处更危险的是服务器一旦暴露在公网密码爆破脚本全天二十四小时扫弱密码几分钟就被打穿。密钥登录恰好把这些问题一并解决。从字面上理解SSH 密钥登录就是用一对“钥匙文件”代替密码来完成客户机和服务器之间的身份认证。客户机持有私钥服务器端保存你的公钥。登录时客户机用自己的私钥和服务器端的公钥完成一系列数学运算校验校验通过就直接进入会话整个过程不需要输入任何密码。这套机制在 OpenSSH 里已经是非常成熟的方案Linux 服务器、macOS、Windows 的 OpenSSH for Windows 都原生支持。这篇内容我打算按照自己实际操作的顺序来写先讲清楚密钥认证到底是怎么完成的再把客户机端生成密钥、服务器端配置公钥的每一步细节过一遍包括那些文档里不会写清楚的权限坑和排查方法。最后会延伸几个高频场景比如 GitLab/GitHub 配置、群晖 NAS 免密登录、VS Code 远程开发以及如何限制只有指定用户或用户组能通过 SSH 登录。不管你是刚接触 Linux 的小白还是已经在服务器上摸爬滚打一阵子的运维这篇文章应该都能给你一些可用参考的思路。2. SSH密钥认证的工作原理一对文件如何完成身份校验很多教程上来就让你执行ssh-keygen然后复制id_rsa.pub到服务器就算配置完了。这样确实能用但一旦出问题就完全不知道从哪排查。我建议先花五分钟搞明白原理后面遇到问题你才有能力自己判断。2.1 非对称加密公钥私钥的天然分工SSH 密钥认证依赖的是非对称加密算法主流是 RSA 和 Ed25519。这类算法的特点是加密和解密使用的是两把不同的钥匙公钥和私钥。公钥可以公开分发谁拿到都无所谓私钥必须严密保管只能由持有者自己拥有。打个比方公钥就像一把挂锁任何人都能拿来把箱子锁上但锁上之后只有持有私钥的人才能打开箱子。服务器端保存你的公钥相当于发给你一个“身份凭证”它能验证你的身份但它自己无法冒充你。私钥放在客户机的本地磁盘里登录时由 SSH 客户端调用全程不出客户机。这里有个关键细节密钥认证过程中私钥不会通过网络传输。服务器用公钥加密一段随机数据发回给客户机客户机用私钥解密后再返回一段约定的校验信息服务器验证正确就允许登录。所以即使网络抓包也抓不到你的私钥。2.2 一次完整的免密登录流程拆解整个登录过程可以拆成四步理解了这个过程很多配置错误一眼就能看出来。第一步客户机发起连接向服务器发送支持的密钥算法列表和自己的密钥指纹信息。第二步服务器在自己的~/.ssh/authorized_keys文件里查找是否有匹配的公钥。如果没找到服务器会退回密码认证这也是为什么有时候配置了密钥却还是会弹出密码提示——问题基本都出在公钥根本没放对位置。第三步如果找到了公钥服务器生成一串随机数用这把公钥加密后发给客户机。第四步客户机用私钥解密计算出一个签名值返回给服务器服务器验签通过会话建立。整个过程中服务器始终只接触公钥客户机始终只接触私钥。只要私钥不泄露即使服务器被攻破或者 DNS 被劫持攻击者也拿不到你的私钥。2.3 RSA和Ed25519怎么选我早些年一直用 RSA 2048 位密钥后来换到 Ed25519 之后回不去了。Ed25519 的密钥长度更短生成和校验速度更快安全性在现代密码学标准下也更强。如果你的服务器系统版本不算太旧默认都支持 Ed25519。我在 Ubuntu 20.04 之后的系统上实测OpenSSH 7.0 以上的版本就可以直接用。RSA 的优势在于兼容性极广一些很老的嵌入式设备、网络设备只支持 RSA。所以我现在的习惯是常规服务器一律用 Ed25519遇到老设备再为它单独生成一把 RSA 密钥而不是全部退回到 RSA。下面是我常用的生成命令建议直接复用ssh-keygen -t ed25519 -C yournameclient-host -f ~/.ssh/id_ed25519-C参数是给你的密钥加一个备注通常写“用户名主机名”方便以后辨认。-f指定密钥文件的保存路径默认是~/.ssh/id_ed25519。执行完会在你的客户机~/.ssh目录下生成两个文件id_ed25519是私钥id_ed25519.pub是公钥。3. 客户机端准备三平台生成密钥对的完整操作密钥登录的起点是客户机。所谓客户机就是你发起 SSH 连接的那台设备可能是你自己的 Windows 笔记本也可能是一台 macOS或者是一台用来当跳板的 Linux 机器。我在三套环境里都操作过下面把差异和细节一并讲清楚。3.1 Windows客户机从OpenSSH到PowerShell早几年在 Windows 上做 SSH 还要装 PuTTY 或者 Bitvise SSH Client现在不需要了。Windows 10 1809 之后的版本自带 OpenSSH 客户端直接打开 PowerShell 或者 Windows Terminal 就能用。先检查系统是否自带Get-Command ssh如果输出里有路径说明可以直接用。如果没有可以在“设置 - 系统 - 可选功能”里添加 OpenSSH 客户端。很多人问 Bitvise 还好不好用我的看法是如果你只是简单地连服务器系统自带的 OpenSSH 已经完全够用Bitvise 的优势在于自带 SFTP 图形界面和会话管理适合重度使用 Windows 做运维的人但不是必需。在 PowerShell 里生成密钥的命令和 Linux 下基本一致ssh-keygen -t ed25519 -C my-win-laptop生成后密钥默认在C:\Users\你的用户名\.ssh\目录下。注意查看是否有隐藏文件PowerShell 的dir默认不显示隐藏项要用dir -Force。Windows 上有一个比较大的坑是换行符。如果你用记事本打开公钥文件、手动复制到服务器终端里粘贴很容易因为 Windows 的 CRLF 换行符导致公钥内容里混入一个^M字符服务器端校验时会直接失败。我建议在 PowerShell 里用type命令输出公钥内容再复制粘贴的时候不要做任何手工修改。3.2 Linux/macOS客户机终端里的标准流程Linux 和 macOS 的操作几乎一致macOS 自带的 OpenSSH 版本比较新直接用即可。生成命令和上面一样我习惯顺便把 SSH Agent 也启用这样私钥只需要解锁一次后续登录不用反复输入私钥口令。eval $(ssh-agent -s) ssh-add ~/.ssh/id_ed25519如果你生成密钥的时候设置了口令passphrase第一次ssh-add会要求输入一次之后本会话内就不再询问。这个设置值得推荐私钥在磁盘上是加密的即使电脑丢了别人拿到私钥文件也打不开。3.3 客户机端其他高频工具VS Code与终端模拟器VS Code 的 Remote-SSH 插件本质上是调用本机 OpenSSH 客户端所以只要你终端里能用密钥登录VS Code 里也一定能用。配置方法很简单CtrlShiftP输入Remote-SSH: Open SSH Configuration File编辑~/.ssh/config写类似下面的配置Host myserver HostName 192.168.1.100 User root Port 22 IdentityFile ~/.ssh/id_ed25519保存后重新打开连接VS Code 就会自动走密钥认证。我唯一要提醒的是IdentityFile路径要写绝对路径Windows 下写法是C:\Users\你的用户名\.ssh\id_ed25519注意反斜杠在配置文件里要写成双反斜杠或者直接改用正斜杠。终端模拟器方面Windows Terminal 和 macOS 自带终端都行没有特殊要求。4. 服务器端配置authorized_keys的放置与权限陷阱客户机端把公钥准备好之后真正容易出问题的地方是在服务器端。公钥放哪个文件、目录权限对不对、sshd_config里有没有允许密钥认证这三件事任何一件没做到位都会导致密钥登录失败。4.1 公钥上服务器的三种方法传统方法是把客户机的公钥内容追加到服务器上目标用户的~/.ssh/authorized_keys文件里。比如你要用root用户登录服务器端操作就是mkdir -p ~/.ssh chmod 700 ~/.ssh echo ssh-ed25519 AAAA... yournameclient ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keysmkdir -p确保目录存在chmod 700是设置目录权限为仅本人可读写执行chmod 600是设置文件权限为仅本人可读写。这两步权限设置极其重要OpenSSH 在验证密钥之前会检查这些权限如果发现authorized_keys文件或者.ssh目录权限过于松散为了安全它会直接忽略这个文件表现就是密钥认证失败并回退到密码输入。还有一种更方便的方式用ssh-copy-id一条命令搞定公钥分发ssh-copy-id -i ~/.ssh/id_ed25519.pub root服务器的IP执行后会提示你输入一次服务器密码然后自动完成创建目录、追加公钥、设置权限的全部工作。ssh-copy-id在 macOS 和 Linux 上默认自带Windows 不在自带命令范围内但可以用 PowerShell 的type配合管道手动实现type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh root服务器IP mkdir -p ~/.ssh cat ~/.ssh/authorized_keys这种方法本质上是把公钥文件内容通过管道发送到远程在远程执行追加写入。注意服务器端的引号内命令最好用连接避免目录不存在时直接写入失败。4.2 权限设置的硬性要求我在实际运维中见过太多因为权限导致密钥认证不生效的案例这里把硬性要求列成一张表建议收藏对照路径要求权限说明/home/用户名或/root755 或更严不能组可写家目录本身组可写会导致 OpenSSH 拒绝验证/home/用户名/.ssh700只有所有者能读写执行/home/用户名/.ssh/authorized_keys600只有所有者能读写/etc/ssh/sshd_config600全局配置一般不用动需要注意的是家目录的权限也是一个检查项。如果你的家目录是drwxrwxr-x也就是组用户可写OpenSSH 出于防篡改考虑也会拒绝使用其中的密钥文件。遇到这类问题先跑一遍ls -ld /root、ls -ld ~/.ssh、ls -l ~/.ssh/authorized_keys看权限是不是符合上表。4.3 sshd_config 关键参数与 root 登录限制服务器端还有一个经常被忽略的地方/etc/ssh/sshd_config配置文件。这个文件控制 SSH 服务的全局行为其中几个参数和密钥登录直接相关。PubkeyAuthentication yes # 允许密钥认证 PasswordAuthentication no # 关闭密码认证 PermitRootLogin prohibit-password # 禁止root使用密码登录但仍允许密钥登录 AuthorizedKeysFile .ssh/authorized_keys # 公钥存放文件路径修改完配置文件后要执行systemctl restart sshdUbuntu 系或者systemctl restart sshdCentOS 系使配置生效。注意有些系统服务名是ssh而不是sshd比如 Ubuntu 早期版本和 Debian可以用systemctl status ssh先确认。这里有我踩过的一个大坑PermitRootLogin prohibit-password表示 root 用户只能通过密钥登录不能通过密码登录。这个配置很推荐既保留 root 的密钥登录能力又封掉了密码暴力破解路径。但如果你恰好服务器上还没配好密钥就改了这一项那你很可能把自己锁在外面。所以我建议调整配置时先确保已经有一条终端会话保持着或者配好密钥后再修改密码认证选项。另外关机或者重启虚拟机前有些人会见到类似“客户机操作系统已禁用 CPU”的提示这其实和 SSH 配置没直接关系多半是虚拟机资源分配或 BIOS 设置的问题。但如果你同时改了系统安全策略建议先确认 SSH 服务状态正常再重启避免重启后连不上机器。4.4 排查链路从握手失败到回退密码的每一步密钥登录不生效时我推荐的排查顺序是固定的按这个顺序来基本都能定位问题。第一步先在客户机端用ssh -v输出调试信息ssh -v root服务器IP-v参数会打印连接过程的所有调试信息。关注关键输出Offering public key正常情况服务器会回复Authentication succeeded。如果输出里只有Next authentication method: password说明客户端提出密钥认证后服务器拒绝了。第二步检查服务器端的认证日志。Ubuntu 系的日志在/var/log/auth.logCentOS 系在/var/log/secure。搜索最近一次登录尝试的日志看到Failed publickey或者error: key_load_public: invalid format前者多半是公钥没匹配上后者是公钥内容格式坏了。第三步逐项检查权限。这一步最耗时但也最立竿见影。把所有涉及权限的目录文件列一遍按上面表格的硬性要求一一对照。按照这个链路排查绝大多数问题都能在几分钟内找到原因。我至今没遇到过超出一屏日志能解决的情况。5. 从单机到批量批量分发密钥与自动化运维当你手里的服务器数量超过五台手动一台台敲ssh-copy-id也开始痛苦了。这时候要把思路从“单机登录”切换到“批量分发”这也是密钥登录真正的价值所在。5.1 基于 Ansible 批量推送公钥Ansible 是最省事的方案。它基于 SSH 协议工作只要控制端能通过密码或密钥连接到目标机器就能批量做事。批量推送公钥的写法很简单- hosts: all tasks: - name: 确保 .ssh 目录存在 file: path: /root/.ssh state: directory mode: 0700 - name: 写入公钥 authorized_key: user: root state: present key: {{ lookup(file, /root/.ssh/id_ed25519.pub) }}第一次执行时需要提供服务器密码Ansible 会逐台写入公钥。执行成功后再次运行就会走密钥认证不再要求输入密码。我在五十多台机器的环境里用过这个方案整个过程大概几分钟比手动操作高效得多。唯一要注意的是如果目标机器上sshd_config已经关闭了密码认证这个首次连接还是需要密码的所以要么先保留密码认证跑一次要么批量分发之前确认网络环境安全可控。5.2 不借助 Ansible 的轻量脚本方案如果不想引入 Ansible写一个简单的 Shell 循环也能完成批量分发。我早期用过下面这个脚本模板#!/bin/bash SERVERS192.168.1.11 192.168.1.12 192.168.1.13 USERroot PUBKEY$(cat ~/.ssh/id_ed25519.pub) for HOST in $SERVERS; do ssh $USER$HOST mkdir -p ~/.ssh echo $PUBKEY ~/.ssh/authorized_keys if [ $? -eq 0 ]; then echo $HOST 完成 else echo $HOST 失败 fi done条件允许的话更推荐 Ansible因为脚本方式每次都会重复追加公钥执行两次后authorized_keys里会出现重复行虽然不影响登录但维护时看着很闹心。Ansible 的authorized_key模块天然是幂等的重复执行不会重复添加。5.3 批量环境中私钥的保管策略批量配置一旦规模化私钥的安全就直接决定所有服务器的安全。我的经验是给私钥设置强口令然后通过 SSH Agent 加载。有人图方便直接把私钥口令留空这样在批量自动化时确实省事但一旦客户端被入侵所有服务器就全裸奔了。在工作场景中更稳妥的做法是用ssh-agent托管私钥配合一个强登录口令。需要批量推送时先解锁一次之后在当前会话内可以自由连接所有配置过的机器。另外私钥文件建议只在客户机上保留一份不要随意拷贝到 U 盘或网盘。6. 密钥登录的延伸场景Git、群晖、VS Code与登录限制密钥登录的价值不会停留在“能免密登录 SSH”这一步。很多日常开发运维工具都基于同一套 SSH 密钥机制配好之后事半功倍。这里挑几个最常用的场景展开。6.1 GitLab/GitHub 配置 SSH 密钥Git 仓库的 SSH 协议推送和拉取用的就是这一套密钥体系。以 GitLab 为例生成密钥后把id_ed25519.pub的内容复制到 GitLab 的“SSH 密钥”设置页面保存后本地就能通过 SSH 协议访问仓库了。git clone gitgitlab.com:你的用户名/你的仓库.gitGerrit 也是一样在用户设置里添加 SSH 公钥后就可以用ssh -p 29418 用户名gerrit地址来操作评审任务。如果你用的是 GitLab配置完公钥后建议本地执行一次ssh -T gitgitlab.com能收到欢迎信息就说明连接正常。6.2 群晖 NAS 免密登录群晖 DSM 系统本身基于 Linux也支持 SSH 密钥登录。在群晖控制面板开启 SSH 功能后用我们前面讲的方法把客户机公钥追加到~/.ssh/authorized_keys就能免密登录。需要注意的坑是群晖的/root目录可能在某些版本里默认不可写你需要先切换到admin用户或者用自己的管理员账号操作权限不对的话会出现 “Permission denied” 的报错。群晖配置好密钥之后配合rsync可以做很多自动化的事情比如服务器定期备份到 NAS、远程同步指定目录。我在家里的一台 NAS 上配好密钥后写了个 cron 脚本每天自动把服务器上的日志归档拉回本地效果很稳定。6.3 限制只有指定用户或用户组可以 SSH 登录运维安全里有一条常见要求只允许特定用户或用户组远程登录。在sshd_config里可以这样配置AllowGroups wheel # 或者 AllowGroups ssh-users AllowUsers alice bob # 也可以指定具体用户对应到实操中先创建一个专门的 SSH 登录组groupadd ssh-users usermod -aG ssh-users alice然后在sshd_config里写AllowGroups ssh-users重启 SSH 服务这样只有组内的用户能连进来其他用户即使密码正确也会被拒绝。热搜词里有一条“设置只有 wheel 组的用户可以 ssh 远程登录如何取消使 root 用户也可以 ssh 登录”这里的做法是一样的要么把 root 加入允许组要么加上PermitRootLogin prohibit-password允许 root 用密钥登录。很多人踩坑的点在于修改AllowGroups时不小心把自己当前的用户移出了组导致连接直接被拒。改了这类配置后千万不要直接关掉当前的连接窗口应该新开一个窗口测试能连上之后再关旧的。6.4 Windows侧生态工具Bitvise、VS Code与系统服务如果你在 Windows 上工作ssh命令可以直连VS Code 的 Remote-SSH 也是同一套配置只要本地~/.ssh/config写好连接参数VS Code 会自动读取。Git 在 Windows 下使用 SSH 密钥时注意如果之前配置的是 PuTTY 风格的.ppk密钥需要先转换成 OpenSSH 格式或者直接用系统自带的 OpenSSH 客户端重新生成密钥对。Bitvise SSH Client 的优势是图形化的会话管理和内置 SFTP 面板适合不习惯命令行的用户。但如果你已经接受了ssh命令行和密钥登录的思路Bitvise 并不是必需的。反过来服务器端用 Bitvise SSH Server 的情况比较少见国内多数服务器还是 OpenSSH 的环境。6.5 本地端口转发与跳板机场景下的密钥复用密钥登录配置好后还可以配合 SSH 的跳板机参数。比如你有一台内网服务器只能通过跳板机访问客户机的~/.ssh/config可以这样写Host internal-server HostName 10.0.0.5 User root ProxyJump jump-server IdentityFile ~/.ssh/id_ed25519 Host jump-server HostName 跳板机公网IP User ubuntu IdentityFile ~/.ssh/id_ed25519这种场景下密钥登录的价值非常明显你只需要在跳板机和内网服务器上都放好公钥本地一次解锁私钥之后后续所有连接都不再输入密码。我自己的感受是一旦适应了这种配置再回到“每台机器都要输入密码”的模式会觉得非常痛苦。7. 常见问题实解从权限回退到批量失败的排错笔记这一部分是我打算留给自己的排错笔记也是在各种项目里遇到最多的几类问题。如果你配置过程中卡住了直接按这个列表对状态。7.1 明明配了密钥还是提示输密码按问题出现的频率排序最常见的原因是公钥文件权限不对。其次是公钥内容粘贴有误尤其是 Windows 上复制公钥时混入多余字符。第三是 SSH 服务端配置了AuthorizedKeysFile指向了非默认路径公钥虽然放好了但服务端根本不读那个路径。用ssh -v看一眼输出基本能判断是哪一种。7.2 多把密钥的管理问题如果你有多台服务器、多个 Git 平台需要多把密钥不要把所有私钥都命名为id_ed25519。SSH 默认只读取id_ed25519、id_rsa等固定文件名多把密钥的场景建议用~/.ssh/config做映射每种连接场景指定不同的IdentityFile。这种做法最清晰也不用频繁得改~/.ssh目录里的文件名。7.3 修改配置后忘记重启 SSH 服务这个坑特别常见。改完sshd_config后如果没重启或重载服务配置不会生效。我的习惯是改配置后立即执行sshd -t systemctl restart sshdsshd -t先检查配置语法避免语法错误导致服务起不来。一旦语法有问题直接重启可能把整个 SSH 服务搞挂到时候连不上机器就麻烦了。7.4 免密登录失效与时间服务器有关吗这个话题可能在热搜词里被联系到我要澄清一下SSH 密钥认证本身不依赖客户端和服务器的时间同步。但如果服务器用了 Kerberos 认证或者某些带票据的单点登录系统那时间同步确实会影响验证结果。普通 OpenSSH 密钥登录时间不同步不构成问题。如果你配置了密钥登录却失败优先查权限不要去折腾时间。7.5 批量分发后部分机器仍然要密码这种情况多数是部分机器的家目录权限不合规或者公钥没有正确追加。建议写一个快速检查脚本逐台机器检查权限和公钥是否在authorized_keys里for HOST in $(cat servers.txt); do echo $HOST ssh -o BatchModeyes -o ConnectTimeout5 $HOST ls -ld ~/.ssh ~/.ssh/authorized_keys; grep -c ssh-ed25519 ~/.ssh/authorized_keys doneBatchModeyes表示禁止交互式密码输入连不上的直接跳过特别适合批量检查。7.6 虚拟机环境里的特殊提示前面提到过热搜词里出现“客户机操作系统已禁用 cpu”这类相关内容。这种情况一般是 VMware 等虚拟机环境里的处理器设置和客户机操作系统不匹配或者 VMware Tools 相关组件出了问题。它不影响 SSH 密钥登录的配置但如果你是在虚拟机里练习配置遇到系统层面异常时先解决虚拟机本身的资源问题不要和 SSH 配置混在一起排查。判断标准很简单直接在客户机的虚拟控制台登录系统看能不能正常操作。如果能再回到 SSH 层面排查。8. 写在最后一套密钥走天下的配置习惯在我自己的环境中密钥登录不仅解决了“输入密码”这个表层痛点更重新定义了我管理服务器的方式。以前每次要记密码、改密码、担心密码泄露现在只需要管好客户机上的私钥文件服务器端全部交给公钥验证安全性和便利性同时得到提升。如果你准备开始配置我的建议是先在虚拟机里或一台不重要的机器上完整跑一遍流程客户机生成密钥、服务器端放公钥、关闭密码认证然后在配置了公钥的服务器上验证可以登录再回头把密码认证关闭。整个流程二十分钟就能走完之后你会发现自己再也回不到密码登录的老路上去了。