npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@hugehard/ech

v0.1.3

Published

Local HTTPS inspector and proxy with Encrypted Client Hello support

Readme

ECH

一个支持 TLS Encrypted Client Hello(ECH)的本地 HTTP/HTTPS 代理与调试工具。代理服务和 Web 管理界面默认共用 127.0.0.1:8080

典型的浏览器链路如下:

Chrome → ZeroOmega → http://127.0.0.1:8080 → ECH 上游链路 → 目标网站

ZeroOmega 只负责把 Chrome 流量转发到本地代理,ECH 握手、DNS HTTPS(TYPE65)查询和上游连接由本包的原生程序完成。

它不只是 ECH 客户端,还可以作为本地开发代理、HTTPS 抓包工具和轻量 Mock 服务使用:

  • 把线上 JS、CSS 或接口地址改写到本地开发服务器。
  • host:// 把域名连接到指定 IP,同时保留原域名、TLS SNI 和证书校验。
  • 按域名选择直连、系统代理或全局配置的上游代理。
  • 修改请求 Header、响应 Header,模拟状态码和响应内容。
  • 模拟网络延迟,或主动阻断指定请求。
  • 查看请求与响应详情、搜索请求、重放请求、复制 curl。
  • 用多个可开关的规则集管理开发、测试和故障模拟规则。

支持的平台

  • macOS Apple Silicon(arm64)
  • Windows x64
  • Linux x86_64
  • Node.js 18 或更高版本

macOS Intel 暂未包含原生二进制。本文主要说明 Chrome 在 macOS 和 Windows 上的使用方法。

五分钟安装

在终端或 PowerShell 中依次执行:

npm install -g @hugehard/ech
ech start
ech install-ca
ech extension

然后完成两项浏览器操作:

  1. 在 Chrome 中安装命令准备好的离线 ZeroOmega 插件。
  2. 在 ZeroOmega 中导入 ECH 配置并选择 ECH 情景模式。

完成后可以运行:

ech open

浏览器会打开本地管理界面 http://127.0.0.1:8080

第一步:安装 npm 包

macOS

打开“终端”,执行:

npm install -g @hugehard/ech
ech help

Windows

打开 PowerShell,执行:

npm install -g @hugehard/ech
ech help

如果能够看到 ech 的命令列表,说明安装成功。如果提示 ech: command not found 或“无法将 ech 识别为命令”,请关闭并重新打开终端;仍然无效时,检查 npm 全局 bin 目录是否已经加入 PATH

升级已有安装:

npm install -g @hugehard/ech@latest
ech restart

升级不会删除 ~/.ech-inspector/ 中已有的配置、规则和本地 CA。

第二步:启动代理并生成本地 CA

首次启动:

ech start

启动成功会显示类似内容:

ECH Inspector started (pid 12345).
Proxy + UI: http://127.0.0.1:8080

确认运行状态:

ech status

首次启动会在用户目录创建:

~/.ech-inspector/config.json
~/.ech-inspector/rules.txt
~/.ech-inspector/ca.pem
~/.ech-inspector/ca-key.pem
~/.ech-inspector/inspector.log

Windows 中的默认位置为:

%USERPROFILE%\.ech-inspector\

ca.pem 是需要加入系统信任库的本地 CA 证书。ca-key.pem 是本地 CA 私钥,不能复制、上传或分享;拿到该私钥的人可以伪造本机代理签发的证书。

第三步:安装并信任证书

HTTPS 流量经过本地代理时,代理需要使用 ECH Inspector Local CA 为目标域名动态签发证书。如果系统没有信任这张 CA,Chrome 会显示 NET::ERR_CERT_AUTHORITY_INVALID 等证书错误。

必须先运行一次 ech start 生成证书,再运行:

ech install-ca

macOS 自动安装

ech start
ech install-ca

该命令会把 ~/.ech-inspector/ca.pem 加入当前用户的 login keychain,并设置为受信任根证书。macOS 可能要求输入当前账户密码或确认钥匙串操作。

安装后请使用 Command + Q 完全退出 Chrome,再重新打开。只关闭 Chrome 窗口不等于退出程序。

可以用下面的命令检查证书是否存在:

