
1. 为什么我抛弃密码登录免密访问的真实价值先讲个实际情况。我手里常年管着七八台Linux服务器有公司的生产环境也有自己折腾的测试机系统密码各不相同长度还都不短每次登录都得从密码管理器里翻出来复制麻烦不说SCP传文件更是灾难——每传一趟就要输入一次密码传两个目录下来手指头都抽筋。后来我下定决心把所有机器全部改成SSH密钥登录过程并不复杂但用完之后彻底回不去了。SSH免密登录的原理说白了就是“钥匙和锁”的关系。你在自己的Windows电脑上生成一对密钥一把私钥留在本机绝对不能给别人一把公钥放到服务器上。连接服务器的时候对方会验证你是否持有匹配的私钥验证通过就放行完全不需要输入密码。整个过程是加密的比密码登录更安全也比密码登录更省事。这个需求覆盖的人群很广初次接触Linux的Windows用户、天天要连跳板机的运维、需要写脚本批量同步文件的开发甚至只是偶尔连一下云服务器的小白都值得花十分钟把这一套配好。配完之后你再也不用担心服务器密码复杂度不够被安全部门点名也不用在终端里一遍遍敲密码了。本文会从Windows环境准备开始完整走一遍密钥生成、公钥部署、免密验证、报错排查的流程最后聊聊安全上我觉得每个人都应该注意的点。2. 环境准备先确认Windows侧具备的条件2.1 检查自带的OpenSSH客户端多数人不用装任何软件很多人以为在Windows上搞SSH得先装个PuTTY或者Xshell其实从Windows 10 1809版本开始系统就原生内置了OpenSSH客户端直接就能用。第一步是确认你的电脑上有这个命令。操作方式按下Win X选“终端”或“Windows PowerShell”在窗口里运行ssh -V如果输出类似OpenSSH_for_Windows_8.1p1, LibreSSL 3.0.2这样的版本信息说明已经自带客户端了后面所有操作都能直接做不用额外安装任何第三方软件。如果你的系统比较老没有这个命令可以去“设置 - 应用 - 可选功能 - 添加可选功能”找到“OpenSSH客户端”安装。整个过程大概一分钟比网上那些建议装Git又装Putty的教程清爽得多。2.2 建议装Windows Terminal但非必需自带的PowerShell窗口其实也能跑完所有命令但我想说如果你打算长期跟服务器打交道Windows Terminal值得安装。微软商店里直接搜就能装免费支持多标签页、自定义字体、复制粘贴快捷键也更顺手。平时我习惯开两三个标签页一个连着测试机一个写配置文件另一个查资料。如果你更习惯类Unix的操作感也可以装Git Bash。这个工具会额外提供很多Unix小工具比如cat、grep、ssh-copy-id但注意Git Bash自带的ssh-copy-id在Windows上不一定能用后面我会讲替代方案。核心命令用PowerShell完全够。2.3 把服务器信息提前列好开始之前先把下面这些信息准备好省得到时候手忙脚乱信息项示例说明服务器IP192.168.1.100云服务器填公网IP内网机填内网IP用户名root也可能是 ubuntu、centos 等SSH端口22如果改过端口后面命令要带上-p是否支持密码登录支持第一次部署公钥需要密码或者用其他方式把公钥放上去这里有个容易忽略的点云服务商比如阿里云、腾讯云通常默认只允许密钥登录你买完服务器后会让你下载一个.pem私钥文件这种场景同样适用本文方法区别只在于第一次部署公钥时你可能需要在控制台网页上操作而不是在命令行里输密码。如果是这种情况直接跳到第4节手动部署部分的思路。3. 生成密钥对ssh-keygen的命令细节与建议3.1 加密算法怎么选Ed25519还是RSA现在生成密钥你其实是在选加密算法。目前最常见的有两种Ed25519这是现代首选密钥长度短安全强度高生成快对性能影响小。OpenSSH 6.5以后的版本都支持。RSA经典老牌兼容性最好很多老旧Linux发行版和网络设备只认RSA。建议用4096位。我的倾向是除非你的服务器是CentOS 6、Ubuntu 14.04这种上古版本否则一律选Ed25519。原因很简单同样的安全性它的密钥更短使用更流畅配合现代系统完全没有兼容性问题。老系统怎么判断拿不准就选RSA 4096兼容性一定是最大的。下面两张图感受一下区别特性Ed25519RSA 4096密钥长度固定极短4096位性能快较慢安全强度高高兼容性OpenSSH 6.5所有平台推荐场景现代Linux、主流云服务器老旧系统、网络设备3.2 执行生成命令并理解每个参数确认终端没问题之后在PowerShell里执行ssh-keygen -t ed25519 -C windows-acer -f $env:USERPROFILE\.ssh\id_ed25519逐个参数解释一下-t ed25519指定使用Ed25519算法。如果要用RSA就写-t rsa -b 4096。-C windows-acer这是注释信息作用是让你以后看到公钥就能认出这是哪台电脑生成的密钥。不填的话默认是“用户名主机名”也够用但我习惯写个这台机器的主人或者机器名多台设备管理起来方便。-f指定密钥保存位置和文件名。这里我指定到了当前用户的.ssh目录下文件名是id_ed25519。如果你在Windows上直接用默认路径一般就是C:\Users\你的用户名\.ssh\id_ed25519。执行完终端会提示你设置passphrase。这是给私钥加的一道口令密码不是服务器的登录密码而是你使用私钥时额外要输入的短语。它跟密码的区别是你每连一次服务器可能都要输一遍这个口令所以很多人干脆留空。我不建议留空。私钥文件在你硬盘上就是一串文本如果电脑被偷、被植入木马私钥被拷走对方就能拿它直接登录你所有配置了对应公钥的服务器没有任何防线。设一个passphrase等于给私钥再加一层锁泄露了也还能抢救。后面我会讲用ssh-agent缓存来减少反复输入的麻烦这个口令不算白设。生成完成之后在.ssh目录下会看到两个文件id_ed25519私钥绝对不要发给任何人。文件权限也尽量收紧。id_ed25519.pub公钥这个可以随便分发放到服务器上就行。3.3 查看公钥内容确认它长什么样在同一个终端里运行type $env:USERPROFILE\.ssh\id_ed25519.pub输出大致是ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPxg9xWCT3GsRqFZ4x0vjWewBghmncn3wZbRzu4q2KOt windows-acer注意整个内容是一行开头是算法名中间是一长串base64编码的密钥数据最后是我的-C注释。复制的时候记得完整复制整行不要手动换行也不要带多余空格否则服务器端可能识别失败。提示Windows上type命令在CMD和PowerShell里都能用cat命令在PowerShell 7和Git Bash里也能用。习惯哪个用哪个。4. 把公钥部署到Linux服务器上4.1 最省事的部署方式PowerShell一行命令搞定如果你第一次还能用密码登录服务器那部署公钥最简单的方式就是把本地公钥内容追加到服务器上~/.ssh/authorized_keys文件里。在PowerShell里执行type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh 用户名服务器IP mkdir -p ~/.ssh chmod 700 ~/.ssh cat ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys拆开来看这条命令由三部分组成type ... .pub—— 读取本地公钥文件内容。|—— 管道符号把公钥内容作为输入传给SSH命令。ssh 用户名服务器IP ...—— 先登录到服务器然后在服务器上依次执行引号内的命令创建.ssh目录如果不存在的话、设置目录权限700、把接收到的公钥追加写入authorized_keys、再把文件权限设为600。这里我特意把权限设置写在一条命令里了。这一步很重要很多新手就栽在这里——公钥写进去了但authorized_keys文件权限太宽松比如644SSH服务会直接拒绝使用这个密钥登录认为不安全。执行过程中会要求你输入服务器密码密码正确后就部署成功了。4.2 没有密码或密码不可用怎么办有些场景你压根没法用密码登录。比如云服务器创建时只下载过.pem私钥文件或者你压根还没找管理员要密码。这时候可以分两种情况处理。如果手里有.pem私钥文件用它先登录一次服务器再手动操作ssh -i C:\Users\你的用户名\Downloads\mykey.pem 用户名服务器IP登录进去之后手动完成上面那条管道命令的后半部分创建目录、粘贴公钥、改权限。如果连私钥都没有只能去云厂商控制台的网页终端登录那就在网页终端的shell里执行mkdir -p ~/.ssh chmod 700 ~/.ssh echo ssh-ed25519 AAAA...你的公钥内容... ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys这种情况下的公钥内容就需要你先把Windows上的id_ed25519.pub内容复制出来再手动粘贴到服务器。粘贴的时候留意一下很多网页终端默认开启了自动换行可能导致公钥被截断成多行这会让密钥失效。看到粘贴结果有换行就重新粘一次确保它是一行完整的内容。4.3 服务器端配置项检查公钥已经放进authorized_keys了但免密登录还不一定马上能用。服务器端的SSH配置也需要确认两个核心选项。用root或sudo权限打开SSH配置文件sudo vim /etc/ssh/sshd_config重点看这两行PubkeyAuthentication yes AuthorizedKeysFile .ssh/authorized_keysPubkeyAuthentication必须为yes表示允许公钥认证方式。AuthorizedKeysFile默认就是.ssh/authorized_keys如果被改过说明服务器可能从别的路径读取公钥那你就得把公钥放到对应文件里。改完配置记得重启服务让它生效sudo systemctl restart sshd不同发行版的服务名可能有区别CentOS/RHEL旧系统是service sshd restartUbuntu/Debian上可能是systemctl restart ssh。拿不准就两个都试或者用systemctl status sshd看一下服务名。还有一个容易忽略的如果服务器开启了SELinux强制模式有时候权限对了但SELinux上下文不对照样登录不了。云服务器和桌面版Linux一般遇不到但如果你在公司内网的机器上折腾遇到密钥放进去仍无法登录的情况可以考虑sudo restorecon -Rv ~/.ssh恢复一下上下文。5. 免密登录验证与日常使用优化5.1 第一次连接接受指纹并确认免密成功公钥部署完成后在Windows上直接执行ssh 用户名服务器IP如果一切正常不会再问密码而是会提示你确认服务器的指纹信息The authenticity of host 192.168.1.100 (192.168.1.100) cant be established. ED25519 key fingerprint is SHA256:xxxxxxxxxxxxxxxxxxxxx. Are you sure you want to continue connecting (yes/no/[fingerprint])?输入yes回车即可。这个提示是SSH在帮你登记这台服务器在known_hosts中的指纹防止以后有假冒服务器来骗取登录信息。第一次遇到正常确认就行。确认完之后你会直接进入服务器的shell免密登录成功。如果你在前面设置了passphrase这里会先要求你输入私钥的口令输完后收尾之后连接还可能再问。如果觉得麻烦往下看ssh-agent的部分。5.2 用config配置文件管理多台服务器服务器多了之后每次都要敲ssh root192.168.x.x -p 2222这类长命令很痛苦。Windows的OpenSSH同样支持~/.ssh/config配置文件可以给每台服务器起个简短别名。在C:\Users\你的用户名\.ssh\目录下新建一个文件命名为config没有扩展名内容示例Host prod HostName 10.0.0.5 User root Port 22 IdentityFile ~/.ssh/id_ed25519 Host test HostName 192.168.1.50 User testuser Port 2222 IdentityFile ~/.ssh/id_ed25519_other配置完之后连接服务器只需要输入ssh prodssh会根据别名自动读取HostName、User、Port和私钥文件路径。这个文件里可以放任意多台机器的配置运维效率提升非常明显。想查配置是否生效可以执行ssh -G prod看解析结果比一个个敲命令舒服得多。5.3 用ssh-agent缓存passphrase告别每连必输很多人在passphrase这里妥协设了嫌麻烦不设心里又不踏实。其实有个两全其美的办法——ssh-agent。ssh-agent是OpenSSH自带的一个后台服务作用是把私钥加载到内存里之后一定时间内连接服务器都不需要再输入passphrase。在Windows上首先要确保ssh-agent服务处于运行状态。在PowerShell管理员模式里执行Get-Service ssh-agent如果状态不是Running就启用并启动Set-Service -Name ssh-agent -StartupType Automatic Start-Service ssh-agent然后加载你的私钥ssh-add $env:USERPROFILE\.ssh\id_ed25519这条命令会要求你输入一次passphrase之后只要agent服务在运行免密登录不再询问口令。每次重启电脑后需要重新执行一次ssh-add或者你可以在$PROFILEPowerShell配置文件里加入这行命令省去手动操作。5.4 多台Windows设备之间同步公钥如果你家里一台台式机、一台笔记本都要连同一批服务器不需要每台机器重新生成公钥部署一遍。方法是把A电脑生成的id_ed25519.pub内容复制到B电脑的~/.ssh/authorized_keys里或者干脆把A电脑的整个.ssh/id_ed25519和.pub文件拷贝到B电脑的.ssh目录下。注意私钥被拷贝到另一台机器等于一次性把访问权限给了那台机器。如果复制的是私钥文件一定确保两台都是你自己的可信设备并且文件不要经过网盘等中间环节裸奔传输。更稳妥的做法是每台设备生成独立的密钥对服务器上同时追加多个公钥这样某台设备丢了单独删掉对应公钥就行不需要全盘重来。6. 免密登录失败的完整排查链路这部分我特意单独开一节因为免密登录失败是大部分人第一次配置时最糟心的环节。我会按照实际操作中最常见的出错顺序带你把问题逐个排掉。6.1 排查第一站客户端连着是不是同一个用户一个特别低级的坑在Windows上生成密钥、部署公钥的时候用的是root结果登录时写的是ubuntu或centos系统去找这个用户的authorized_keys当然找不到你的公钥直接报Permission denied (publickey)。所以排查第一件事确认ssh 用户名IP里的用户名跟部署公钥时用的用户一致。公钥部署在谁的~/.ssh/authorized_keys里你就得用谁的身份登录这不是Windows能替你决定的。6.2 排查第二站服务器上authorized_keys文件内容对不对在服务器上执行cat ~/.ssh/authorized_keys看看输出是否只有一行开头是否为ssh-ed25519或ssh-rsa内容是否和Windows上id_ed25519.pub完全一致。注意Windows上复制到Linux后行尾可能残留\r回车符这在某些情况下会干扰密钥解析。如果发现尾部多了一个字符可以用sed -i s/\r$// ~/.ssh/authorized_keys清理掉。再检查权限ls -l ~/.ssh/authorized_keys文件权限必须是600或者更严格目录权限是700。如果输出是-rw-r--r--这种644权限SSH会认为文件不够安全直接忽略里面的公钥。修复命令chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys6.3 排查第三站用ssh -v看详细日志Windows命令行怎么都连不进时最好用的工具就是verbose模式ssh -v 用户名服务器IP或者更详细一点ssh -vvv 用户名服务器IP输出结果里重点看下面几行debug1: Authentications that can continue: publickey,password debug1: Next authentication method: publickey debug1: Offering public key: C:\\Users\\.../.ssh/id_ed25519 debug1: Authentications that can continue: publickey,password看到Offering public key正常但后面还是Authentications that can continue说明公钥被服务器拒绝。这个时候就要回服务器看SSH日志sudo journalctl -u sshd -f或者老系统sudo tail -f /var/log/secure日志里会明确告诉你认证为什么失败比如Authentication refused: bad ownership or modes就是权限问题No such file or directory就可能是路径不对。看日志定位问题比瞎猜高效得多。6.4 排查第四站服务器sshd服务是否正常有时候公钥和权限都对但就是连不上报错不是认证失败而是Connection timed out或者Connection refused这种情况八成是网络层面的问题跟密钥本身无关。从Windows先ping一下服务器ping 服务器IP能通的话继续在Windows上检查服务器22端口是否可达Test-NetConnection 服务器IP -Port 22如果TcpTestSucceeded为False那就是防火墙或安全组挡了。云服务器请在控制台安全组规则里放通22端口或你的自定义SSH端口自建服务器检查firewall-cmd --list-all或ufw status确认SSH端口是否放行。如果端口通了但还是拒绝再检查服务器上sshd是否在运行systemctl status sshd没运行就启动它并设为开机自启systemctl enable --now sshd6.5 最隐蔽的坑修改过端口但命令没带端口号很多生产服务器为了防扫描会把SSH端口从默认的22改成别的比如58422。这种情况下直接ssh 用户名IP是不会成功的连密码都不会让你输。解决方式很简单在ssh命令里加-p 端口号ssh -p 58422 用户名服务器IP如果你用了config文件在对应Host段落里写Port 58422即可日常连接则直接享受别名带来的便利。7. 安全底线与我的个人建议免密登录配置完成但并不等于结束安全上的几个原则我在多次踩坑之后现在每次都严格遵守。7.1 私钥必须贴身保管不要裸奔分发私钥文件就是你全部服务器的合钥匙。不要把它通过微信、邮件、云盘明文传递不要把整个.ssh目录打包丢到一个共享U盘里更不要把私钥贴到聊天工具或者代码仓库里。我见过有人为了图省事把私钥内容直接写进文档发到群里等于把所有服务器大门敞开。如果非要在多台设备之间复制私钥请用加密压缩工具打包后传递或者直接用U盘物理拷贝用完及时删除中间痕迹。7.2 passphrase一定要设置但记得配合ssh-agent很多人设了passphrase之后觉得烦干脆取消。而我的做法是所有私钥一律设置passphrase然后用ssh-add加载到系统ssh-agent中这样平时使用完全感觉不到口令存在但私钥文件泄露时还有一层保护。这是一对很好的组合——安全性和易用性都兼顾。Windows下设置passphrase之后如果你发现每次打开新终端都要重新ssh-add可以在PowerShell配置文件中预置加载逻辑或者手动把ssh-agent服务设置为自动启动再配合配置文件里的AddKeysToAgent yes选项写入~/.ssh/config顶行让OpenSSH在首次使用私钥时自动加入agent缓存。7.3 确认免密成功后再考虑关闭密码登录有些新手配置完密钥后会寻求把密码登录彻底关闭来杜绝密码爆破。这个方向是对的但时机很重要。关掉PasswordAuthentication no之前我建议先在另一个终端窗口测试一次纯密钥连接确认不用密码也能顺利登录再修改服务器配置。否则一旦密钥这边还有隐藏问题你在断开当前连接后可能再也进不了系统。修改方式sudo vim /etc/ssh/sshd_config找到PasswordAuthentication yes改为PasswordAuthentication no改完后重启sshdsudo systemctl restart sshd然后新开一个窗口测试连接。能进说明一切正常不能进就赶紧恢复配置。这个操作其实不难但很多人因为心急跳过验证步骤最后只能跑到云控制台用网页VNC救场。7.4 最后再分享一个小技巧scp也可以免密了配置完免密登录附带的好处是scp传文件也不用输密码了。比如从服务器上下载日志scp 用户名服务器IP:/var/log/nginx/access.log D:\logs\access.log或者上传一个配置文件scp D:\config\nginx.conf 用户名服务器IP:/etc/nginx/conf.d/test.conf既然ssh能免密scp走的是同一套认证机制自然也是免密的。写自动化脚本的时候这省掉的可不是一点点操作成本。整体来说整套流程从生成密钥到日常使用大概十几分钟就能搞定。我的个人建议是先拿一台不重要的测试服务器练习一遍把各个环节捋顺再往生产环境推进。毕竟多花十分钟配置能在这之后无数次的连接中省回无数个十分钟。