ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

VSCode/Cursor远程连接一直要密码?SSH免密登录排查与修复指南

VSCode/Cursor远程连接一直要密码?SSH免密登录排查与修复指南 1. 先搞清楚编辑器一直要的到底是服务器密码还是私钥口令1.1 同一句话背后两种完全不同的原因很多人在VSCode或Cursor里第一次配远程连接遇到一直提示要输入密码第一反应就是去改服务器上的SSH配置。我刚开始也是这么干的结果服务器端authorized_keys、sshd_config来回改了七八遍问题不但没消失反而越排查越乱。后来我才意识到第一步不是去动服务器而是先把编辑器弹出来的这个提示看清楚。VSCode和Cursor本质上都走Remote-SSH这一套机制弹窗内容虽然长得像但含义可以分成两类如果弹窗里写的是类似Enter password for userhost这是服务器登录密码提示你在进行纯密码认证。如果弹窗里写的是Enter passphrase for key /home/user/.ssh/id_ed25519这是私钥口令说明密钥已经找到了但私钥本身有加密口令需要你输入一次解开私钥。这两种情况解决路径完全不同。前者是公钥认证没成功服务器根本没收你的钥匙后者是客户端拿到了钥匙但需要口令才能开门。你如果一直把passphrase当成服务器密码来输自然输多少次都进不去因为输错几次之后SSH会直接给你一个Authentication failed然后把窗口重新弹出来。1.2 为什么手动SSH能免密VSCode和Cursor却不行很多人还遇到过一种特别矛盾的现象在终端里手动执行ssh userhost一次密码都不用输但只要回到VSCode或Cursor里点连接就又是那个密码框。这里面有个关键差异你手动执行ssh命令时OpenSSH客户端会默认尝试当前用户主目录下所有标准私钥文件比如~/.ssh/id_ed25519、~/.ssh/id_rsa一旦成功就免密登录。而VSCode和Cursor的Remote-SSH虽然最终也是调用ssh命令但它们对环境中可用的密钥来源依赖程度更高。尤其在Windows上如果私钥文件存放在某个从网上下载的压缩包里解压出来的目录而不是标准用户目录下手动ssh可能压根没用到这个私钥它用的是系统里Windows自带的OpenSSH代理已经缓存好的那把而VSCode启动时没有读到同一个代理状态于是回到密码认证。还有一种情况就是手动ssh用的用户身份和Remote-SSH配置里的User字段对不上手动命令里默认是当前Linux登录名而VSCode配置文件里写的是root或者其他账号两把钥匙对应两个账号自然一个免密一个要密码。所以在动手改任何东西之前先确认弹窗里要的到底是password还是passphrase再确认你手动ssh时用的用户和私钥路径跟编辑器配置里是否完全一致。这一步看起来简单实际能省掉后面一大半的冤枉路。2. 用ssh -vvv的输出判断密钥到底递到哪一步断了2.1 调试日志怎么读如果你已经确认手动ssh可以免密登录但VSCode不行那接下来不要瞎猜直接用verbose模式看一次真实握手过程。终端执行ssh -vvv -i ~/.ssh/id_ed25519 userhost注意这里加-i是想强制指定私钥目的是把客户端行为限定在最小范围。这条命令执行后屏幕上会刷出几十行debug信息。别被这堆输出吓到你只需要盯几个关键行。正常情况下你会看到类似这样的信息debug1: Offering public key: /home/user/.ssh/id_ed25519 ED25519 SHA256:xxxxxxxx... debug1: Server accepts key: ... debug1: Authenticated to host ([192.168.1.10]:22).这三行代表完整的成功链路客户端把自己的公钥指纹发给服务端服务端在authorized_keys里查到了对应条目于是直接认证通过。如果失败你会看到两种典型情况debug1: Offering public key: /home/user/.ssh/id_ed25519 debug1: Next authentication method: password这说明客户端确实把公钥递过去了但服务端没有接受程序自动降级到密码认证。搜索关键字你有没有意识到Offering后面没有接Server accepts key中间一定出了问题。还有一种情况debug1: No more authentication methods to try.或者直接就跳到Next authentication method: password这说明客户端压根没有可用的私钥可以递给服务器或者被服务器拒绝前就没了。2.2 日志关键词与问题层级的对应关系我整理了一个自查速查表每次排查都直接对照debug日志特征问题所在层级优先排查方向出现Offering public key但没有Server accepts key服务端不认这把公钥authorized_keys内容、权限、是否追加错行完全没有Offering public key这一行客户端没有可用身份IdentityFile路径、ssh-agent是否缓存密钥、config配置出现Too many authentication failures客户端提交密钥太多、服务端拒绝配置IdentitiesOnly yes同时清理ssh-agent无用密钥出现Permission denied (publickey,password)服务端只允许公钥或密码认证但两者都失败服务端sshd_config检查PubkeyAuthentication再看本地私钥和agent出现passphrase相关提示私钥文件本身有加密口令用ssh-add把解出口令后的密钥写进agent或重做无口令私钥这个表不用背重要的是理解一个逻辑SSH免密登录成功需要客户端愿意出示正确的钥匙服务端愿意接受这把钥匙两者缺一不可。debug输出就是告诉你断在哪一端。我自己的习惯是只要遇到这种问题我不管手动ssh行不行都会先跑一次ssh -vvv -i ~/.ssh/对应私钥 userhost把输出从头到尾过一遍。5分钟之内基本能定位问题方向总比自己对着配置瞎改半小时强得多。3. 修复实操按这个顺序从本地到服务器一趟走完3.1 第一步确认并生成密钥对把公钥放到服务端如果你本地还没有SSH密钥对直接生成一把用ed25519算法主推现代客户端和服务端安全性和速度都好ssh-keygen -t ed25519 -C my-vps-key -f ~/.ssh/id_ed25519生成过程中如果你不设置passphrase就一路回车。这个操作生产的私钥是明文的只要不泄露给他人安全性依然可以接受。然后把公钥传到服务器有工具直接一步到位ssh-copy-id -i ~/.ssh/id_ed25519.pub userhost如果你用的发行版没有ssh-copy-id手动追加也简单cat ~/.ssh/id_ed25519.pub | ssh userhost mkdir -p ~/.ssh chmod 700 ~/.ssh cat ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys这里顺手把目录和文件的权限都做了因为服务端OpenSSH对~/.ssh目录和authorized_keys的权限要求很严。目录必须是700文件可以是600或644但如果组和其他人可写服务端会拒绝使用。这才是免密配置里第一道容易被忽略的门槛。3.2 第二步处理Windows上私钥权限这是最常翻车的地方如果你跟我一样主要用Windows做日常开发那大概率栽过这个坑私钥明明在权限也看着正常但手动ssh每次都能连上VSCode连不上。原因往往是私钥文件的安全描述符里包含了继承自其他目录的ACL条目OpenSSH for Windows对这种权限过宽的私钥会直接拒绝使用并把这把锁当作无效。怎么判断两个办法。第一看ssh -vvv日志里有没有类似Bad permissions或permissions too open的warning第二直接执行下面这个PowerShell命令把权限收干净# 对私钥文件只保留当前用户读取权限并关闭继承 icacls $env:USERPROFILE\.ssh\id_ed25519 /inheritance:r /grant:r $env:USERNAME:R # 对.ssh目录只保留当前用户完全控制并关闭继承 icacls $env:USERPROFILE\.ssh /inheritance:r /grant:r $env:USERNAME:F执行完之后还有一种图形界面方式可以确认右键私钥文件选择属性 → 安全 → 高级你会看到继承已关闭权限列表里只有你自己的账户而没有SYSTEM、Administrators都还在的情况。每次从压缩包解压、从旧电脑拷贝、或用工具导入过密钥都值得重新检查一次ACL。这个问题太隐蔽因为它不影响你用其他方式打开文件只有OpenSSH在意。3.3 第三步在~/.ssh/config中把身份固定下来这是最核心的一步。很多人的VSCode/Cursor反复要密码就是因为config文件里没有明确指定用哪把钥匙。新建或修改~/.ssh/config写入以下内容Host my-server HostName 192.168.1.10 User root Port 22 IdentityFile ~/.ssh/id_ed25519 IdentitiesOnly yes ServerAliveInterval 60 ServerAliveCountMax 3这里几个字段的作用得说明白IdentityFile强制指定使用这把私钥。没有这行SSH客户端只会尝试默认文件而你的认证文件如果不是标准名字或者放在别处就会跳过。IdentitiesOnly yes告诉SSH别把ssh-agent里其他所有钥匙都拿去试只用config里指定这把。这个选项能直接解决多钥匙环境下Too many authentication failures的问题。ServerAlive是心跳保活参数防止长时间不操作后连接被服务端掐断。如果你经常被卡死后要重连加上这两个参数体验会好非常多。修改完后不要忘记VSCode/Cursor里新建连接的时候Host字段填的不是userhost而是这个config里自定义的别名my-server也就是在Remote-SSH连接面板里直接输入my-server回车。3.4 第四步检查服务端sshd_config如果客户端已经配置成指定钥匙日志显示Offering public key但服务端没有回应确认那问题就在服务端。登录服务器执行sudo grep -E PubkeyAuthentication|AuthorizedKeysFile|PasswordAuthentication /etc/ssh/sshd_config正常情况下应该看到PubkeyAuthentication yes AuthorizedKeysFile .ssh/authorized_keys PasswordAuthentication yesPasswordAuthentication是否要改成no是你的策略问题但公钥认证至少得是yes。如果被注释掉了也默认是yes但如果被显式改成了no那无论本地配置多正确服务器都不会接受钥匙。检查完修改后记得重载服务sudo systemctl reload sshd # 或者老式SysVinit系统 sudo /etc/init.d/ssh reload注意是reload不是restartreload不中断现有连接更安全。3.5 私钥本身有口令时用ssh-agent一劳永逸如果你确实给私钥设置了passphrase又不想每次都输入那最舒服的方式是用ssh-agent# Linux / macOS eval $(ssh-agent -s) ssh-add ~/.ssh/id_ed25519macOS上还可以用密钥链保管免去重启后重新添加ssh-add --apple-use-keychain ~/.ssh/id_ed25519Windows系统只要OpenSSH Authentication Agent服务开着也可以直接执行ssh-add $env:USERPROFILE\.ssh\id_ed25519做完这步后当你在VSCode或Cursor里连接时私钥口令就由agent接手不会再弹出passphrase框。这一步对于那些不是卡在服务器认证、纯粹卡在私钥口令上的人是最终解法。4. 几个容易反复踩的隐秘细节4.1 authorized_keys文件里的换行符和空行如果你在Windows上手动编辑过authorized_keys文件再传回Linux服务器极大概率踩坑。记事本或一些编辑器默认保存CRLF换行而OpenSSH解析这个文件时对结尾回车符处理偶尔出问题导致整行公钥识别不了。解决方法是把文件转换成LF或者干脆在Linux服务器上用echo命令重新写入。另外authorized_keys每一行只允许一条公钥。如果你不小心把多条公钥粘在了同一行后面那条永远不会生效。我自己用scp传文件的习惯是传.pub文件然后在服务器上执行cat id_ed25519.pub ~/.ssh/authorized_keys用系统原始文件追加能避开一切换行和编码问题。4.2 组策略和SELinux的极端情况服务端如果启用了SELinux即使权限正确公钥也可能被安全策略拦下。多见于CentOS/RHEL系。判断方法很简单ls -Z ~/.ssh/authorized_keys正常会显示类似system_u:object_r:ssh_home_t:s0的上下文。如果不对执行restorecon -Rv ~/.ssh不过说实话现在很多云服务器默认系统盘关闭SELinux这个问题频率不算高如果前几步都查过还不行再往这个方向试。理论上推荐的顺序是最后排查它因为它最小众。4.3 多次认证失败限制——多把钥匙反而坏事ssh-agent里如果缓存了五六个密钥OpenSSH客户端在与服务器握手的默认行为是把所有可用私钥挨个试而服务端默认MaxAuthTries只允许6次尝试。一旦你的尝试次数超过限制不管里面最后一把钥匙是不是对的连接直接被拒提示Too many authentication failures。你说气不气明明有对的钥匙却被前面那些不对的钥匙拖累。解决方式就是上面提到的IdentitiesOnly yes或者把agent里不需要的key清掉ssh-add -D ssh-add ~/.ssh/id_ed25519我个人的习惯是在config里全部显式指定IdentityFile并开启IdentitiesOnly让行为完全确定不依赖agent的随机顺序。4.4 密钥算法兼容性新版客户端遇到老服务器如果你用的还是老式RSA私钥而服务器OpenSSH版本比较旧或者反过来新版客户端默认禁用了ssh-rsa签名算法也可能出现密钥明明配好但认不了的情况。这类问题在CentOS 6/7老机器上尤其多。可靠的做法是直接用ed25519算法重建密钥对并重新把公钥放到服务器。如果有些老旧设备只认RSA那才考虑生成rsassh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa在config里把IdentityFile指向新的id_ed25519就行。4.5 修改配置后VSCode/Cursor不会自动感知配置文件和密钥改完光点连接按钮没用。Remote-SSH插件区经常缓存了旧连接状态。最稳妥的操作顺序是关闭当前远程窗口退回本地。打开命令面板执行Remote-SSH: Kill VS Code Server on Host...选中对应主机清理远端残留进程。完全退出VSCode/Cursor再重新打开。不要小看这一步。很多时候你本地配置已经修好了但远端还残留着旧会话信息插件区再用旧会话去握手结果当然还是老样子。4.6 known_hosts指纹变化服务器重装系统或更换IP后known_hosts里的主机指纹会跟你当前SSH到的服务器对不上这时候连接会被中断可能表现为反复要求密码或直接提示指纹冲突。看debug日志时如果出现REMOTE HOST IDENTIFICATION HAS CHANGED处理方法就是删除旧的known_hosts条目ssh-keygen -R 192.168.1.10然后重新连接接受新指纹即可。这个问题不常见但遇到时特别迷惑因为其他所有配置看起来都是对的。5. 一张自查清单按顺序过一遍基本都能解决我把整个排查路径整理成一张清单每次遇到VSCode/Cursor一直要密码就直接按这个顺序走看弹窗是password还是passphrase如果是passphrase直接用ssh-add解锁并添加进agent。执行ssh -vvv -i ~/.ssh/id_ed25519 userhost判断问题在客户端还是服务端。客户端层面检查私钥文件是否存在、命名是否标准、Windows下ACL是否收干净、config是否显式设置IdentityFile和IdentitiesOnly。服务端层面检查authorized_keys里是否有对应公钥、目录和文件权限是否为700/600、sshd_config里的PubkeyAuthentication是否为yes、SELinux是否干预。清理远端用Remote-SSH命令杀掉远端Server进程重启编辑器确保known_hosts没有指纹冲突。如果用的是跳板机/堡垒机还要确认config里通过ProxyJump定义的跳板账号也有正确的密钥否则会卡在半路。5.1 配置完成后如何快速验证修复完不要急着打开VSCode先在本地终端里验证整条链路ssh -i ~/.ssh/id_ed25519 my-server echo OK hostname这里用-i和config别名有点重复但没关系它保证我们指定的钥匙在起作用。如果这句输出OK加主机名说明SSH本身已经通了接下来再去VSCode里连my-server基本一次成功。之后每次新建远端项目、换新机器、或者公司跳板机变更过密码我都习惯跑一遍这条验收命令再进入编辑器。这个习惯让我省掉了很多不必要的反复。5.2 一点诚实的经验折腾这个问题的过程里我最大的体会是SSH免密失败的原因远没有想象中复杂但排查顺序错了会把人折磨到崩溃。我最开始总是一上来就怀疑服务器配置把sshd_config翻个底朝天结果罪魁祸首往往只是Windows私钥权限没收拾干净或者被ssh-agent里多余钥匙拖累。所以与其用试去撞答案不如尊重debug输出让日志告诉你该修哪里然后再动手。这个过程初看繁琐实际上比随机尝试省时间得多。另外如果你同时用VSCode和Cursor配置文件是完全共享的修好一次两边都会跟着好。这一点算是这类编辑器较省心的地方至少不用为两款软件分别维护两套SSH配置。如果你按这个清单走了一遍还是不行那我建议把ssh -vvv完整输出贴出来再去社区的Remote-SSH板块搜索关键词基本能找到对应问题。毕竟你的情况大概率不是全球第一个遇到的也绝对不是最后一个。
返回列表