security find-certificate -c "ECH Inspector Local CA" "$HOME/Library/Keychains/login.keychain-db"

macOS 手动安装

如果 ech install-ca 失败:

  1. 打开“钥匙串访问”。
  2. 选择左侧的“登录”钥匙串。
  3. 选择菜单“文件 → 导入项目”。
  4. 导入 ~/.ech-inspector/ca.pem
  5. 搜索 ECH Inspector Local CA 并双击证书。
  6. 展开“信任”,把“使用此证书时”改为“始终信任”。
  7. 关闭窗口并按系统提示确认。
  8. 使用 Command + Q 完全退出并重启 Chrome。

在 Finder 中打开证书目录:

open "$HOME/.ech-inspector"

Windows 自动安装

在普通 PowerShell 中执行即可,不需要写入计算机级证书库:

ech start
ech install-ca

该命令等价于把证书加入“当前用户 → 受信任的根证书颁发机构”:

certutil.exe -user -addstore Root "$env:USERPROFILE\.ech-inspector\ca.pem"

如果 Windows 显示安全警告,请核对证书名称为 ECH Inspector Local CA 后确认。安装完成后,完全退出所有 Chrome 窗口和后台进程,再重新打开 Chrome。

可以检查证书是否已安装:

certutil.exe -user -store Root "ECH Inspector Local CA"

Windows 手动安装

如果自动命令失败:

  1. Win + R,输入 certmgr.msc 并回车。
  2. 展开“受信任的根证书颁发机构 → 证书”。
  3. 右键“证书”,选择“所有任务 → 导入”。
  4. 选择 %USERPROFILE%\.ech-inspector\ca.pem;看不到文件时将文件类型切换为“所有文件”。
  5. 选择“将所有的证书都放入下列存储”,目标选择“受信任的根证书颁发机构”。
  6. 完成导入,并确认能看到 ECH Inspector Local CA
  7. 完全退出并重启 Chrome。

证书安装常见问题

  • 提示 CA does not exist:先执行 ech start,确认启动成功后再执行 ech install-ca
  • 仍显示证书不受信任:确认安装的是 ca.pem,不是 ca-key.pem,然后完全退出并重启 Chrome。
  • 重新生成过 CA:旧 CA 和新 CA 不相同,需要重新执行 ech install-ca
  • 使用自定义数据目录:证书位于 $ECH_INSPECTOR_DATA_DIR/ca.pem,不再是默认路径。
  • 某些应用使用自己的证书库:需要把 ca.pem 单独导入该应用;系统已信任不代表所有应用都会自动信任。

第四步:离线安装 Chrome 插件

最终用户不需要访问 Chrome Web Store。运行:

ech extension

命令会完成以下操作:

  • 将官方签名的 ZeroOmega v3.5.0 CRX 复制到用户数据目录。
  • 准备一个“加载已解压的扩展程序”兜底目录。
  • 根据当前 config.json 生成 ZeroOmegaOptions-ECH.bak
  • 打开 chrome://extensions/
  • 在 macOS Finder 或 Windows 资源管理器中定位 CRX 文件。

扩展 ID 为:

pfnededegaaopdmhkdmcofjmoldfiped

默认离线文件位置如下。

macOS:

~/.ech-inspector/extension/zeroomega-3.5.0.crx
~/.ech-inspector/extension/zeroomega-3.5.0-unpacked/
~/.ech-inspector/extension/ZeroOmegaOptions-ECH.bak

Windows:

%USERPROFILE%\.ech-inspector\extension\zeroomega-3.5.0.crx
%USERPROFILE%\.ech-inspector\extension\zeroomega-3.5.0-unpacked\
%USERPROFILE%\.ech-inspector\extension\ZeroOmegaOptions-ECH.bak

需要重新查看这些路径时运行:

ech extension --path

方法 A:拖拽 CRX

  1. 在 Chrome 地址栏输入 chrome://extensions/
  2. 打开页面右上角的“开发者模式”。
  3. 找到 zeroomega-3.5.0.crx
  4. 将 CRX 文件拖到扩展程序页面中间。
  5. Chrome 弹出确认窗口后,点击“添加扩展程序”。
  6. 打开扩展详情,核对 ID 为 pfnededegaaopdmhkdmcofjmoldfiped

