首页
/
行业洞察
/
正文
INDUSTRY INSIGHT · 深度
VSCode Remote SSH配跳板机连接内网服务器与Docker容器实践
📅 2026/10/17 21:57:24
✍️ 爱科研究院
👁 阅读 3,247
本地开发机连公司内网服务器最大的痛点不是 SSH 本身而是“中间还有一层跳板机”。生产环境、测试环境通常都藏在某个内网段里本地电脑直连不上必须先连一台有公网入口、同时能访问内网的那台机器再从那台机器跳到目标服务器。以前这套流程只能在终端里敲命令凑合现在 VSCode Remote SSH 可以把这条链路完整搬进编辑器连远程服务器、甚至远程服务器里的 Docker 容器都能像写本地代码一样开发和调试。这篇就是我实际配置 VSCode Remote SSH 借助跳板机连接远程服务器及远端容器的完整记录适合所有被内网服务器折腾过的后端、运维以及需要在容器里做开发的同学参考。1. 先理清楚为什么本地机连不上一台“需要跳板机”的服务器1.1 跳板机场景的现状很多人第一次遇到跳板机时会有个疑问远程服务器不是有 IP 吗凭什么本地连不上原因很简单目标服务器通常只有内网 IP比如10.10.x.x而公司网络的边界上只有跳板机有公网 IP 或能和本地电脑建立可达连接。安全策略要求所有对内网服务器的访问都必须经过跳板机这叫“统一入口、统一审计”。所以真实网络拓扑往往是这样本地开发机可以访问跳板机跳板机可以访问目标服务器所在的内网网段本地开发机不能直接访问目标服务器这种场景下你要从本地登录目标服务器必须形成“本地 - 跳板机 - 目标机”的两级链路。终端里可以连续执行两次ssh但 VSCode Remote SSH 需要的是一个可直接连接的“最终主机”这就要求我们把这两段链路在 SSH 层面“拼接”起来。1.2 SSH 的“两级跳”到底发生了什么先拆解一下 SSH 的跳转过程。你执行ssh usertarget时SSH 客户端会向 target 的 22 端口发起连接然后协商认证。如果 target 不在本地网络里连接就失败了。加了一台跳板机后实际上你希望的是本地先连上跳板机然后由跳板机替你向 target 发起连接并把两端的数据流进行中转。这个“替你连”的动作就是 OpenSSH 的-J参数和ProxyJump配置在做的事。它相当于客户端告诉跳板机帮我建立一个到 target 的通道然后我直接通过这条通道完成 SSH 认证和会话。对目标服务器来说连接的来源是跳板机所以只要跳板机有权限进入内网链路就走得通。1.3 为什么 VSCode Remote SSH 也能走通这条链路VSCode Remote SSH 本质上是本地 VSCode 通过 SSH 在远程服务器上安装并启动一个vscode-server服务然后本地窗口和远程服务之间建立通信。它并不关心你的 SSH 连接有几个中间节点只要本地能通过 SSH 到达最终主机它就能正常工作。所以你完全可以在~/.ssh/config里把“经过跳板机跳转”这一层配置好让 VSCode 直接选择目标机的别名发起连接剩下的跳转逻辑由 SSH 客户端自行处理。2. SSH 跳板机制原理与两种配置写法2.1 ProxyJump最省事的写法OpenSSH 从 7.3 开始支持ProxyJump在ssh_config里的写法非常简单# ~/.ssh/config Host jump HostName 1.2.3.4 User ops Port 22 IdentityFile ~/.ssh/id_ed25519 Host prod-web HostName 10.10.10.10 User root ProxyJump jump IdentityFile ~/.ssh/id_ed25519这里Host prod-web是目标机的别名HostName是内网 IPProxyJump jump声明了要经过的跳板机。配置好之后终端里执行ssh prod-web或者 VSCode Remote SSH 里选择prod-web会自动先连 jump再连 10.10.10.10整个过程和直连一样顺滑。这种写法的好处是逻辑清晰语义直白而且支持多级跳转比如ProxyJump jump1,jump2会依次经过这两台机器。多数现代 Linux 发行版和 macOS 自带的 OpenSSH 都支持这个参数Windows 上只要用的是新版 OpenSSH 也没有问题。2.2 ProxyCommand老写法但仍有存在价值如果你的跳板机或者本地 OpenSSH 版本比较老不支持ProxyJump可以退而求其次使用ProxyCommandHost prod-web HostName 10.10.10.10 User root ProxyCommand ssh -W %h:%p jump-W表示让跳板机进入“转发模式”把标准输入输出和最终主机的 22 端口直接打通。%h和%p是 SSH 配置里的内置变量会替换成目标机的 HostName 和端口。这种写法是ProxyJump的底层实现方式如果哪天ProxyJump因为 OpenSSH 版本问题不可用可以把配置临时改成这种形式。另外还有一种比较老的写法叫nc代理转发例如ProxyCommand ssh jump nc %h %p。这种方式依赖跳板机上装了netcat而且每次都会多启动一个进程实际用起来远没有-W干净我不建议新项目再踩这个坑。2.3 密钥、Agent 转发和“二级密钥”的处理思路使用跳板机时密钥管理容易让人绕晕。这里有一个关键点目标机的认证发生在第二条链路上本地 SSH 客户端会用配置里针对目标机指定的IdentityFile做认证而这把私钥的验证过程是通过跳板机转发过去的。如果你在跳板机上还保存了一份专门用于目标机的私钥也可以实现在跳板机上手动登录目标机。但从 VSCode Remote SSH 的角度我更推荐把目标机的私钥放在本地然后用ssh-agent配合配置完成认证。具体做法是将相关私钥加入本地比如执行ssh-add ~/.ssh/id_ed25519。在~/.ssh/config中开启 Agent 转发ForwardAgent yes。跳板机上如果有限制需要允许转发一般是跳板机 SSH 服务端配置/etc/ssh/sshd_config里的AllowAgentForwarding yes。注意如果跳板机上的 OpenSSH 服务端把AllowTcpForwarding或AllowAgentForwarding关掉了ProxyJump依然可能工作因为它建立的是 TCP 转发通道但 agent 转发可能会失败这点排查时要区分清楚。3. 实操本地机 - 跳板机 - 远程服务器的完整配置3.1 准备阶段确认三端 OpenSSH 版本与网络可达性在动手改配置之前先确认三件事。第一本地机器上的 OpenSSH 客户端版本执行ssh -V能看到版本号即可只要能显示版本基本上都支持ProxyJump。第二确认本地能访问跳板机执行ssh ops跳板机IP能顺利登录再继续。第三确认跳板机到目标服务器的网络连通性可以登录跳板机后执行ping 10.10.10.10或ssh root10.10.10.10如果跳板机到目标机也畅通那么链路可行剩下的事情就是写配置。3.2 编辑~/.ssh/config一套配置同时解决 VSCode 与终端我实际工作中的习惯是给每个环境都建一个别名比如测试环境叫test-api生产环境叫prod-web这样后续在 VSCode 里选主机时非常直观。完整的配置示例# 跳板机 Host bastion HostName 192.168.30.5 User ops Port 22 IdentityFile ~/.ssh/id_ed25519 ForwardAgent yes ServerAliveInterval 30 ServerAliveCountMax 3 # 目标服务器 1 Host prod-web HostName 10.10.10.10 User root ProxyJump bastion IdentityFile ~/.ssh/id_ed25519 ServerAliveInterval 30 # 目标服务器 2 Host prod-db HostName 10.10.10.11 User deploy ProxyJump bastion IdentityFile ~/.ssh/id_ed25519ServerAliveInterval 30的作用是每 30 秒发送一个保活包防止长时间没有操作时连接被网络设备强制断开。这个参数在跳板机场景下尤其重要因为链路多了一段任何一个中间节点把空闲连接回收你都会突然发现 VSCode 卡住不动。另外如果觉得每次连接都要确认主机指纹很烦可以在全局配置里取消严格校验Host * StrictHostKeyChecking no UserKnownHostsFile /dev/null不过这个全局配置只建议用于内网测试环境生产环境最好保留StrictHostKeyChecking ask避免中间人风险。配置写完后先用终端验证一下ssh prod-web如果顺利进入目标机说明链路配置正确。VSCode 里再安装 Remote-SSH 扩展命令面板里执行Remote-SSH: Connect to Host选择prod-web即可。3.3 落地验证从 VSCode 发起连接并排障第一次在 VSCode 里连接时它会在远程主机上自动下载对应版本的vscode-server这个过程受网络环境影响较大。如果远程服务器无法访问外网就会卡在“Setting up SSH Host”界面。遇到这个问题有几个处理顺序先确认终端的ssh prod-web能不能正常登录。再确认远程主机能否访问更新服务器手动执行curl -I https://update.code.visualstudio.com测试。如果远程主机不能访问外网但本地可以可以给 VSCode 设置remote.SSH.allowLocalServerDownload为 true让本地从官网下载后通过 SFTP 推送到远程。如果远程主机能访问外网但仍然卡住多半是网络用户代理问题需要在 VSCode 设置里配置http.proxy和https.proxy。注意vscode-server 版本和本地 VSCode 版本强相关如果本地自动更新过 VSCode而远程主机上的 vscode-server 没有随之更新VSCode 通常会重新下载安装。这个过程偶尔会留下旧版本目录遇到异常时可以rm -rf ~/.vscode-server后重连。一旦 VSCode 进入远程窗口左下角会显示“SSH: prod-web”此时你可以直接打开远程服务器上的文件夹插件也会以远程模式运行。终端面板会自动打开到目标机的 shell调试、代码跳转、端口转发都与本地开发几乎无差别。4. 进阶把 VSCode 连到远程服务器里的 Docker 容器4.1 方案A容器自带 SSH通过宿主端口映射再连容器如果你想在目标服务器的 Docker 容器里开发最简单的方案是让容器运行一个 SSHD 服务并把宿主机的某个端口映射到容器的 22 端口。启动容器时可以这样docker run -d --name dev-container -p 2222:22 my-dev-image以前面的跳板配置为基础你可以在~/.ssh/config中新增一个主机条目把最终 HostName 指向宿主机端口指向映射端口Host prod-container HostName 10.10.10.10 User dev Port 2222 ProxyJump bastion IdentityFile ~/.ssh/id_ed25519_dev这样 VSCode 选择prod-container时会先经过跳板机再连到宿主机的 2222 端口最终进入容器里的 SSHD。这个方案思路简单稳定性也不错但要求容器镜像里必须安装并启动openssh-server同时设置好密码或密钥认证。为了让 Key 认证可用构建镜像时要把公钥写入容器的~/.ssh/authorized_keys文件。4.2 方案BSSH 端口转发把远端容器端口映射到本地如果不想在容器里装 SSHD另一个思路是做端口转发把远程宿主机上已经映射出来的端口比如 2222再映射到本地某个端口然后 VSCode 直接连localhost。这样跳板链路在外层完成VSCode 的配置和普通直连没有区别。操作时先执行ssh -N -L 2222:10.10.10.10:2222 bastion这个命令的含义是通过跳板机bastion建立一条隧道把本地 2222 端口转发到10.10.10.10的 2222 端口。-N表示不执行远程命令只做转发。隧道建立后在 VSCode 里连接Host local-container HostName 127.0.0.1 User dev Port 2222这个方案的好处是不需要每次都在~/.ssh/config里写复杂的 ProxyJump缺点是你需要保持那条ssh -N隧道不中断。实际使用中我更喜欢把它和ControlMaster结合起来比如在~/.ssh/config里配置Host bastion ControlMaster auto ControlPath ~/.ssh/ctl-%r%h:%p这样第一次连接会建立主连接后续的转发、连接都会复用不需要反复输入密码速度也快很多。4.3 方案CRemote-SSH Remote Containers 实现“附加到容器”如果你已经通过 VSCode Remote SSH 连接到了宿主机那么还有一种更轻量的方式安装 Remote Containers 扩展直接“附加”到正在运行的容器里。具体操作是用 Remote-SSH 连接目标服务器宿主机。在扩展市场安装“Remote Containers”如果远程环境里没有需要先装到远程主机。命令面板输入Remote-Containers: Attach to Running Container...。选择目标容器VSCode 会自动进入容器环境。这个方案不需要容器里有 SSHD不需要额外端口映射直接复用 Docker 的 API 连接到容器进程查看容器内文件系统、运行终端、调试代码都非常方便。它和“先在宿主机下载 vscode-server再进容器下载一份 server”的原理类似但整体体验是最接近“在容器里开发”的。需要注意远程宿主机上必须能执行 docker 命令Remote Containers 底层是通过 Docker CLI 与容器通信的如果当前用户不在 docker 用户组里需要先解决权限问题否则会报 “permission denied while trying to connect to the Docker daemon socket”。三种方案我实际都用过。如果只追求快速看代码方案C体验最好如果你需要把容器当作独立开发环境或者想让外部的 CI/终端工具也能直接连进容器方案A更通用方案B适合临时调试用完随时断开隧道不污染任何配置。5. 常见问题与排查笔记5.1 最常踩的坑vscode-server 下载卡住无论有没有跳板机VSCode Remote SSH 连远程主机时最容易卡住的地方就是 vscode-server 下载。症状是连接窗口一直显示“Setting up SSH Host”十几分钟后还是老样子。排查思路按照优先级来先登录跳板机再从跳板机登录目标机手动确认目标机到外网的连通性。很多内网服务器只开放了 80/443 端口可能无法直连 VSCode 的更新服务这种情况下把remote.SSH.allowLocalServerDownload设置为 true让本地机器代下载即可。提示跳板机场景下vscode-server 下载的是“最终目标机”上的版本如果目标机无法访问外网和跳板机有没有外网无关先明确这一点能少走很多弯路。5.2 跳板机私钥与目标机私钥如何区分我见过不少人把同一把私钥同时放到跳板机和目标机里最终导致本地 SSH 连接时拿到一堆认证失败日志。正确理解是本地到跳板机的认证使用Host bastion配置里的IdentityFile跳板机到目标机的认证使用Host prod-web配置里的IdentityFile。这两个文件最好分开生成目标机的私钥不要直接放在跳板机上否则跳板机本身就能直接登录目标机安全边界形同虚设。5.3 不打开 VSCode 时 SSHD 日志怎么看如果 SSH 连接本身失败VSCode 只会给出很模糊的报错。此时应该回到终端先执行ssh -vvv prod-web从详细输出里看认证到哪一步失败。如果跳板机转发正常但目标机拒绝密钥大概率是目标机authorized_keys文件权限或内容有问题。也可以在目标机上临时开启 sshd 调试日志sudo tail -f /var/log/auth.log重新执行一次连接看日志输出会非常直观。有个容易被忽略的点目标机的 OpenSSH 版本如果太老默认可能不加载ed25519类型的密钥确认一下服务器支持哪种密钥格式。5.4 双跳、多级跳板也能搞定有些网络架构不止一台跳板机比如本地先到 DMZ 区的一台机器再到核心内网的机器最后才到目标服务器。ProxyJump支持逗号分隔多个跳板Host core-server HostName 10.20.1.5 User admin ProxyJump dmz-zone,core-zone执行连接时OpenSSH 会先连dmz-zone再通过它连core-zone最后从core-zone连目标机。配置越链越长时建议在每台跳板机的条目上也加ServerAliveInterval因为中间任何一跳掉线整条链路都会断。5.5 有没有必要上专业的跳板机系统如果团队规模小用普通服务器当跳板机完全够用。但如果涉及大量审计需求比如谁在什么时候执行了什么命令、上传下载过什么文件那么建议考虑专业堡垒机方案。这类系统通常自带 Web 入口、审计录像和命令记录并且会提供统一的 SSH 接入方式和 VSCode Remote SSH 配合时本质上只要把跳板地址换成堡垒机地址即可只是有些堡垒机会强制要求二次认证这会导致 VSCode 的首次连接多一步人工确认需要稍微设置一下认证方式。配置跳板机连接这件事归根结底就是理解“本地 - 跳板 - 目标机”这条链路并用 SSH 配置文件把链路固化下来。我在实际使用中有一个小习惯每新增一个目标服务器都在~/.ssh/config里复用同一个跳板别名并且给目标机设置一个清晰易记的名字这样 VSCode 的主机列表永远只显示业务别名不会出现一堆看不懂的 IP。如果你以后遇到“明明能连跳板却连不上目标机”的情况先别急着怪 VSCode回终端用ssh -vvv跑一遍多半能定位到密钥、转发开关或者网络策略这几个点上。
📌 标签:
工业官网
设计趋势
AI 建站
SEO
获取完整报告 →
RELATED ARTICLES
推荐阅读
2026/10/17 21:52:24
蓝桥杯智能阅读助手开发:结构感知分块与可解释推理实战
2026/10/17 21:52:24
基于AT89C51RC的电脑钥匙外围电路设计要点与避坑指南
2026/10/17 21:52:24
N4系统集成选型与Device升级包计点实战指南
2026/10/17 22:52:34
PowerPoint内嵌JS运行器:零基础JavaScript教学课件实战
2026/10/17 22:52:34
Vue3+Web3.js区块链DApp实战:从架构设计到合约部署
2026/10/17 22:52:34
H5页面实现扫码功能:Web端二维码识别实战指南
2026/10/17 22:52:34
Factsage热力学计算入门:相图、平衡模块与数据库避坑指南
2026/10/17 22:52:34
pyKT工程落地实战:从Excel数据到线上API的完整链路
2026/10/17 22:47:34
AI沟通的核心方法论:从底层原理到高效Prompt模板与避坑指南
2026/10/17 0:02:58
NetSpot 实战:用信道分析与频宽优化解决 Wi-Fi 卡顿
2026/10/17 0:02:58
C++ split() 字符串分割的五种实现与性能实测
2026/10/17 0:02:58
R语言坐标轴范围设置:从xlim/ylim到coord_cartesian的完整指南
2026/10/17 10:00:11
流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南
2026/10/17 10:16:23
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别
2026/10/17 10:16:02
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容
2026/10/17 10:15:50
我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
2026/10/16 18:46:48
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026/10/16 18:46:46
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)