1. 为什么Remote-SSH能解决"每次输密码"这个老大难
先说个真实场景:我日常要在公司的跳板机、家里的NAS、云上的开发服务器之间来回切,每台机器的密码策略还不一样,有的要求12位起步、有的三个月强制换一次。刚开始用VS Code的Remote-SSH插件时,每次连接都要敲一遍密码,一天下来光输密码就得十几次。后来实在受不了,花了一个下午把SSH密钥认证彻底搞定,从那以后所有远程开发都是秒开,输入密码这件事彻底消失在我工作流里。
Remote-SSH的原理很简单:VS Code在本地跑一个客户端,通过SSH协议连到远程机器,然后在远程机器上启动一个服务器端组件(vscode-server),本地编辑器界面和远程文件系统通过这个通道同步。你本地装插件、敲快捷键、看代码,实际执行和编译都在远程机器上完成。这个机制天生就是为密码认证设计的——每次建立连接都需要身份验证,如果走密码,那就是一次一输。
免密登录的本质,就是把"密码认证"换成"密钥认证"。
密钥认证用的是非对称加密:本地生成一对密钥(公钥+私钥),把公钥放到远程机器的~/.ssh/authorized_keys文件里。连接时,远程机器用公钥加密一段随机数据发给本地,本地用私钥解密后回传,远程验证通过就算登录成功。整个过程不需要在网络上传输密码,安全性比密码认证更高,也彻底绕开了"每次敲密码"的痛点。
这篇文章就围绕这件事展开:密钥怎么生成、公钥怎么放过去、VS Code里怎么配、踩了哪些坑,以及几个能让体验更顺滑的进阶操作。适合被Remote-SSH输密码折磨过的人,也适合刚接触SSH密钥认证、想在VS Code里直接落地的新手。
2. 准备工作:搞清楚你的SSH客户端环境
动手之前,先确认本地环境里有没有可用的SSH工具。Windows、macOS、Linux三套系统的检查方式不太一样,但目标一致:能执行ssh命令,能找到~/.ssh目录。
2.1 Windows环境:OpenSSH客户端要装好
Windows 10 1809之后的版本基本都自带OpenSSH客户端,但老系统、精简版系统可能会有缺失。判断方法很简单:打开PowerShell或CMD,输入:
ssh -V能输出版本号(比如OpenSSH_for_Windows_8.1p1, LibreSSL 3.0.2)就说明没问题。如果提示"不是内部或外部命令",需要自己去"设置 → 应用 → 可选功能"里添加OpenSSH客户端,或者用winget安装:
winget install Microsoft.OpenSSH.Beta提示:Windows下安装完后,记得重开一个终端窗口,让PATH环境变量生效。
2.2 macOS和Linux:基本都是自带的
macOS和主流Linux发行版默认都带OpenSSH客户端,直接验证就行:
ssh -V如果哪台机器意外没装(比如精简版Linux服务器),macOS可以用Homebrew装:
brew install opensshDebian/Ubuntu系列:
sudo apt update && sudo apt install openssh-client2.3 确认本地SSH密钥是否已存在
很多人之前配过GitHub的SSH免密,那本地其实已经有密钥了,没必要重新生成。查看方式:
ls -la ~/.ssh/看到id_ed25519和id_ed25519.pub这类文件就说明已有密钥对。id_ed25519是私钥(绝对不能外传),id_ed25519.pub是公钥(可以放到任何远程机器上)。
如果目录不存在或者为空,才需要重新生成一对密钥。生成命令推荐用ed25519算法:
ssh-keygen -t ed25519 -C "your_email_or_comment"执行后会问两个问题:保存路径(直接回车用默认的~/.ssh/id_ed25519)和密码短语(passphrase)。
这里有个常见的认知误区:passphrase和服务器密码是两回事。passphrase是给私钥文件本身加密用的,相当于私钥的"开机密码"。如果设了passphrase,每次使用私钥时还要输入一次,等于免密登录只免了远程机器密码,没免本地私钥密码。但VS Code的Remote-SSH和系统SSH Agent配合后,可以做到只在首次解锁私钥时输一次,后续全程免密。
我的建议是:本地电脑是个人设备、没有物理安全顾虑的话,passphrase可以直接留空;如果是公司电脑或公用机器,建议设置passphrase,然后配合SSH Agent用(后面讲)。
生成完成后,查看公钥内容:
cat ~/.ssh/id_ed25519.pub形如ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAxxxxx your_email@example.com的一长串就是你的公钥。
3. 把公钥放到远程机器:三种方式任选
公钥放不到远程机器上,免密就是空谈。根据你手头的条件,从最简单的开始选。
3.1 最省事的方式:ssh-copy-id
Linux和macOS用户基本都有ssh-copy-id这个工具,一条命令把公钥推过去并自动追加到authorized_keys:
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@remote_host执行后会要求输入一次远程机器的密码,输入后工具会自动在远程创建~/.ssh目录(如果没有)、把公钥追加到authorized_keys、并设置正确的权限。整个过程只需一次密码。
3.2 Windows用户的替代方案
Windows自带的OpenSSH客户端通常没有ssh-copy-id命令,但有两个办法:
办法一:用PowerShell管道手工写入
type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh user@remote_host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"这个命令会先读取本地公钥内容,通过管道传给远程的ssh命令,远程端执行mkdir -p ~/.ssh创建目录、用cat >>追加到authorized_keys。
办法二:直接在远程机器上手工编辑
如果远程机器有网页终端(云服务商控制台自带的那种)或者你能通过其他方式登录,直接登录远程机器,执行:
mkdir -p ~/.ssh chmod 700 ~/.ssh echo "ssh-ed25519 AAAA...你的公钥内容..." >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys注意权限:~/.ssh必须是700,authorized_keys必须是600。权限太宽松的话,OpenSSH会认为文件不安全,直接忽略这个文件,导致免密失效。
3.3 放完后先手动验证一次
无论用哪种方式,放完公钥后先别急着动VS Code,在终端里手测一下:
ssh user@remote_host如果直接进到远程机器的shell而没要密码,说明密钥认证已经生效。如果还是要密码,先别继续往下走,去检查权限和文件路径。
注意:远程机器的
~是指你登录用户的家目录。如果你登录的是root,那就是/root/.ssh/authorized_keys;如果登录的是普通用户dev,那就是/home/dev/.ssh/authorized_keys。放错用户目录是免密失效的头号原因。
4. 在VS Code里配置并验证免密连接
命令行SSH免密验证通过后,VS Code Remote-SSH基本就水到渠成了。这个插件并不自己实现SSH协议,而是复用你本机的OpenSSH客户端,所以命令行能免密,VS Code就一定能免密。
4.1 安装Remote-SSH插件
VS Code扩展市场搜索"Remote - SSH",认准微软官方发布的(发布者为Microsoft),安装量千万级那个。装完会提示重载窗口,照做就行。
4.2 配置SSH Config文件
Remote-SSH插件会读取SSH Config文件里的主机信息。在VS Code里按F1,输入Remote-SSH: Open SSH Configuration File,选择配置文件打开。
Windows路径一般是C:\Users\你的用户名\.ssh\config,macOS/Linux是~/.ssh/config。没有这个文件就手动新建一个。
一个最小可用的配置示例:
Host my-server HostName 192.168.1.100 Port 22 User dev IdentityFile ~/.ssh/id_ed25519各字段含义:
Host:你在VS Code里看到的主机别名,可以自定义,比如my-web-server、nas,方便记忆HostName:实际连接的IP地址或域名Port:SSH端口,默认22,改了端口就填对应值User:远程登录用户名IdentityFile:指定使用哪个私钥文件。本地有多对密钥时建议显式指定,避免SSH默认顺序找不到对的私钥
如果远程机器还有跳板需求,config里还可以配ProxyJump,但那个属于进阶玩法,后面单独说。
4.3 在VS Code中连接并观察过程
配置好后,VS Code左下角有个绿色的><图标(Remote Window按钮),点它会弹出远程连接菜单,选择Connect to Host,再选刚才配置的my-server,VS Code会新开一个窗口开始连接。
第一次连接远程机器时,VS Code需要往远程下载并解压vscode-server组件,这取决于网速,通常需要几十秒到几分钟不等。左下角状态栏会显示下载进度,底部输出面板能看详细日志。
连接成功后,左下角会变成SSH: my-server,左下角的绿色图标也变成远程状态。此时打开的文件、终端都是远程机器上的,本地和远程由一条安全通道连通。
关键验证点:整个连接过程没有弹出任何密码输入框的话,说明VS Code已经通过SSH Config里的IdentityFile找到了本地私钥、完成了密钥认证,免密登录正式生效。
4.4 常见失败点:VS Code提示输入密码但命令行免密正常
这个问题很多人遇到过:命令行ssh已经免密了,VS Code连接还是弹密码框。排查思路如下:
第一,确认VS Code用的SSH客户端和命令行是同一个。Windows下如果装了Git Bash,Git Bash自带的ssh和系统OpenSSH可能是两套密钥目录。VS Code的Remote-SSH默认调用的也是系统ssh,但如果你在VS Code设置里改了remote.SSH.path指向了别的ssh程序,那走的可能就是另一套配置。检查方法:VS Code设置里搜remote.SSH.path,留空表示用系统默认。
第二,确认IdentityFile路径写对了。Windows下config文件里的路径要写成/c/Users/你的用户名/.ssh/id_ed25519(Git Bash风格)或者C:\Users\你的用户名\.ssh\id_ed25519(部分场景支持),但最稳妥的做法是写成~/.ssh/id_ed25519,让SSH客户端自己解析。
第三,看SSH日志。在VS Code的输出面板里选"Remote - SSH"频道,能看详细的连接日志。如果日志里出现Offering public key、Authentications that can continue: publickey这类信息,说明服务器在要求公钥认证但本地没提供对的公钥;如果出现Permission denied (publickey,password),说明公钥认证失败后回落到密码认证——这时候优先怀疑authorized_keys内容或权限有问题。
5. 免密登录的原理与权限细节:为什么有时候"全对"却连不上
很多人在免密配置上栽跟头,不是公钥没放对,而是踩了SSH权限检查的隐藏雷区。这节把原理和细节说透。
5.1 SSH密钥认证的完整流程
一次标准的SSH密钥认证,流程是这样的:
- 客户端发起连接,告诉服务器自己有哪些公钥(通过
SSH_MSG_REQUEST_PUBKEY消息试探) - 服务器检查公钥是否在目标用户的
authorized_keys里,如果在,就用这个公钥加密一段随机质询数据发回客户端 - 客户端拿到质询数据,用本地私钥解密,再把解密结果发回服务器
- 服务器验证解密结果正确,认证通过,建立会话
这就是为什么公钥文件比私钥文件更"公开"的原因:公钥只是用来加密质询数据的,真正的身份验证靠的是持有对应私钥这一事实。把公钥随便发到GitHub、服务器上都没问题,但私钥一旦泄露,就等于把家门钥匙交给了别人。
5.2 权限检查:OpenSSH的"洁癖"
OpenSSH服务端对目录权限有严格要求,任何一步权限"过度开放"都会导致authorized_keys被忽略。常见权限要求如下:
| 路径 | 要求权限 |
|---|---|
用户家目录~ | 不能对组和其他用户开放写权限(不能是777或755) |
~/.ssh目录 | 700(只有本人可读写执行) |
~/.ssh/authorized_keys | 600(只有本人可读写) |
~/.ssh/私钥文件 | 600(只有本人可读写) |
| 父目录的所有者 | 必须是你本人或root |
如果你用ssh-copy-id推的公钥,这些权限工具会自动设好;但如果你是用echo或scp手工放过去的,很可能忽略了权限问题。
排查命令:
ls -ld ~ ~/.ssh ~/.ssh/authorized_keys看到形如drwx------(目录)和-rw-------(文件)就符合要求。如果权限不对,用这两条修正:
chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys如果家目录权限也有问题,还需要:
chmod 755 ~注意:这里的
~是远程机器上你登录用户的家目录,不是本地路径。很多人习惯性在自己电脑上执行chmod,结果改了个寂寞。
5.3 远程机器的SELinux或防火墙也可能拦截
Linux服务器开启了SELinux(CentOS、RHEL、龙蜥等系统常见)时,即使文件权限全对,SELinux策略也可能拒绝SSHD读取新添加的authorized_keys。
如果免密失效且权限都正确,可以试试:
restorecon -R -v ~/.ssh这条命令会恢复.ssh目录的SELinux上下文。运气好的话,一条命令就解决问题。
另外,云服务器安全组和系统防火墙(firewalld/ufw)也要确认放行SSH端口。有时候公钥认证是成功的,但连接被防火墙拦在半路,表现也是"连不上"或者"要密码",容易误导排查方向。
6. SSH Agent与passphrase:本地私钥加密上了怎么办
如果生成密钥时给私钥设置了passphrase,那么每次使用私钥时,SSH客户端都会要求输入这个passphrase。VS Code连接远程机器时也一样——虽然远程密码免了,但本地私钥还等着解锁,等于没免干净。
解决办法是用SSH Agent把私钥"暂存"在内存里,解锁一次后,后续所有SSH连接都从Agent里直接取私钥,不再反复问passphrase。
6.1 启动SSH Agent并添加私钥
Windows:
# 启动SSH Agent服务(如果未运行) Get-Service ssh-agent | Set-Service -StartupType Automatic Start-Service ssh-agent # 将私钥添加到Agent ssh-add $env:USERPROFILE\.ssh\id_ed25519执行ssh-add时会要求输入一次passphrase,输入后私钥就一直驻留在Agent里,直到重启电脑或手动移除。
macOS:
eval "$(ssh-agent -s)" ssh-add ~/.ssh/id_ed25519macOS的Agent可以由Keychain管理,加--apple-use-keychain参数(新版)可以把passphrase存入钥匙串,重启后都不需要重新添加:
ssh-add --apple-use-keychain ~/.ssh/id_ed25519Linux:
eval "$(ssh-agent -s)" ssh-add ~/.ssh/id_ed25519桌面版Linux更推荐用keychain或gnome-keyring这类工具管理,能免去每次手动ssh-add的麻烦。
6.2 没有passphrase的话,Agent还有用吗
有用。即使私钥没有passphrase,SSH Agent依然是一个推荐实践。原因是:很多SSH连接场景(比如从开发机跳板到内网服务器)需要多次转发身份。SSH Agent Forwarding(转发)可以把本地Agent的socket转发到远程,让你在远程机器上执行git clone、scp到其他机器时,也能直接用本地私钥认证,而不用把私钥文件拷到远程。
不过Agent Forwarding要谨慎使用——它相当于把本地的"免密能力"开放给了远程机器。如果远程机器被入侵,攻击者可以借用你的Agent去连接所有配置了对应公钥的机器。我的习惯是:个人开发用的可信内网机器才开Agent Forwarding,公网服务器绝对不开。
7. 高频坑汇总:Remote-SSH免密配置中我踩过的雷
这节把实际使用中遇到的典型问题和排查思路整理成清单,每一条都是真实踩过的。看完之后,大部分免密问题你都能自行定位。
7.1 连上之后又掉线:SSH保活机制
远程开发经常有这种场景:代码写到一半去倒杯咖啡,回来发现VS Code已经断线重连了,或者终端卡在那儿不动。这是因为SSH连接在长时间没有数据交互后,会被网络设备(NAT网关、云防火墙)判定为超时连接而掐断。
解决办法是在SSH Config里加保活参数:
Host my-server HostName 192.168.1.100 User dev IdentityFile ~/.ssh/id_ed25519 ServerAliveInterval 60 ServerAliveCountMax 3ServerAliveInterval 60表示每60秒客户端主动向服务器发一个保活心跳包;ServerAliveCountMax 3表示连续3次心跳无响应才断开。设置后,长时间挂机、断网恢复后的自动重连都会稳定不少。
7.2 多台机器要用不同的密钥或配置
工作中有几台不同的服务器,有的内网、有的公网、有的需要指定特定私钥。SSH Config支持为每个主机单独指定所有参数:
Host office HostName 192.168.1.10 User dev Port 22 IdentityFile ~/.ssh/id_ed25519_office Host cloud HostName 47.98.xx.xx User root Port 22022 IdentityFile ~/.ssh/id_rsa_cloudVS Code Remote-SSH连接时,插件会读取整个config文件,你在连接菜单里选择哪个Host,就走哪套配置。一台开发机同时管理多个远程环境非常方便。
7.3 跳板机场景:ProxyJump
公司内部网络常见的拓扑是:本地只能直连跳板机,内网开发服务器要通过跳板机才能访问。SSH原生支持跳转代理:
Host jump HostName 跳板机IP User yourname IdentityFile ~/.ssh/id_ed25519 Host inner-server HostName 10.0.1.50 User dev IdentityFile ~/.ssh/id_ed25519 ProxyJump jump配置后,VS Code连接inner-server时,SSH客户端会自动先连上jump,再通过jump转发连接到内网服务器。整个过程免密,VS Code里显示也是直接连上内网目标。
7.4 "Could not establish connection to" 的通用排查清单
如果VS Code连接远程机器失败,按以下顺序逐一排查:
| 检查项 | 验证方法 | 常见修复 |
|---|---|---|
| 网络可达性 | ping 远程IP | 检查防火墙/安全组 |
| SSH端口 | telnet 远程IP 22 | 检查sshd是否监听 |
| 用户名 | ssh user@host能否登录 | 确认username |
| 密钥认证 | ssh -v user@host看日志 | 检查authorized_keys |
| vscode-server | 查看远程 ~/.vscode-server | 删除后重新连接 |
| 磁盘空间 | df -h | 清理远程磁盘 |
| 系统时间 | date对比 | 时间偏移过大可能影响某些认证 |
其中vscode-server损坏或版本不一致是VS Code特有的大坑。插件更新、远端环境异常、磁盘空间满了,都可能让~/.vscode-server处于半损坏状态。遇到连接报错但命令行SSH正常的情况,先删掉远程的~/.vscode-server目录再重连,让VS Code重新部署一次,往往能直接解决。
7.5 公钥变更后不生效的坑
有时候你重新生成了密钥对,把新公钥放到了远程,但连接还是用的旧公钥。这是因为SSH Agent里缓存了旧的私钥。检查方式:
ssh-add -l如果列表里显示的是旧密钥信息,先清除再添加:
ssh-add -D ssh-add ~/.ssh/id_ed25519对于VS Code来说,重启一次窗口或彻底退出重开,确保SSH Agent状态重新加载。
8. 进阶:把Remote-SSH免密用得更顺手
免密登录搞定后,远程开发的体验还能再上一层楼。这节分享几个我日常依赖的进阶配置。
8.1 直接通过VS Code打开远程文件夹
连接上远程主机后,VS Code左上角的资源管理器会显示远程文件系统。点"打开文件夹",输入远程绝对路径(比如/home/dev/project),就能像操作本地项目一样浏览、编辑远程代码。配合免密,整个过程没有一次密码输入,打开速度取决于网络和文件数量。
8.2 远程终端:用VS Code的集成终端操作远程机器
连接成功后按Ctrl+`打开终端,这个终端直接运行在远程机器上。免密的好处在这里体现得淋漓尽致:你可以一次开三个终端,一个跑web服务、一个跑数据库客户端、一个敲Shell命令,全部都在远程机器上,本地只需要一个VS Code窗口。
配合Remote-SSH: Open Folder打开的项目目录,终端默认就切到项目路径下,省去了每次cd的麻烦。
8.3 端口转发:让本地浏览器访问远程服务
远程机器上跑了个Web服务(比如开发服务器监听在0.0.0.0:3000),本地浏览器想访问怎么办?Remote-SSH自带端口转发功能。
VS Code里按F1,输入Remote-SSH: Forward Port from Active Host,填入远程端口号(比如3000),VS Code会在本地随机开一个端口(或直接映射),然后提供http://localhost:3000让你访问。配合免密和SSH隧道,本地调试远程服务完全不需要手动起隧道命令。
8.4 远程机器离线安装vscode-server(离线环境)
部分内网服务器无法访问外网,VS Code第一次连接时会卡在"下载vscode-server"这一步。这种情况需要手动把vscode-server的压缩包拷到远程机器上。
操作思路:先在本地或一台能联网的机器上,从VS Code的更新服务器下载对应版本的vscode-server-linux-x64.tar.gz,然后scp到远程,解压到~/.vscode-server/bin/<commit-id>/目录。具体版本号可以从VS Code的Help → About里看到Commit ID,也可以从连接日志里找到它尝试下载的URL。
这个方法略繁琐,但确实是离线内网环境使用Remote-SSH的标准解法。前提是本地到远程的SSH通道本身就是通的——免密配好之后,整个文件传输过程也彻底免密,可以说是一环套一环的收益。
9. 从免密到更高效:我的长期使用体会
把Remote-SSH免密配好之后,收益是持续性的,不只是省了输密码那几秒钟。最直观的变化是:远程开发从一个"需要专门准备"的事,变成了跟本地开发一样自然的事。打开VS Code、选主机、进项目,一气呵成。
我个人的习惯是把常用的主机都写进~/.ssh/config,每台主机一个语义清晰的别名,比如pro-web、staging-db、home-nas。这样每次开远程都不需要记IP、记端口、记用户名,选择主机名即可。
另外,建议定期清理authorized_keys文件里的废弃公钥。离职的同事、换掉的电脑、临时的测试密钥,不清理的话等于给旧设备留了后门。同样是免密,安全性和便利性要平衡——权限收敛、私钥保护、定时审计,这些才是免密登录能够长期稳定使用的底气。
在配置过程中如果遇到问题,按这篇文章提到的顺序排查:公钥放没放对、权限对不对、SSH Agent有没有缓存的旧密钥、VS Code的vscode-server需不需要重建。90%的问题都出在这四个环节里。剩下的10%,打开SSH日志看Authentication那段信息,一条条对着排查,基本都能找到答案。