不同 Chrome 版本对离线 CRX 的限制不同。如果拖拽成功,可以跳过下一节;如果提示只能从 Chrome Web Store 安装、扩展无效或直接拒绝拖入,请使用方法 B。

方法 B:加载已解压的扩展程序

  1. 保持 chrome://extensions/ 的“开发者模式”处于开启状态。
  2. 点击“加载已解压的扩展程序”。
  3. 选择 zeroomega-3.5.0-unpacked 目录本身,不要选择它的上一级 extension 目录。
  4. 确认扩展列表出现 Proxy SwitchyOmega 3 (ZeroOmega)
  5. 核对扩展 ID 为 pfnededegaaopdmhkdmcofjmoldfiped

使用已解压方式后,不要删除或移动该目录,否则 Chrome 无法继续加载插件。npm 包升级后可以再次运行 ech extension 更新离线文件,然后在 chrome://extensions/ 点击插件卡片上的刷新按钮。

固定插件图标

  1. 点击 Chrome 工具栏右上角的拼图图标。
  2. 找到 Proxy SwitchyOmega 3 (ZeroOmega)
  3. 点击旁边的固定图标,让它常驻工具栏。

第五步:配置 ZeroOmega

本地代理类型必须选择 HTTP,不要选择 SOCKS。HTTPS 网站会通过 HTTP 代理的 CONNECT 通道工作。

新用户:导入自动生成的配置

如果这是新安装的 ZeroOmega,没有需要保留的旧配置,推荐使用自动生成的备份:

ech extension options

该命令会打开 ZeroOmega 选项页,并在 Finder/资源管理器中定位 ZeroOmegaOptions-ECH.bak

在 ZeroOmega 中:

  1. 点击左侧“导入/导出”。
  2. 找到“选项”。
  3. 点击“从备份文件恢复”。
  4. 选择 ZeroOmegaOptions-ECH.bak
  5. 看到“导入选项成功”后,点击工具栏中的 ZeroOmega 图标。
  6. 选择 ECH 情景模式。

备份会根据当前 ECH 配置生成,默认内容是:

情景模式:ECH
协议:HTTP
服务器:127.0.0.1
端口:8080
快速切换:ECH / [直接连接]

注意:从备份恢复会替换 ZeroOmega 现有的全部情景模式和设置。已经在使用 ZeroOmega 的用户不要导入,应该手动添加配置。

已有用户:手动新建 ECH 情景模式

  1. 点击 ZeroOmega 图标,进入“选项”。
  2. 点击左侧“新建情景模式”。
  3. 情景模式名称填写 ECH
  4. 类型选择“代理服务器”。
  5. 点击“创建”。
  6. 协议选择 HTTP
  7. 服务器填写 127.0.0.1
  8. 端口填写 8080
  9. 点击左侧“应用选项”保存。
  10. 点击工具栏中的 ZeroOmega 图标,选择 ECH

如果修改过 proxyHostproxyPort,请以 ech status 显示的地址为准,不要照抄默认端口。

第六步:验证是否正常

1. 检查本地服务

ech status

正常结果应包含:

ECH Inspector is running
Proxy + UI: http://127.0.0.1:8080

2. 检查 ZeroOmega

点击工具栏中的 ZeroOmega 图标,确认当前选中的是 ECH,而不是 [直接连接][系统代理]

3. 打开管理界面

ech open

也可以直接访问:

http://127.0.0.1:8080

4. 发起测试请求

在 Chrome 中打开需要经过本地代理的网站,然后回到管理界面的 Network 页面查看请求。只要请求出现,并且 Chrome 没有证书告警,说明插件、代理和 CA 信任链已经接通。

需要实时看错误日志时运行:

ech logs -f

日常使用

开始使用:

ech start

然后在 ZeroOmega 中选择 ECH

暂时停用代理时,先在 ZeroOmega 中切换到 [直接连接],再执行:

ech stop

如果直接停止本地服务但 ZeroOmega 仍选中 ECH,Chrome 会因为无法连接 127.0.0.1:8080 而打不开网页。

