客户端 -> 本地中继 -> Google/CDN 前端 -> GAS (Google Apps Script) 中继 -> Cloudflare Worker -> 出口
|
+-> 向网络 DPI 过滤器显示 www.google.com
客户端 -> 本地中继 -> Google/CDN 前端 -> GAS (Google Apps Script) 中继 -> Cloudflare Worker -> 自托管上游转发器 -> 出口
|
+-> 向网络 DPI 过滤器显示 www.google.com
在正常使用中,浏览器将流量发送到运行在您计算机上的代理。
代理通过 Google 相关基础设施发送该流量,因此网络只看到允许的域名,例如 www.google.com。
您部署的中继随后通过 Cloudflare Worker 获取真实网站,并通过相同路径返回响应。
这意味着过滤器看到的是正常的 Google 流量,而实际目标地址仍隐藏在中继请求中。
git clone https://github.com/denuitt1/mhr-cfw.git
cd mhr-cfw
pip install -r requirements.txt
无法直接访问 PyPI? 请改用此镜像:
pip install -r requirements.txt -i https://mirror-pypi.runflare.com/simple/ --trusted-host mirror-pypi.runflare.com
worker.js 文件(位于 deploy/ 目录下),复制所有内容,并粘贴到 Apps Script 编辑器中。const WORKER_URL = "myworker.workers.dev";
Code.gs 文件(位于 deploy/ 目录下),复制所有内容,并粘贴到 Apps Script 编辑器中。const AUTH_KEY = "your-secret-password-here";
const WORKER_URL = "https://myworker.workers.dev";
⚠️ 请记住您在步骤3中设置的密码。您将在下面的配置文件中使用相同的密码。
点击 run.bat 文件(Windows)或 run.sh 文件(Linux)以启动中继。
如果是首次运行,将弹出设置向导,您需要输入 AUTH_KEY 和 Google Apps Script 部署 ID。
您应该会看到一条消息,说明 HTTP 代理正在 127.0.0.1:8085 上运行。
我们建议使用 v2rayN 客户端 并配置 socks5 代理。
您也可以使用 FoxyProxy 的 Chrome 扩展 或 Firefox 扩展 在浏览器中使用此代理。
在浏览器中打开 ipleak.net,您应该看到您的 IP 地址显示为 Cloudflare 的地址。
当您运行虚拟机时,它运行在与宿主机隔离的网络环境中。默认情况下,虚拟机无法直接访问宿主机 localhost 上运行的服务——包括本代理。
为解决此问题,您需要找到虚拟机监控程序分配给宿主机的网关 IP,然后在虚拟机内部配置代理时使用该 IP 代替 localhost。
示例:VirtualBox(NAT 模式)
宿主机始终可在虚拟机内通过 10.0.2.2 访问。设置代理:
export http_proxy="http://10.0.2.2:8085"
export https_proxy="http://10.0.2.2:8085"
export all_proxy="socks5://10.0.2.2:8085"
要使此设置永久生效,请将以上行添加到 ~/.bashrc 并运行 source ~/.bashrc。
由于此代理执行 SSL 检查,您可能会看到证书错误。安装附带的 ca.crt 以解决此问题:
sudo cp ca.crt /usr/local/share/ca-certificates/ && sudo update-ca-certificates
您可以在同一网络中的手机或其他设备上使用此代理——无需额外软件。
1. 查找宿主机 IP
# Windows
ipconfig
# Linux / macOS
ip addr
查找连接到路由器的适配器的 IP(例如 192.168.1.8)。
2. 转发端口(仅限 Windows,如果服务绑定到 localhost)
以管理员身份运行 CMD:
netsh interface portproxy add v4tov4 listenaddress=192.168.1.8 listenport=8085 connectaddress=127.0.0.1 connectport=8085
netsh advfirewall firewall add rule name="Proxy 8085" dir=in action=allow protocol=TCP localport=8085
3. 在手机上配置代理
将手机连接到同一个 Wi-Fi,然后手动设置代理:
192.168.1.8)8085在 Android 上:设置 → Wi-Fi → 修改 → 代理 → 手动 在 iPhone 上:设置 → Wi-Fi → (网络) → HTTP 代理 → 手动
4. 安装 CA 证书
将 ca.crt 传输到您的手机,然后:
验证码(Cloudflare Turnstile/机器人挑战、reCAPTCHA、hCaptcha)将令牌绑定到解决挑战的 IP。Cloudflare Worker 每次请求都通过不同的边缘 IP 退出,因此即使您解决了挑战,目标网站上的验证也会失败。此可选附加组件允许 Worker 将所有 fetch() 调用转发到您在有稳定 IP 的 VPS 上运行的小型 Node 服务器——为目标网站提供一致的出口地址。
cf_clearance)。如果您没有遇到这些问题,可以保持未配置状态——Worker 的行为将与之前完全一样。
Cloudflare Worker 不提供稳定的出站 IP——fetch() 通过轮换的 Cloudflare 边缘 IP 池退出,这正是破坏 IP 绑定验证码令牌的原因。Cloudflare 的静态出口选项(BYOIP、Egress Workers)属于企业级功能,因此带有静态 IP 的小型 VPS 是实用的变通方案。转发器只是一个瘦代理,它从稳定地址重新发起 fetch()。
参考实现位于 deploy/upstream-forwarder/upstream_forwarder.js。
它需要 Node 18+ 且无依赖。建议在 Caddy 或 nginx 后面使用 TLS 运行——Worker 会拒绝非 HTTPS 的转发器 URL。
# 在您的 VPS 上(Ubuntu/Debian 示例):
sudo apt install -y nodejs # 必须为 18+
export AUTH_KEY="some-long-random-string-at-least-32-chars"
export PORT=8787
node deploy/upstream-forwarder/upstream_forwarder.js
使用 Caddy 前端实现自动 TLS:
forwarder.example.com {
reverse_proxy 127.0.0.1:8787
}
快速测试:
curl -X POST https://forwarder.example.com/fwd \
-H "x-upstream-auth: $AUTH_KEY" \
-H "content-type: application/json" \
-d '{"u":"https://httpbin.org/ip","m":"GET","h":{}}'
解码后的响应体应显示 VPS 的 IP。
在 Cloudflare 仪表板中 → 您的 Worker → Settings → Variables and Secrets:
保存并重新部署 Worker。
通过代理浏览 https://httpbin.org/ip——您应该看到 VPS 的 IP,而不是 Cloudflare 的 IP。然后重新访问之前无法正常工作的受验证码保护的网站——挑战现在应该可以验证。
转发器必须要求验证。没有
AUTH_KEY它将拒绝启动。任何拥有 URL 和密钥的人都可以将其用作中继,请保密两者。
默认情况下,Worker 处理的每个请求都通过转发器路由,因此无关流量也会消耗 VPS 带宽。若要使只有需要稳定出口 IP 的网站通过 VPS 发送,请在 config.json 的 forwarder_hosts 中列出它们——语法与 bypass_hosts 相同(精确主机名或 .后缀)。不匹配的内容回退到 Worker 上的直接 fetch()。
{
...
"forwarder_hosts": [
"example.com",
".cf-protected-suffix"
]
...
}
将列表留空(或删除该键)以保持历史行为(转发所有内容)。
MHR-CFW 仅用于教育、测试和研究目的。
| 名称 | 类型 | 值 |
|---|
UPSTREAM_FORWARDER_URL | 秘密 | https://forwarder.example.com/fwd |
UPSTREAM_AUTH_KEY | 秘密 | 您在 VPS 上设置的相同 AUTH_KEY |
UPSTREAM_FAIL_MODE | 变量 | closed(默认)——转发器失败时返回 502。使用 open 可回退到直接 fetch。 |
UPSTREAM_TIMEOUT_MS | 变量(可选) | 默认 25000 |