Forest
Hermes 通过 SSH 反向隧道控制 Edge 浏览器

Hermes 通过 SSH 反向隧道控制 Edge 浏览器

背景

最近在折腾 Hermes AI Agent 的浏览器自动化功能,想实现一个很酷的用法:在服务器上通过 CDP (Chrome DevTools Protocol) 远程控制我本地 Windows 电脑上的 Edge 浏览器

这个方案的好处是:

  • 不需要在服务器上安装浏览器(省内存)

  • 直接使用本地已有的浏览器会话(Cookie、登录状态都保留)

  • 可以让 AI 控制”真实”的浏览器环境,和人工操作一致

  • 预期架构

    服务器 (Hermes)
         ↓ (SSH 连接)
    Windows 本机
         ↓ (CDP 协议)
    Edge 浏览器 (本地运行)

踩坑全过程

第一步:配置 SSH 反向隧道

一开始的命令很简单:

ssh -v -L 9222:localhost:9222 root@服务器IP

看起来成功了,SSH 日志显示端口转发建立:

debug1: remote forward success for: listen 9222, connect localhost:9222

服务器端也能看到端口在监听:

tcp        0      0 127.0.0.1:9222          0.0.0.0:*               LISTEN

第二步:启动 Edge 远程调试

在 Windows 上用这个命令启动 Edge:

msedge.exe --remote-debugging-port=9222 --remote-debugging-address=0.0.0.0 --user-data-dir="C:\edge_debug_profile"

记得把 --user-data-dir="C:\edge_debug_profile" 参数加上,不然无法正常启动 Edge 的远程调试并监听端口。
本地浏览器访问 http://localhost:9222/json/version 也能看到正常的 CDP 响应。

第三步:问题出现了!

但是在服务器上测试连接:

curl http://127.0.0.1:9222/json/version
# 结果:Empty reply from server

TCP 连接能建立,但是 HTTP 请求没有响应!

第五步:关键发现 — SSH 日志的秘密

仔细看 SSH 调试日志,发现了关键线索:

debug1: connect_next: host localhost ([::1]:9222) in progress

问题找到了!

SSH 把 localhost 默认解析成了 IPv6 地址 [::1],但是我的 Edge 浏览器只监听了 IPv4 的 127.0.0.1

虽然日志显示 “connected”,但紧接着连接就被释放了(channel 1: free),因为 IPv6 的 9222 端口上根本没有服务在监听。

解决方案:强制 SSH 用 IPv4 地址(推荐,最简单)✅

建立隧道时明确使用 127.0.0.1 而不是 localhost

ssh -v -R 9222:127.0.0.1:9222 root@服务器IP

这样 SSH 就会用 IPv4 连接 Edge,而不是 IPv6。

完整使用步骤

1. Windows 端准备

关闭所有 Edge 窗口,用命令启动:

msedge.exe --remote-debugging-port=9222 --user-data-dir="C:\edge_debug_profile"

本地验证:浏览器打开 http://localhost:9222/json/version

2. 建立 SSH 反向隧道(关键!)

.ssh/config 配置:
给服务器起个别名 hermes-server,登录时自动把服务器的 9222、8080 端口转发到本地电脑,并且保持连接永远不断线

Host hermes-server 
	HostName 123.123.123.123 
	User root 
	Port 22 
	RemoteForward 9222 127.0.0.1:9222 远程端口转发到本地
	LocalForward  8642 127.0.0.1:8642 本地端口转发到远程
	ServerAliveInterval 30 防止网络空闲时SSH 自动断开:每 30 秒,本地电脑给服务器发一个心跳包
	ServerAliveCountMax 10 断线重连机制:如果连续**10 次心跳包都没收到服务器回应,就认为连接断开,SSH 会自动尝试重连;30 秒 × 10 次 = 5 分钟没响应就自动重连

3. 服务器端配置 Hermes

编辑 ~/.hermes/config.yaml

browser:
  cdp_url: 'http://127.0.0.1:9222'

测试正常~~~

踩坑回顾

原因解决方案
SSH 隧道连接但无响应localhost 被解析为 IPv6,Edge 只监听 IPv4127.0.0.1 代替 localhost
Edge 启动参数默认只绑定环回接口需要 --remote-debugging-address --user-data-dir参数
Windows 防火墙可能拦截环回接口连接临时关闭防火墙测试
多个 Edge 进程必须关闭所有 Edge 才能用新参数启动任务管理器结束所有 msedge.exe

扩展用法

1. 多浏览器隔离

用不同的 --user-data-dir 和端口,可以同时运行多个独立的浏览器实例。

2. 配合 Puppeteer/Playwright

这个方案也适用于 Puppeteer、Playwright 等自动化框架:

const browser = await puppeteer.connect({
  browserWSEndpoint: 'ws://服务器IP:9222/devtools/browser/...'
});

结语

这个问题卡了我好几个小时,一开始一直在服务器端找原因,没想到最后是一个看似不起眼的 IPv4/IPv6 解析问题。

localhost 这个”简单”的域名背后,其实隐藏着操作系统的双栈解析逻辑。在做端口转发、网络调试时,优先用具体的 IP 地址而不是主机名,往往能避免很多奇怪的问题。

希望这篇文章能帮到同样在折腾 CDP 远程控制的朋友们!


最后提醒: 不要把 CDP 端口暴露在公网,这个接口有完整的浏览器控制权限,非常危险!一定要通过 SSH 隧道或 VPN 来访问。