完整功能介绍

1. Web 管理界面和请求记录

运行:

ech open

管理界面与代理共用 http://127.0.0.1:8080,包括两个主要页面。

Network 页面

Network 页面用于确认请求实际走了哪条链路,以及检查请求和响应内容:

  • 按 URL、请求方法或错误信息搜索。
  • 查看状态码、耗时、上游类型和完整 URL。
  • 查看请求 Header、请求 Body、响应 Header、响应 Body。
  • 查看请求使用的是 directrewriteechech-auto 或回退链路。
  • “重放”会使用内存记录中的请求方法、Body 和原始 Header 再发起一次请求。
  • “复制 curl”会生成可在终端复现请求的命令;文本 Body 会写入命令,二进制 Body 不会直接写入。
  • “清空”只清除内存中的请求记录,不会删除规则、配置或证书。
  • “下载 CA”可以下载当前 ca.pem,供需要独立证书库的应用导入。

请求详情和接口 JSON 会对 Authorization、Cookie、Set-Cookie、API Key 等敏感 Header 脱敏;但“重放”和“复制 curl”需要使用原始 Header,因此复制出的 curl 可能包含凭据。

如果请求 Body 超过 captureBodyLimit,界面只保留截断后的预览,重放和复制 curl 也只能使用这部分内容;大文件上传不应依赖该功能完整重放。

Rules 页面

Rules 页面用于直接编辑规则,不需要手动寻找 rules.txt

  • ON/OFF:总开关。关闭后所有规则停止生效,但规则内容仍保留。
  • Create / Rename / Delete:创建、重命名或删除规则集。
  • 每个规则集可以独立启用或停用,适合区分“本地开发”“测试环境”“Mock”“故障模拟”。
  • Import / Export:导入或导出当前规则集的文本。
  • Save:校验并立即应用。语法错误时会显示具体行号,错误配置不会生效。
  • Command/Ctrl + S:保存。
  • Command/Ctrl + /:注释或取消注释当前行。

规则保存在数据目录的 rules.txtrules.txt.workspace.json 中,重启后继续生效。

2. 规则基本格式

每行是一条规则:

匹配范围 操作 [操作 ...]

空行和以 # 开头的行会被忽略。同一行可以组合多个操作:

api.example.com/v1 includeFilter://m:GET reqHeaders://X-Debug=1 reqDelay://300

匹配范围

| 写法 | 匹配范围 | 适用场景 | | --- | --- | --- | | * | 所有进入规则处理的请求 | 全局 Header 或统一故障模拟 | | api.example.com | 精确域名 | 针对一个服务 | | *.example.com | 所有子域名,不包含根域名 example.com | 针对一组子域 | | api.example.com/v1 | 域名相同且路径以 /v1 开头 | 针对一组 API | | https://api.example.com/v1 | 从 URL 写法中提取域名和路径前缀,协议本身不参与匹配 | 更易读的域名加路径写法 | | /https:\/\/cdn\.example\.com\/assets\/(.*)/ | Go RE2 正则匹配完整 URL | JS/CSS 地址改写和复杂匹配 | | /pattern/i | 忽略大小写的正则 | 大小写不固定的 URL |

正则还支持 ms 标志。保存规则时会校验正则;不支持 JavaScript 正则特有的 lookbehind 等 RE2 不支持的语法。

HTTPS 抓包范围

HTTPS 默认使用 CONNECT 透明隧道,不会解密全部网站。下列情况才会进入本地 TLS 抓包:

  1. 域名命中 captureHosts
  2. 域名命中 ech://...echConfig://... 规则。
  3. 域名命中 URL 改写规则。

因此,如果只写下面这条规则:

api.example.com reqHeaders://X-Debug=1

它可以处理明文 HTTP,但 HTTPS 请求还需要把域名加入 captureHosts,或者与 ECH/URL 改写规则组合:

{
  "captureHosts": "api.example.com,*.dev.example.com"
}

host://proxy:// 属于连接层规则,即使不解密 HTTPS 也可以作用于 CONNECT 隧道。

3. URL、JS 和 CSS 地址改写

目的

