vscode远程调试node服务连接丢失,90%是内网穿透链路被中间设备静默回收所致;根本原因是frp等工具不透传tcp keepalive包,需在frpc.ini和frps.ini中启用tcp_keepalive并配置heartbeat_timeout,而非仅调整ssh或vscode设置。

VSCode 远程调试 Node 服务时连接丢失,90% 不是代码或服务问题,而是内网穿透链路在空闲期被中止——本质是 TCP 连接被中间设备(frp / nat / 防火墙)静默回收,不是 VSCode 或 Node 本身掉线。
为什么内网穿透环境下 ServerAliveInterval 失效
frp、ngrok 等穿透工具通常只转发应用层数据,不透传 TCP keepalive 包。即使你在 ~/.ssh/config 里设置了 ServerAliveInterval 60,这些心跳包发不到真实服务器,只到 frp client 端就被终止,服务器完全收不到。
- 现象:SSH 命令行直连穿透后的地址能通,但 VSCode 连上几秒后就卡在 “Establishing a connection to the remote extension host”
- 验证方式:在远程服务器上运行
ss -tnp | grep :22,发现连接状态很快变成FIN_WAIT2或消失,说明连接被单向切断 - 根本原因:frp 默认不启用
tcp_keepalive,且 client 和 server 端都未配置保活探测
必须改 frp 配置,而非只调 VSCode 或 ssh
VSCode 和 SSH 层的保活对穿透链路无效,必须让 frp 主动维持隧道活跃。重点改两处:
使用一条命令部署ProbeChain Rydberg测试网代理节点。自动注册为Agent(NodeType=1),免gas,支持macOS/Linux/Windows。触发词:/r
- frp client 配置(
frpc.ini)加:tcp_keepalive = true(启用底层 TCP 心跳) - frp server 配置(
frps.ini)加:tcp_keepalive = true和heartbeat_timeout = 90(避免心跳超时误判) - 若用 frp v0.50+,还需确认
protocol = tcp(kcp 协议默认禁用 keepalive,且不稳定) - 重启 frp client 和 server 后,再试
ssh -o ConnectTimeout=10 -o ServerAliveInterval=0 user@tunneled-host—— 此时应能稳定维持连接超过 5 分钟
VSCode 调试器启动阶段额外卡顿的真正原因
Node 调试器(node --inspect)监听的端口(如 9229)需通过 frp 暴露,但 VSCode 默认尝试从本地直连该端口,失败后才 fallback 到 SSH 隧道,导致“Debug adapter process has terminated”错误。
- 解决方案:在
.vscode/launch.json中强制走 SSH 隧道,加字段:"port": 9229+"address": "localhost"+"sourceMaps": true,并确保"skipFiles": ["<node_internals>"]</node_internals> - 关键点:不要设
"address": "0.0.0.0",否则 VSCode 会绕过 SSH 直连,而穿透环境里 0.0.0.0 不可达 - 验证方式:启动调试后,在远程服务器运行
lsof -i :9229,确认只有node进程在监听,且没有其他进程抢端口
frp 日志里出现 “timeout” 但 SSH 能连,说明问题在隧道层
frp server 日志若频繁打印 timeout: read tcp …: i/o timeout,而 ssh user@host 命令始终成功,说明问题不在 SSH 层,也不在 VSCode,而在 frp 自身的连接复用策略。
- 临时缓解:在 frpc.ini 的 [common] 下加
pool_count = 5(默认为 0,即不复用连接) - 长期方案:升级 frp 到 v0.54+,启用
health_check_type = tcp并配health_check_timeout_s = 3,让 client 主动探测 server 可达性 - 注意:旧版 frp(v0.4x)对高并发调试请求支持差,容易因连接池耗尽导致 VSCode 反复重连失败
内网穿透下的远程调试,稳定性瓶颈永远在隧道层,不是编辑器或语言运行时。改 frp 配置比调 VSCode 设置有效十倍;而所有“重装插件”“清缓存”“换端口”的操作,都是在绕开真正的问题点。










