
干了十来年开发我越来越觉得本地代码、远程服务器的组合是绕不开的日常。代码在服务器上依赖在服务器上数据也在服务器上你却要天天用 SSH 客户端连进去敲命令想看代码还得再开一个编辑器改完又要同步回去。VS Code 的 Remote-SSH 插件可以说把这条路彻底捋直了它让本地 VS Code 变成了一块“遥控器”界面、快捷键、扩展都在本地但真正读写文件、执行命令、跑调试的其实是远程服务器。这篇文章就按我自己的实操路径从原理、环境准备、免密登录到远程跑代码、踩坑排错一步步写清楚适合刚接触远程开发的初学者也适合已经会用但老被各种小问题卡住的朋友。1. 为什么推荐 Remote-SSH这套方案的设计思路是怎么来的刚入行那会儿远程开发最常见的做法是本地开一个编辑器改完代码用 FTP/SFTP 传到服务器再手动登录服务器跑一遍脚本。这套流程最大的问题不是慢而是“版本容易漂移”——本地改了一版服务器上还是旧的出问题了你根本不知道在调谁。后来有人用 Samba 把服务器目录直接挂载成本地盘虽然省了上传这一步但本地工具链解释器、编译环境、调试器和服务器不一致很多坑也就跟着来了。Remote-SSH 的思路完全不同。它不是同步文件而是让本地 VS Code 变成纯前端界面所有代码读写、终端操作、语言服务全部在远程服务器上执行。你按 F5 调试时本地只是发了个指令真正启动调试会话的是服务器上的 VS Code Server 组件。这样代码、环境、数据三者天然统一再用不上“本地一份、服务器一份”这种双轨模式。1.1 这套架构解决的核心痛点第一痛点是环境一致性。服务器上跑的是 Linux本地是 Windows 或 macOS同一个 Python 脚本在两边的包版本、路径分隔符、权限模型都可能不同。Remote-SSH 让你直接在服务器环境里写代码、跑测试彻底绕开“在我电脑上是好的”这种尴尬。第二痛点是编辑体验。用命令行 Vim 写 Python 不是不行但代码补全、跳转定义、重构这些现代编辑器的基本能力会大打折扣。Remote-SSH 相当于把 VS Code 的完整编辑能力“远程化”你在本地怎么用连到服务器后还是怎么用。第三痛点是协作。团队共用一台开发机时每个人连进去看到的都是同一个工作区代码一致、配置一致沟通成本低很多。尤其是训练模型、处理大数据的场景数据根本搬不动只有远程开发这一条路。1.2 Local 与 Remote 扩展的差异为什么有些扩展在远程端会“消失”用 Remote-SSH 后你会发现一个现象左边扩展栏被分成了两层“本地已安装”和“SSH: 主机名”两组。这是这套架构最容易让新人懵的地方。Python、C/C、Jupyter 这类扩展必须安装到远程端因为它们要解释代码、分析语法树、访问远程的解释器。如果你只装在本地连到服务器后会显示“此扩展在此工作区中被禁用因为其被定义为在远程扩展主机中运行”然后提示你安装到远程。UI 美化、主题、图标这类纯界面扩展则留在本地就行装到远程反而浪费资源。我现在的习惯是先装上 Remote Development 扩展包里面包含 Remote-SSH、Remote-WSL、Dev Containers 三个模块再在需要的时候让 VS Code 自动把语言类扩展装到远程端。这样做的好处是不同项目依赖的解释器版本不同扩展跟着项目走不容易出现“本地扩展把远程进程带崩”的情况。2. 环境准备先把本地和服务器两边弄利索Remote-SSH 最让人省心的一个地方是它几乎没有“重装环境”的要求。服务器端不需要你预装任何 VS Code 相关软件插件会在第一次连接时自动在 ~/.vscode-server 目录下部署一个服务端。但这不代表你可以什么都不管SSH 客户端、服务端服务、OpenSSH 版本这几个前置条件还是得先确认好。2.1 Windows 上的 OpenSSH 客户端检查与 VS Code 安装先说本地。Windows 10 1809 之后的系统都自带 OpenSSH 客户端一般不需要额外装。你可以先打开 PowerShell 执行ssh -V只要输出类似 OpenSSH_for_Windows_8.1p1 的版本信息就算过了。如果没有去“设置 - 系统 - 可选功能”里添加“OpenSSH 客户端”即可。VS Code 本体直接去官网下载稳定版装的时候我建议勾选“添加到 PATH”这样后续在终端里输 code 命令可以直接唤起编辑器。装好之后在扩展面板搜“Remote-SSH”装完重启窗口左侧出现远程资源管理器图标说明插件就位了。macOS 和 Linux 自带 ssh 客户端一般不需要额外配置。Linux 上如果 ssh 命令缺失用 apt 或 yum 装一个 openssh-client 包就能解决。2.2 服务器端的 SSH 服务检查与常见“连不上”原因服务器端需要运行 sshd 服务。Ubuntu/Debian 系统有可能默认没装 openssh-server表现就是你在本机执行 ssh userhost 直接 timeout 或者拒绝连接。先到服务器上查一下systemctl status sshd # 如果服务不存在先安装 sudo apt install openssh-server sudo systemctl enable --now ssh如果服务已经在运行但还是连不上优先检查防火墙。很多云服务器的安全组默认只放行 22 端口但本地如果是自定义端口就需要在安全组和服务器防火墙同时放行。最简单的方式是sudo ufw allow 22/tcp sudo ufw reload我踩过最隐蔽的一个坑是服务器上装了多个 SSH 端口监听sshd_config 里 Port 写的和实际进程监听的不一致。排查时可以执行 ss -tlnp | grep ssh 看真实监听端口再去和客户端连的端口对照。2.3 Windows 服务器如何参与远程开发如果你要连的是 Windows 服务器也可以用 Remote-SSH。服务器端装上 OpenSSH Server或者用 Bitvise SSH Server 这类第三方实现也行。配置好管理员登录后VS Code 连进去默认会让你选择远程操作系统的类型选 Windows 即可。需要注意的一点是Windows 远程端目前对 PowerShell 的支持比 CMD 好所以尽量把默认 Shell 设为 PowerShell否则部分扩展可能拿不到正确的环境变量。不过说实话日常后端开发遇到 Windows 服务器的概率不高Linux 场景占了绝大多数。这段就当是给特殊需求的朋友一个方向具体配置网上都有很成熟的文档。3. 配置 SSH Config 与免密登录日常开发的正确打开方式第一次连远程服务器大多数人会直接用 VS Code 的命令面板输入密码连接但每次都要输密码体验很差而且到期重置密码后所有会话都会断。配置 SSH 密钥免密登录是必须做的一步它不仅能省掉输密码的步骤还能让自动化脚本、Git 操作都顺畅起来。3.1 SSH Config 文件的多主机配置VS Code 的 Remote-SSH 会自动读取 SSH 配置文件。Windows 上路径是 C:\Users\你的用户名.ssh\configLinux/macOS 在 ~/.ssh/config。强烈建议所有主机都写进这个文件里因为你一旦有了多台服务器这个文件就是你的“服务器通讯录”。Host my-dev-server HostName 192.168.1.100 User ubuntu Port 22 IdentityFile ~/.ssh/id_ed25519 ServerAliveInterval 60 ServerAliveCountMax 3各字段的意义我简单说一下Host 是你在 VS Code 里看到的别名可以随意起HostName 是真实 IP 或域名User 是登录用户名Port 是 SSH 端口默认 22 也得写上省得换服务器时忘了改IdentityFile 指定私钥路径ServerAliveInterval 是我特别建议加的它会让客户端每隔 60 秒发一个保活包网络不稳定或长时间操作时不会因为空闲被服务器踢下线。写完保存后打开 VS Code 命令面板执行 Remote-SSH: Connect to Host就能看到刚配置的别名点击即可连接。这个配置方案最大的好处是如果你有跳板机还能用 ProxyJump 实现“先跳板、再目标”整个链路对你完全透明。3.2 生成密钥对并完成免密登录密钥对的作用是“用你的私钥作为身份凭证”。生成密钥这一步很常规ssh-keygen -t ed25519 -C your_emailexample.com连续回车会在 ~/.ssh 下生成 id_ed25519私钥和 id_ed25519.pub公钥。有经验的老手喜欢用 ed25519 而不是传统的 RSA因为它更短、更快、安全性也不差。如果你的服务器 SSH 版本太老不认识 ed25519那就换回 RSAssh-keygen -t rsa -b 4096。然后把公钥追加到服务器的授权列表里ssh-copy-id -i ~/.ssh/id_ed25519.pub ubuntu192.168.1.100ssh-copy-id 这个命令会自动处理公钥追加和权限设置比手动 cat 再粘贴省心。如果服务器禁止了 ssh-copy-id少见手动方式如下cat ~/.ssh/id_ed25519.pub | ssh ubuntu192.168.1.100 mkdir -p ~/.ssh chmod 700 ~/.ssh cat ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys完成后退出服务器重新连一次发现不用输密码就说明配置生效了。这里有一个特别容易踩的问题如果 ~/.ssh 或 authorized_keys 的权限太宽松服务器会直接拒绝公钥认证这个后面专门讲。3.3 为什么推荐密钥认证而不是纯密码密码认证最大的问题是每次连接都要输密码而 VS Code 远程开发经常要建立多个会话反复输密码效率极低。密钥相当于一把只在你本机的“钥匙”服务器只保存对应的“锁芯”公钥私钥不落盘到服务器。就算服务器被入侵攻击者拿到的也只是公钥无法反向推导出私钥。另外如果你要配置 CI/CD 或个人脚本自动拉取私有仓库密钥认证几乎是唯一靠谱的方式。把私钥加到 ssh-agent 里再配合 GitHub/GitLab 的 Deploy Key整个过程全程无密码非常顺滑。4. 在远程环境里写代码、跑代码实操部分的完整记录前面这些配置属于“地基”接下来才是大家最关心的部分怎么真正在远程环境里打开项目、改代码、跑脚本、看结果。我按自己平时的工作流一步步说。4.1 连接远程主机并正确打开项目目录在 VS Code 里按下 F1输入 Remote-SSH: Connect to Host选中目标主机。底部状态栏变成绿色或者显示 SSH: my-dev-server说明已经连上了。此时“打开文件夹”和本地完全不同弹出的是一个远程路径选择器你需要填服务器上的绝对路径。很多新人第一次会犯的错误是连上之后又从本地“文件 - 打开文件夹”去选项目。这不仅打不开远程目录还会让整个工作区变成本地模式。正确方式是连上远程后用菜单栏的“文件 - 打开文件夹”在弹出的远程文件树里定位到 /home/ubuntu/project 这类路径。连接成功后VS Code 会自动在服务器端部署 VSCode Server 组件。第一次连接可能要等几十秒甚至更久因为要下载服务端压缩包解压到 ~/.vscode-server。如果下载速度很慢大概率是网络到 GitHub 的链路问题这个后面会说怎么处理。4.2 在远程终端里运行代码以及解决“文本文档怎么运行”这类基础问题连上远程后按 Ctrl 打开终端你会发现这个终端默认就跑在服务器上和 SSH 客户端手动连进去的效果一样。这意味着你现在可以用服务器的解释器直接执行代码。我给一个最直观的示例。假设项目里有一个 Python 文件 hello.pyprint(Hello from remote server)在终端执行python hello.py输出 Hello from remote server说明代码确实是在服务器上跑的而不是本地。很多刚接触“远程运行代码”的朋友会以为必须把代码放到某个特定位置才能运行其实不是。它和你在本地 Windows 上打开命令行执行脚本是一样的逻辑终端当前目录在哪相对路径就相对哪。如果你装的是 Python 3但服务器上默认 python 指向的是 Python 2一些老系统会有这个情况可以改用python3 hello.py如果项目用了虚拟环境记得先激活再运行source venv/bin/activate python hello.py4.3 配置 Python 解释器与调试功能远程写 Python 代码至少要把 Python 扩展装到远程端。当你打开一个 .py 文件时VS Code 大概率会弹出提示询问是否安装推荐的 Python 扩展。点击“在 SSH: xxx 中安装”即可。之后用 F5 启动调试VS Code 会拿远程解释器来执行断点、变量监视、调用栈全都能正常用。如果你的项目在虚拟环境里按 CtrlShiftP 打开命令面板执行 Python: Select Interpreter选择一个远程路径下的 python 可执行文件比如 /home/ubuntu/project/venv/bin/python。选错了解释器最直接的后果是导入包时莫名其妙报 ModuleNotFoundError所以第一次配置时务必看清楚路径。Node.js、Go、Rust 等项目同理只要对应的语言扩展装到远程端调试体验和本地几乎没有差别。4.4 端口转发远程服务本地预览这招太好用了远程开发里最让我惊喜的功能是端口转发。服务器上跑了一个 Flask 或 Node.js 服务监听 5000 端口本地浏览器直接访问 http://127.0.0.1:5000 就能看到结果就像服务跑在本机一样。VS Code 会在检测到远程端口开启时自动提示“转发端口”你也可以手动操作点开“端口”面板输入远程端口号VS Code 会自动把它映射到本地某个端口。底层的原理是建立一条 SSH 反向隧道流量从本地端口转发到远程端口。你甚至可以只用命令行来完成比如ssh -L 8080:localhost:5000 -N my-dev-server这等于手动实现了“本地浏览器访问远程服务”的效果。对前后端联调、调试回调接口、演示 demo 都很实用。4.5 让远程终端更顺手的小配置连的服务器多了之后终端体验就很影响效率了。如果你习惯 macOS 风格或想要更接近现代终端的外观我这里有两个推荐一是把终端字体设为 Cascadia Code 或 JetBrains Mono这两款字体对连字符、零、小写 l 和大写 I 的区分做得很好长时间盯代码眼睛不累二是在服务器上装 zsh 加 oh-my-zsh再配合 zsh-autosuggestions 插件执行过的命令会自动提示补全按右方向键就能快速键入。这一步和 Remote-SSH 没有直接关系但配合起来很舒服。毕竟你每天都要在远程终端里敲命令命令行体验太原始的话再好的编辑器也会被拖累。字体设置的位置在 VS Code 的设置里搜 Terminal Integrated: Font Family填入字体名称即可。5. 常见问题与排查技巧实录Remote-SSH 整体体验确实稳但真正落地的过程中总会碰到一些稀奇古怪的问题。我挑几个我实际遇过、以及社区里高频出现的问题按“现象 - 原因 - 解决”的方式整理出来方便你遇到类似情况时直接对号入座。5.1 Permission denied, please try again密码和密钥都不能认证这是最经典的问题几乎每个人都遇到过。如果密码正确仍然报这个错优先怀疑 SSH 服务配置是否允许密码认证。检查服务器上的 /etc/ssh/sshd_configsudo grep -E PasswordAuthentication|PubkeyAuthentication /etc/ssh/sshd_config如果 PasswordAuthentication 是 no密码登录自然被禁PubkeyAuthentication 是 no 则密钥登录被禁。改完后记得重启服务sudo systemctl restart ssh注意要先确认当前会话能继续连不要改完就断了否则你可能把自己锁在服务器外面。这种情况我有过惨痛经历后来规范操作都是先起一个临时会话测试确认能连上再关闭旧窗口。另一个常见原因是权限太宽松。服务器端 ~/.ssh 目录权限必须是 700authorized_keys 文件权限必须是 600。如果权限给了 777 或 644OpenSSH 出于安全考虑会直接拒绝这个密钥。修复方法chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys5.2 扩展显示“在远程扩展主机中被禁用”怎么办这个问题我在前面提到过。当扩展只装到本地而没装到远程时界面会提示“此扩展在此工作区中被禁用因为其被定义为在远程扩展主机中运行”。解决方式是在扩展面板里找到该扩展点击“在 SSH: xxx 中安装”。如果你希望在连接任何远程主机时都自动安装某个扩展可以在 VS Code 设置里搜索 remote.SSH.defaultExtensions手动填入扩展 ID。这样只要有新的远程主机插件会自动带过去省得一个个手动装。5.3 Ubuntu SSH 无法连接网络和服务端的排查顺序服务器是 Ubuntu本地执行 ssh 命令一直卡住或直接超时我的排查顺序是先确认本地到服务器网络通不通ping 或 telnet IP 22再确认服务器 SSH 服务在不在systemctl status ssh最后看防火墙和安全组有没有放行 22 端口。卡在 “Connection timed out” 基本是网络层面的问题重点查安全组看到 “Connection refused” 说明包能到服务器但 SSH 端口没在监听重点查 sshd 是否启动、端口是否改过。数据库没起来、服务端口没监听这类问题最容易误导人先把这两条路径理清排查效率能高出一大截。5.4 SSH 会话断开后正在跑的命令还会继续吗这个问题经常被问到明确回答普通 SSH 会话断开后你启动的前台命令会收到挂断信号进程随之终止。如果你在远程服务器上跑一个训练脚本SSH 一断就前功尽弃这对远程开发几乎是致命的。解决方案是养成用终端复用工具的习惯。我建议大家至少会用 tmuxtmux new -s train python train.py # 按 CtrlB 然后按 D 脱离会话 # SSH 断开也不影响 tmux attach -t train # 重新接入nohup 也能实现类似效果但 tmux 功能强得多还能多窗口、分屏、滚动日志。我远程开发时的习惯是所有持久任务都丢进 tmux再配合 Remote-SSH 的终端基本不会因为 SSH 抖动导致长时间任务报废。5.5 远程连接时 VS Code Server 下载慢或卡住VS Code 连接远程主机时需要下载 server 组件有时候会卡在 “Setting up SSH Host” 很久。核心原因是 GitHub 的下载链路不稳定。常规解决办法是手动下载 vscode-server 的 tar.gz上传到服务器对应目录解压。具体操作为先在本地打开终端查看 VS Code 的版本号帮助 - 关于然后构造下载链接。链接格式里的 commit id 和版本号要匹配网上很多教程教你从日志里拿 commit id实际上最直接的方法是查看服务器上 ~/.vscode-server/bin 下的目录名那个 40 位字符串就是要找的 commit id。用 wget 下载到本地后通过 scp 传到服务器解压路径和权限对了就不再重复下载。这个问题随着网络环境改善越来越少见了但一旦遇到手动下载永远是最后的通行方案。5.6 SSH 密钥文件权限报错Permissions for key are too openWindows 用户把私钥文件从一个目录复制到另一个目录后经常会在连接时报 Permissions for key.pem are too open。原因是私钥文件继承的 ACL 权限对任何用户都可读OpenSSH 会很较真地拒绝加载。Windows 修复方式稍微繁琐右键私钥文件 - 属性 - 安全 - 高级 - 禁用继承 - 将所有权限授予当前用户确保没有其他用户和组。这个操作经常被忽略但只要是密钥认证报 too open几乎都是权限问题。6. 进阶技巧跳板机连接、后台开发和日常习惯这部分算是我个人经验的延伸。项目大了之后你可能会遇到“只能通过跳板机访问目标服务器”的场景也会有需要同时在本地和远程切换工作区的需求这些都值得单独写一笔。6.1 ProxyJump 配置通过跳板机连接内网服务器有些服务器在内网本地无法直接访问只能先登录一台公网跳板机再从跳板机跳到目标机器。Remote-SSH 的配置里直接用 ProxyJump 字段解决不需要额外装任何工具Host bastion HostName 1.2.3.4 User admin IdentityFile ~/.ssh/id_ed25519 Host internal-server HostName 172.16.0.5 User ubuntu ProxyJump bastion这样你在 VS Code 里直接连 internal-serverSSH 会自动先连 bastion 再跳到内网目标整个链路对编辑器透明。对于需要两台服务器私钥都存在本机的情况也完全适用。跳板机上不需要你的私钥安全性更好密钥始终只在本地。6.2 让 VS Code 记住更多连接习惯一处配置经常影响长期体验把常用的远程仓库目录做成“任务”或“工作区”。VS Code 支持把远程主机和目录保存到工作区文件里下次直接双击工作区就能恢复现场终端、打开的编辑器标签、断点状态都会回来。对于同时要管理多台服务器的场景我习惯在 remote explorer 里给每台主机加标签和描述这样不会出现“看着 IP 想不起来是哪个环境”的尴尬。配置文件的注释里也可以把服务器的用途、用户、登录方式写清楚方便同事接手。6.3 远程开发下备份和同步代码的做法虽然 Remote-SSH 是把代码留在服务器上但这不代表代码不需要备份。我个人会定期用 rsync 把服务器代码同步到本地磁盘rsync -avz --progress ubuntumy-dev-server:/home/ubuntu/project/ /本地/备份路径/这个命令复制目录结构、保留权限和时间戳增量备份速度快。反向也可以把本地代码推到服务器。对于没有配置 Git 的项目这个方法能救命就算配了 Git多做一份本地备份也花不了多少时间。7. 最后再分享一点我自己的实际体会Remote-SSH 用久了以后你会慢慢发现它真正改变的不是“编辑代码的方式”而是“你对环境的理解”。以前我在本地写代码、在服务器跑任务两边总要不断校对环境版本。现在所有事情都发生在同一台机器上出问题的概率直线下降排查问题也更聚焦。如果要从零开始给身边人推荐这套流程我的顺序是先配好免密登录再装 Remote-SSH 扩展然后连一次远程主机把 Python 或 Node 扩展装到远程端最后用 tmux 跑长时间任务。这四步搞定远程开发的基本盘就稳了。还有一些小习惯值得养成连接前先看服务器磁盘剩余空间df -h免得 run 到一半才发现磁盘满了长时间挂机时用 ServerAliveInterval 保活代码里出现中文乱码时统一用 UTF-8 编码并检查服务器 locale 设置。这些细节看似不起眼恰恰是实际使用时最影响心情的地方。真要说 Remote-SSH 有什么“缺点”我觉得是第一次配置 server 组件时的网络依赖以及部分扩展在远程端需要额外安装这两点。但和它带来的便利相比这些都是小问题。如果你正在为“代码在服务器、编辑器在本机”这件事来回搬运文件我建议你花一个小时把 Remote-SSH 配好后面省下来的时间绝对值得。