把浏览器原本要访问的线上资源转发到另一个 HTTP/HTTPS 地址,常用于:

  • 将线上 JS 或 CSS 替换成本地 Vite、Webpack 等开发服务器的文件。
  • 把线上 API 临时转到本地后端。
  • 在不修改页面源码和 DNS 的情况下调试已部署页面。

固定地址改写

cdn.example.com/assets/app.js http://127.0.0.1:5173/app.js

请求 https://cdn.example.com/assets/app.js 时,代理会向 http://127.0.0.1:5173/app.js 发请求。请求方法和 Body 会保留,发往上游的 Host 会改成新地址的 Host。

使用正则改写一组资源

/https:\/\/cdn\.example\.com\/assets\/(.*)/ http://127.0.0.1:5173/$1

例如:

https://cdn.example.com/assets/js/app.abc123.js

会被改写为:

http://127.0.0.1:5173/js/app.abc123.js

只替换带 hash 的主入口 JS:

/https:\/\/cdn\.example\.com\/assets\/app\..*\.js/ http://127.0.0.1:5173/app.js

捕获组规则:

  • $0:整个匹配内容。
  • $1$9:对应正则捕获组。
  • $$:输出一个字面量 $

同一个请求匹配多条 URL 改写规则时,只使用第一条,所以应把精确规则放在通用规则前面。HTTPS URL 改写会自动启用对应域名的 TLS 抓包,无需再加入 captureHosts

4. host:// 指定连接 IP

目的

跳过本地 DNS 结果,强制把某个域名连接到指定 IP,常用于:

  • 调试本地或测试服务器。
  • 绕过错误或被污染的 DNS 解析结果。
  • 把请求定向到某个灰度节点。
  • 在不修改系统 hosts 文件的情况下临时切换地址。

写法

api.example.com host://127.0.0.1

也兼容传统 hosts 写法:

127.0.0.1 api.example.com

可以配置多个 IP,前一个连接失败后继续尝试下一个:

api.example.com host://192.0.2.10,192.0.2.11

host:// 只替换实际 TCP 连接地址,原 URL Host、HTTP Host、TLS SNI 和证书校验仍然使用 api.example.com。这与 URL 改写不同:URL 改写会把请求的目标 URL 和上游 Host 一起改成新地址。

单独使用 host:// 时,HTTPS 默认保持端到端隧道,因此目标 IP 必须能够为原域名提供有效证书。如果该域名还在 captureHosts 或 ECH 规则中,本地代理会先解密浏览器流量,再使用原域名和指定 IP 连接上游。

host:// 只控制直接连接时的目标 IP。如果同一个域名被 proxy://system 或全局上游代理接管,目标域名通常由上游代理解析,host:// 不会传给那个上游代理。

5. 上游代理和代理链路

目的

控制未走 ECH 或 URL 改写的请求如何继续访问网络,适用于:

  • 本机已经有公司代理或第三方代理,需要继续串联。
  • 某些域名必须绕过系统代理直接访问。
  • 大多数请求直连,只有特定域名跟随系统代理。

全局 fallbackProxy

config.json 中配置:

{
  "fallbackProxy": "direct"
}

可选值:

  • direct:直接连接目标,默认值。
  • system:读取系统或环境变量中的 HTTP/HTTPS 代理。
  • http://proxy.example.com:8080:所有普通上游请求使用指定 HTTP 代理。
  • https://proxy.example.com:8443:使用指定 HTTPS 代理。
  • http://user:[email protected]:8080:使用带 Basic 认证的上游代理。配置文件包含明文凭据,应限制文件权限。

macOS 的 system 会读取系统 HTTP/HTTPS 代理,同时遵守 ExceptionsListExcludeSimpleHostnames。Windows 和 Linux 的 system 使用 HTTP_PROXYHTTPS_PROXYNO_PROXY

如果全局代理指回本工具自己的监听地址,启动会拒绝该配置,避免形成代理死循环。

按域名覆盖

api.example.com proxy://system
internal.example.com proxy://direct
  • proxy://system:这个域名使用系统代理。
  • proxy://direct:这个域名强制直连,覆盖全局 fallbackProxy

