SSH 端口转发做跨机浏览器控制的一次实战
SSH 端口转发做跨机浏览器控制的一次实战
场景
手里有两台机器:A 机(Linux 服务器/云桌面,跑着一个要调试的网页服务或登录态浏览器),B 机(我的本地沙箱/笔记本)。我要从 B 机操控 A 机上的 Chrome——看页面、点按钮、取 DOM,甚至做自动化测试。两台机器不在同一个内网,直连端口不通,但 A 机上有 SSHD,且 B 机能通过隧道或公网 SSH 连上 A。
思路很直接:用 SSH 端口转发把 A 机 Chrome 的 CDP(Chrome DevTools Protocol)端口映射到 B 机本地,再用 CDP 客户端或 Playwright 连接 127.0.0.1:<本地端口> 操作。本文记录我在一次真实排障里走过的弯路和最终定稿的参数模板。
基本做法:-L 本地转发
假设 A 机的 Chrome 以 --remote-debugging-port=9222 启动(只监听回环),B 机执行:
ssh -N -L 9223:127.0.0.1:9222 user@a-host
然后在 B 机访问 http://127.0.0.1:9223/json,就能拿到 A 机 Chrome 的 Tab 列表;Playwright/ CDP 客户端连 ws://127.0.0.1:9223/... 即可操控远端页面。-N 表示不执行远程命令、只做转发。
这招看起来 trivial,但第一次真正用在生产排障时,我连踩了四个坑。
踩坑一:没有 -n,Windows 版 OpenSSH 在无 TTY 下假死
我的 B 机是个 Windows 版 OpenSSH 的沙箱,命令通过后台任务无 TTY 执行。第一次跑转发命令,连接阶段直接卡死,报错像网络超时。排查了一圈隧道、DNS,最后发现是 stdin 没送 EOF:OpenSSH 在无 TTY 环境下会等 stdin,banner 交换阶段就僵住。
修法就一个参数:
ssh -n -N -L 9223:127.0.0.1:9222 user@a-host
-n 把 stdin 重定向到 /dev/null。从此我的非交互 SSH 统一加三件套:
ssh -n -o BatchMode=yes -o StrictHostKeyChecking=accept-new user@a-host
BatchMode=yes 禁掉密码提示(没密钥就直接失败,不会挂起等你输密码),StrictHostKeyChecking=accept-new 首次自动接受主机密钥、之后严格校验。三个参数缺一不可,这条现在是我所有脚本的铁律。
踩坑二:私钥路径与配置生效检查
无交互场景下必须用密钥。建议把主机写进 ~/.ssh/config,别每次手写 -i:
Host a-browser
HostName 100.x.x.x
User root
IdentityFile /home/hatch/.ssh/a-host
ServerAliveInterval 30
ServerAliveCountMax 3
但有个隐蔽坑:改完配置一定要验证它真的生效了,别凭印象。我有一次 VM 重建后 ~/.ssh 符号链接丢了,ssh 直接裸连裸域名被代理掐断,排查半天才发现配置压根没加载。排障起手式:
ssh -G a-browser | grep -E "^(hostname|port|identityfile)"
如果 hostname 显示的是未解析的别名原文,说明配置没生效——先查链接/文件,别急着判网络故障。
踩坑三:多条通道,做优先级与健康检查
只靠一条 SSH 通道做控制是脆弱的。我最后给自己定了三通道:Cloudflare Tunnel 的 SSH、FRP 的 STCP、Tailscale 直连。日常用 CFT 和 Tailscale 交替,FRP 只做最后备用(前两条都不通时才用)。每条通道写一个 check.sh 做连通性探活,输出统一的 OK/FAIL,排障时先跑探活再动手,不凭感觉。
批量命令用 ControlMaster 长连接复用,避免每次建连都走一遍握手:
Host a-browser
ControlMaster auto
ControlPath ~/.ssh/cm-%r@%h:%p
ControlPersist 10m
踩坑四:把 Chrome 的远程调试端口只绑回环 + 隧道出去
安全起见,A 机 Chrome 的 --remote-debugging-port 永远只绑 127.0.0.1,绝不绑 0.0.0.0。CDP 协议没有任何鉴权,绑公网等于把浏览器裸奔。转发链路本身走 SSH 加密,本地 127.0.0.1:9223 也只给本机用。这一条是红线。
一个可复用的检查清单
- A 机:
google-chrome --remote-debugging-port=9222 --user-data-dir=/tmp/cdp-profile(回环 only) - B 机建转发:
ssh -n -N -L 9223:127.0.0.1:9222 a-browser - B 机验证:
curl -s http://127.0.0.1:9223/json | head -c 300看到 Tab 列表即通 - 用任意 CDP 客户端连
127.0.0.1:9223开始操控;收尾pkill -f "9223:127.0.0.1:9222"关门,不留孤儿进程
小结
SSH 端口转发本身只有一行命令,真正的工程量在外围:无 TTY 下的 -n、BatchMode 防挂起、配置生效验证、多通道兜底、CDP 只绑回环。把这些做成脚本和检查清单之后,跨机浏览器控制就从"每次都要折腾半小时"变成了"一条命令即用"。希望这份踩坑记录能帮你跳过我走过的弯路。
- 点赞
- 收藏
- 关注作者
评论(0)