规则中的 proxy:// 目前只支持 systemdirect,不能直接填写自定义代理 URL;自定义 URL 应放在全局 fallbackProxy 中。

6. 修改请求 Header

目的

  • 给请求增加调试标识或灰度标识。
  • 临时注入测试用 Authorization。
  • 修改 User-Agent、Origin 或其他上游识别字段。

单个 Header:

api.example.com reqHeaders://X-Debug=1

多个 Header 使用 &

api.example.com reqHeaders://X-Debug=1&X-Environment=local

包含空格或特殊字符时可以使用括号,或者进行 URL 编码:

api.example.com reqHeaders://(Authorization=Bearer test-token)
api.example.com reqHeaders://Authorization=Bearer%20test-token

代理使用覆盖语义:如果请求本来已经存在同名 Header,新值会替换旧值。对 HTTPS 使用该能力时,域名必须处于 HTTPS 抓包范围。

7. 修改响应 Header

目的

  • 本地联调时临时开放 CORS。
  • 禁用浏览器缓存。
  • 修改 Content-Type 或测试前端对响应头的处理。

示例:

api.example.com resHeaders://Access-Control-Allow-Origin=*&Cache-Control=no-store

修改 JSON Content-Type:

api.example.com resHeaders://Content-Type=application/json

响应 Header 修改既适用于真实上游响应,也适用于本地 Mock 响应。同名 Header 会被规则值覆盖。对 HTTPS 使用时同样需要进入抓包范围。

8. Mock 状态码和响应 Body

目的

不访问真实上游,直接由本地代理返回结果,常用于:

  • 前端等待后端接口时先模拟数据。
  • 测试 401、403、404、429、500 等异常状态。
  • 快速验证空数据、错误数据和降级页面。

返回 JSON:

api.example.com/v1/user statusCode://200 resBody://({"id":1,"name":"Local"}) resHeaders://Content-Type=application/json

模拟服务错误:

api.example.com/v1/order statusCode://503 resBody://(service unavailable)

statusCode 必须在 100 到 599 之间。只有配置 statusCode://... 才会触发本地 Mock;单独写 resBody://... 不会拦截真实请求。Mock 命中后不会连接上游。

9. 模拟请求延迟

目的

  • 测试 Loading、Skeleton 和超时提示。
  • 模拟弱网或慢接口。
  • 检查重复提交、请求取消和并发行为。

延迟 1500 毫秒:

api.example.com/v1/order reqDelay://1500

延迟范围是 0 到 300000 毫秒。一个请求同时命中多条延迟规则时,延迟时间会累加。

10. 阻断请求

目的

  • 测试资源加载失败。
  • 临时屏蔽某个接口、埋点或第三方脚本。
  • 模拟网络层失败,而不是返回一个 HTTP 状态码。

推荐写法:

api.example.com/blocked enable://abort

也支持:

api.example.com/blocked block://true

阻断与 Mock 不同:Mock 会返回指定 HTTP 响应,阻断会让请求以代理错误结束。对 HTTPS 使用时需要进入抓包范围。

11. 按请求方法过滤

目的

同一个路径可能同时处理 GET、POST、PUT 等请求,方法过滤可以只对其中一种生效。

只 Mock GET:

api.example.com/v1/user includeFilter://m:GET statusCode://200 resBody://({"id":1})

只延迟 POST:

api.example.com/v1/order includeFilter://m:POST reqDelay://2000

目前文本规则只支持 includeFilter://m:METHOD 这一种 includeFilter 写法。

12. 多条规则的组合与优先级

一个请求可以命中多条规则,处理原则如下:

  • 请求 Header、响应 Header 和延迟可以由多条规则叠加。
  • 同名 Header 被后匹配到的规则覆盖。
  • 多条延迟规则的时间会累加。
  • ECH 模式、host://proxy:// 的后匹配值覆盖前值。
  • URL 改写只执行第一条匹配规则。
  • Block 或 Mock 按规则顺序处理,先遇到的终止操作生效。
  • 规则集按 Rules 页面中的顺序组合,每个规则集内部按文本从上到下执行。

因此应把更精确的 URL 改写、Block 和 Mock 放在更通用的规则前面。

13. ECH 规则

运行以下命令查看配置文件位置:

ech config

rules.txtconfig.json 位于同一目录。规则示例:

example.com ech://require
api.example.com ech://auto
legacy.example.com ech://off
  • ech://require:必须使用 ECH;失败时明确报错,不降级到普通 TLS。
  • ech://auto:优先使用 ECH,失败时允许回退到普通 TLS。
  • ech://off:关闭该域名的 ECH。

三种写法都会让命中的 HTTPS 域名进入本地抓包。ech://off 的含义是上游使用普通 TLS,不是关闭本地抓包;如果只想让请求保持完全透明的端到端隧道,不要为该域名添加 ECH 规则,也不要把它加入 captureHosts

显式指定 ECHConfig 和连接地址:

example.com ech://require echConfig://BASE64_ECH_CONFIG host://192.0.2.10
  • echConfig://BASE64_ECH_CONFIG:使用明确的 ECHConfig,适合验证指定配置或绕过自动发现结果;未写 ech:// 时默认按 require 处理。
  • host://192.0.2.10:指定承载 ECH 请求的连接 IP,同时继续使用原域名作为 SNI 和证书校验名称。
  • 显式设置 echConfig://host:// 后,工具尊重该固定目标,不会自动切换到 relay。

默认情况下,工具先通过可信 DoH 获取 ECH bootstrap,再查询目标域名的 HTTPS(TYPE65)记录。ECHConfig 和 IP hints 会按 DNS TTL 缓存并自动刷新;服务端返回 retry_configs 时会更新配置并重试。

如果目标记录下发的 IP hints 暂时拒绝当前 ECHConfig,工具会继续尝试 Cloudflare ECH relay。ech://require 在两条 ECH 路径都失败时会明确报错,不会降级成普通 TLS。显式配置 echConfig://host:// 时不会自动改道。

常见故障

ERR_PROXY_CONNECTION_FAILED

原因通常是 ZeroOmega 已选择 ECH,但本地代理没有运行。

ech start
ech status

NET::ERR_CERT_AUTHORITY_INVALID

重新执行:

ech start
ech install-ca

确认系统信任库中存在 ECH Inspector Local CA,然后完全退出并重启 Chrome。

CRX 无法拖入或提示必须从商店安装

这是 Chrome 对离线 CRX 的限制。打开开发者模式,使用“加载已解压的扩展程序”,选择 zeroomega-3.5.0-unpacked

ZeroOmega 提示代理设置无法控制

通常是另一个代理插件或浏览器策略正在控制 Chrome 代理。禁用其他代理类扩展,再重新选择 ECH

页面显示 Bad Gatewayupstream request failed

先确认使用的是最新版:

npm install -g @hugehard/ech@latest
ech restart
ech logs -f

日志会记录目标 ECH 路径、relay 尝试和最终错误。ech://require 不会静默降级到普通 TLS。

停止代理后所有网页都打不开

在 ZeroOmega 中选择 [直接连接]。只执行 ech stop 不会自动修改 Chrome 的代理设置。

端口 8080 被占用

运行 ech config,编辑 config.json 中的 proxyPort,然后:

ech restart
ech extension

重新生成并导入 ECH Profile,或者手动把 ZeroOmega 端口改成新端口。

常用命令

ech start               后台启动代理
ech stop                停止代理
ech restart             重启代理
ech status              查看状态和监听地址
ech logs                查看最近日志
ech logs -f             实时跟踪日志
ech open                打开 Web 管理界面
ech install-ca          信任本地 CA
ech extension           准备并打开离线插件安装流程
ech extension options   打开插件选项并定位 ECH 配置备份
ech extension --path    输出 CRX、unpacked 和配置备份路径
ech config              输出 config.json 路径
ech help                查看命令帮助

配置

默认 config.json

{
  "proxyHost": "127.0.0.1",
  "proxyPort": 8080,
  "fallbackProxy": "direct",
  "captureHosts": "",
  "maxSessions": 500,
  "captureBodyLimit": 1048576,
  "upstreamPoolSize": 32,
  "maxConnectionAge": "10m"
}

每个配置项的目的:

| 配置项 | 默认值 | 作用 | | --- | --- | --- | | proxyHost | 127.0.0.1 | 本地代理和管理 UI 的监听地址。保持回环地址可避免局域网或公网中的其他设备访问管理接口。 | | proxyPort | 8080 | 本地 HTTP 代理和管理 UI 共用的端口。修改后也要同步修改 ZeroOmega Profile。 | | fallbackProxy | direct | 普通 TLS、透明隧道和非 ECH 请求的默认上游路线,可选直连、系统代理或明确的 HTTP(S) 代理 URL。 | | captureHosts | 空 | 主动进行 HTTPS 解密和请求记录的域名列表,逗号分隔,支持 *.example.com*。ECH 与 URL 改写规则会自动启用对应域名,不必重复填写。 | | maxSessions | 500 | 内存中最多保留多少条请求记录。达到上限后淘汰最旧记录;不会写入磁盘。 | | captureBodyLimit | 1048576 | 每条请求和响应最多保留多少字节的 Body 预览,默认 1 MiB。它只限制界面中的记录,不截断实际转发内容。 | | upstreamPoolSize | 32 | 可复用的原生上游连接句柄数量。并发较高时可以增加,但会占用更多连接和内存。 | | maxConnectionAge | 10m | 上游连接句柄复用的最长时间。到期后重建,以避免长期复用失效的连接或旧 ECH 状态。 | | logMaxSize | 10485760 | 单个日志文件达到多少字节后轮转,默认 10 MiB。未写出时 CLI 会自动补默认值。 | | logBackups | 3 | 最多保留多少个历史日志文件。设置为 0 表示不保留轮转备份。 |

captureHosts 示例:

{
  "captureHosts": "api.example.com,*.dev.example.com"
}

* 会解密所有通过代理的 HTTPS 流量,只适合明确需要全量调试的环境。范围越大,代理能看到的敏感数据越多,也会增加证书签发、记录和内存开销;日常使用应优先填写具体域名。

fallbackProxy 支持 directsystem 或明确的 http://host:porthttps://host:port。macOS 的 system 会读取系统 HTTP/HTTPS 代理并遵守例外列表;Linux 和 Windows 从 HTTP_PROXYHTTPS_PROXYNO_PROXY 读取。

按域名覆盖上游代理:

api.example.com proxy://system
assets.example.com proxy://direct

其他规则示例:

api.example.com host://127.0.0.1
api.example.com reqHeaders://x-debug=1
api.example.com resHeaders://cache-control=no-store
api.example.com reqDelay://500
api.example.com enable://abort
api.example.com mockStatus://200 mockBody://ok
/https:\/\/cdn\.example\.com\/(.*)/ http://127.0.0.1:8000/$1

环境变量

export ECH_INSPECTOR_DATA_DIR=/path/to/data
export ECH_INSPECTOR_CONFIG=/path/to/config.json

PowerShell 示例:

$env:ECH_INSPECTOR_DATA_DIR = "D:\ech-data"
$env:ECH_INSPECTOR_CONFIG = "D:\ech-data\config.json"

安全说明

  • 代理和管理 UI 默认只监听回环地址,不要把管理端口暴露到公网。
  • 可以把 ca.pem 导入本机信任库,但绝对不要分享 ca-key.pem
  • Web 管理界面的请求记录只保存在内存中。
  • 敏感 Header 会在详情和 API JSON 中脱敏。
  • 用户主动执行“复制 curl”或“重放”时会使用本机内存中的原始 Header,复制出的命令可能包含 Cookie 或 Authorization,请勿发给不可信的人。
  • 不再使用时,可以在“钥匙串访问”或 certmgr.msc 中删除 ECH Inspector Local CA,并在 Chrome 中移除或禁用 ZeroOmega。

第三方插件说明

包内提供 Proxy SwitchyOmega 3(ZeroOmega)v3.5.0 的官方签名 CRX、解压兜底、GPL-3.0-or-later 许可证和对应源码归档。ZeroOmega 是独立第三方项目,与本包不存在隶属或合作关系。详细信息见 extension/THIRD_PARTY_NOTICES.md

Node.js 只用于命令行管理;代理、证书签发和 ECH 传输由随包提供的原生程序完成。