mhr-cfw-domain-fronting-relay

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

MHR-CFW Domain-Fronting Relay

MHR-CFW 域名前置中继

Skill by ara.so — Daily 2026 Skills collection.
MHR-CFW (MasterHttpRelay + Cloudflare Worker) is a Python-based domain-fronting relay that routes HTTP/SOCKS5 proxy traffic through Google Apps Script (GAS) and Cloudflare Workers. Network DPI filters see only traffic to
www.google.com
, while the actual destination is hidden inside the relay chain.
ara.so提供的技能 — 2026每日技能合集。
MHR-CFW(MasterHttpRelay + Cloudflare Worker)是一款基于Python的域名前置中继工具,可通过Google Apps Script(GAS)和Cloudflare Workers路由HTTP/SOCKS5代理流量。网络DPI过滤器只会检测到发往
www.google.com
的流量,而实际目标地址则隐藏在中继链路中。

Traffic Flow

流量流向

Client → Local Proxy (127.0.0.1:8085)
       Google IP (216.239.38.120) — DPI sees www.google.com
       Google Apps Script Web App (Relay)
       Cloudflare Worker
       Target Website

客户端 → 本地代理(127.0.0.1:8085)
       Google IP(216.239.38.120)—— DPI仅识别www.google.com
       Google Apps Script Web应用(中继)
       Cloudflare Worker
       目标网站

Installation

安装步骤

bash
git clone https://github.com/denuitt1/mhr-cfw.git
cd mhr-cfw
pip install -r requirements.txt
If PyPI is blocked:
bash
pip install -r requirements.txt \
  -i https://mirror-pypi.runflare.com/simple/ \
  --trusted-host mirror-pypi.runflare.com

bash
git clone https://github.com/denuitt1/mhr-cfw.git
cd mhr-cfw
pip install -r requirements.txt
若PyPI被屏蔽:
bash
pip install -r requirements.txt \
  -i https://mirror-pypi.runflare.com/simple/ \
  --trusted-host mirror-pypi.runflare.com

Full Setup Guide

完整搭建指南

Step 1: Deploy the Cloudflare Worker

步骤1:部署Cloudflare Worker

  1. Log in to Cloudflare Dashboard
  2. Navigate to Compute > Workers & Pages
  3. Click Create ApplicationStart with Hello WorldDeploy
  4. Click Edit code, delete all default code
  5. Paste the contents of
    script/worker.js
    from the repo
  6. Edit the worker URL constant:
    javascript
    const WORKER_URL = "your-worker-name.workers.dev";
  7. Click Deploy — note your worker URL (e.g.,
    your-worker-name.workers.dev
    )
  1. 登录Cloudflare控制台
  2. 进入Compute > Workers & Pages
  3. 点击Create ApplicationStart with Hello WorldDeploy
  4. 点击Edit code,删除所有默认代码
  5. 粘贴仓库中
    script/worker.js
    的内容
  6. 修改worker URL常量:
    javascript
    const WORKER_URL = "your-worker-name.workers.dev";
  7. 点击Deploy — 记录你的worker URL(例如:
    your-worker-name.workers.dev

Step 2: Deploy the Google Apps Script Relay

步骤2:部署Google Apps Script中继

  1. Go to script.google.com and create a New project
  2. Delete all default code
  3. Paste the contents of
    script/Code.gs
    from the repo
  4. Edit these two constants at the top:
    javascript
    const AUTH_KEY = "your-secret-password-here";   // choose a strong password
    const WORKER_URL = "https://your-worker-name.workers.dev";
  5. Click DeployNew deployment
    • Type: Web app
    • Execute as: Me
    • Who has access: Anyone
  6. Click Deploy and copy the Deployment ID (long random string like
    AKfycb...
    )
  1. 访问script.google.com并创建一个新项目
  2. 删除所有默认代码
  3. 粘贴仓库中
    script/Code.gs
    的内容
  4. 修改顶部的两个常量:
    javascript
    const AUTH_KEY = "your-secret-password-here";   // 设置一个强密码
    const WORKER_URL = "https://your-worker-name.workers.dev";
  5. 点击DeployNew deployment
    • 类型:Web app
    • 执行身份:
    • 访问权限:任何人
  6. 点击Deploy复制部署ID(类似
    AKfycb...
    的长随机字符串)

Step 3: Configure
config.json

步骤3:配置
config.json

bash
cp config.example.json config.json
Edit
config.json
:
json
{
  "mode": "apps_script",
  "google_ip": "216.239.38.120",
  "front_domain": "www.google.com",
  "script_id": "AKfycbXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "auth_key": "your-secret-password-here",
  "listen_host": "127.0.0.1",
  "listen_port": 8085,
  "socks5_enabled": true,
  "socks5_port": 1080,
  "log_level": "INFO",
  "verify_ssl": true
}
FieldDescription
mode
Always
"apps_script"
for GAS relay
google_ip
IP of Google's infrastructure for fronting
front_domain
Domain shown to DPI (
www.google.com
)
script_id
Your GAS Deployment ID from Step 2
auth_key
Must match
AUTH_KEY
in
Code.gs
listen_host
Local bind address (keep
127.0.0.1
)
listen_port
HTTP proxy port (default
8085
)
socks5_enabled
Enable SOCKS5 proxy on
socks5_port
socks5_port
SOCKS5 proxy port (default
1080
)
log_level
DEBUG
,
INFO
,
WARNING
,
ERROR
verify_ssl
Verify SSL certs; set
false
to skip
bash
cp config.example.json config.json
编辑
config.json
json
{
  "mode": "apps_script",
  "google_ip": "216.239.38.120",
  "front_domain": "www.google.com",
  "script_id": "AKfycbXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "auth_key": "your-secret-password-here",
  "listen_host": "127.0.0.1",
  "listen_port": 8085,
  "socks5_enabled": true,
  "socks5_port": 1080,
  "log_level": "INFO",
  "verify_ssl": true
}
字段描述
mode
使用GAS中继时固定为
"apps_script"
google_ip
用于域名前置的Google基础设施IP
front_domain
展示给DPI的域名(
www.google.com
script_id
步骤2中获取的GAS部署ID
auth_key
必须与
Code.gs
中的
AUTH_KEY
一致
listen_host
本地绑定地址(保持
127.0.0.1
即可)
listen_port
HTTP代理端口(默认
8085
socks5_enabled
是否在
socks5_port
启用SOCKS5代理
socks5_port
SOCKS5代理端口(默认
1080
log_level
日志级别:
DEBUG
,
INFO
,
WARNING
,
ERROR
verify_ssl
是否验证SSL证书;设置
false
可跳过验证

Step 4: Run the Proxy

步骤4:运行代理

Linux/macOS:
bash
bash start.sh
Linux/macOS:
bash
bash start.sh

or

python3 main.py

**Windows:**
start.bat

Expected output:
[INFO] HTTP proxy running on 127.0.0.1:8085 [INFO] SOCKS5 proxy running on 127.0.0.1:1080

---
python3 main.py

**Windows:**
start.bat

预期输出:
[INFO] HTTP proxy running on 127.0.0.1:8085 [INFO] SOCKS5 proxy running on 127.0.0.1:1080

---

Using the Proxy

代理使用方法

Browser via FoxyProxy

浏览器通过FoxyProxy配置

Install FoxyProxy:
Configure FoxyProxy:
  • Proxy Type:
    HTTP
    or
    SOCKS5
  • Host:
    127.0.0.1
  • Port:
    8085
    (HTTP) or
    1080
    (SOCKS5)
安装FoxyProxy
配置FoxyProxy:
  • 代理类型:
    HTTP
    SOCKS5
  • 主机:
    127.0.0.1
  • 端口:
    8085
    (HTTP)或
    1080
    (SOCKS5)

curl (HTTP proxy)

curl(HTTP代理)

bash
curl -x http://127.0.0.1:8085 https://ipleak.net/json/
bash
curl -x http://127.0.0.1:8085 https://ipleak.net/json/

curl (SOCKS5 proxy)

curl(SOCKS5代理)

bash
curl --socks5 127.0.0.1:1080 https://ipleak.net/json/
bash
curl --socks5 127.0.0.1:1080 https://ipleak.net/json/

Python requests

Python requests库

python
import requests

proxies = {
    "http": "http://127.0.0.1:8085",
    "https": "http://127.0.0.1:8085",
}

response = requests.get("https://ipleak.net/json/", proxies=proxies)
print(response.json())
python
import requests

proxies = {
    "http": "http://127.0.0.1:8085",
    "https": "http://127.0.0.1:8085",
}

response = requests.get("https://ipleak.net/json/", proxies=proxies)
print(response.json())

Python with SOCKS5

Python搭配SOCKS5

python
import requests

proxies = {
    "http": "socks5://127.0.0.1:1080",
    "https": "socks5://127.0.0.1:1080",
}

response = requests.get("https://ipleak.net/json/", proxies=proxies)
print(response.json())

python
import requests

proxies = {
    "http": "socks5://127.0.0.1:1080",
    "https": "socks5://127.0.0.1:1080",
}

response = requests.get("https://ipleak.net/json/", proxies=proxies)
print(response.json())

Configuration Patterns

配置示例

Minimal config (HTTP only, no SOCKS5)

极简配置(仅HTTP,无SOCKS5)

json
{
  "mode": "apps_script",
  "google_ip": "216.239.38.120",
  "front_domain": "www.google.com",
  "script_id": "YOUR_DEPLOYMENT_ID",
  "auth_key": "YOUR_AUTH_KEY",
  "listen_host": "127.0.0.1",
  "listen_port": 8085,
  "socks5_enabled": false,
  "log_level": "INFO",
  "verify_ssl": true
}
json
{
  "mode": "apps_script",
  "google_ip": "216.239.38.120",
  "front_domain": "www.google.com",
  "script_id": "YOUR_DEPLOYMENT_ID",
  "auth_key": "YOUR_AUTH_KEY",
  "listen_host": "127.0.0.1",
  "listen_port": 8085,
  "socks5_enabled": false,
  "log_level": "INFO",
  "verify_ssl": true
}

Debug config (verbose logging, skip SSL verification)

调试配置(详细日志,跳过SSL验证)

json
{
  "mode": "apps_script",
  "google_ip": "216.239.38.120",
  "front_domain": "www.google.com",
  "script_id": "YOUR_DEPLOYMENT_ID",
  "auth_key": "YOUR_AUTH_KEY",
  "listen_host": "127.0.0.1",
  "listen_port": 8085,
  "socks5_enabled": true,
  "socks5_port": 1080,
  "log_level": "DEBUG",
  "verify_ssl": false
}
json
{
  "mode": "apps_script",
  "google_ip": "216.239.38.120",
  "front_domain": "www.google.com",
  "script_id": "YOUR_DEPLOYMENT_ID",
  "auth_key": "YOUR_AUTH_KEY",
  "listen_host": "127.0.0.1",
  "listen_port": 8085,
  "socks5_enabled": true,
  "socks5_port": 1080,
  "log_level": "DEBUG",
  "verify_ssl": false
}

Listen on all interfaces (for LAN sharing)

监听所有接口(用于局域网共享)

json
{
  "listen_host": "0.0.0.0",
  "listen_port": 8085
}
⚠️ Only use
0.0.0.0
on trusted networks. Anyone on the LAN can use your proxy.

json
{
  "listen_host": "0.0.0.0",
  "listen_port": 8085
}
⚠️ 仅在可信网络中使用
0.0.0.0
。局域网内任何人都可使用你的代理。

Cloudflare Worker (
script/worker.js
) — Key Structure

Cloudflare Worker(
script/worker.js
)核心结构

javascript
// The worker receives proxied requests and forwards them to the target
const WORKER_URL = "your-worker-name.workers.dev"; // set this to your own worker

addEventListener("fetch", event => {
  event.respondWith(handleRequest(event.request));
});
The worker:
  • Receives requests from GAS relay
  • Extracts the target URL from the request
  • Fetches the target on behalf of the client
  • Returns the response back through the chain

javascript
// Worker接收代理请求并转发至目标地址
const WORKER_URL = "your-worker-name.workers.dev"; // 设置为你自己的worker地址

addEventListener("fetch", event => {
  event.respondWith(handleRequest(event.request));
});
Worker功能:
  • 接收来自GAS中继的请求
  • 从请求中提取目标URL
  • 代表客户端获取目标内容
  • 将响应通过链路返回

Google Apps Script (
script/Code.gs
) — Key Structure

Google Apps Script(
script/Code.gs
)核心结构

javascript
const AUTH_KEY = "your-secret-password-here";      // must match config.json auth_key
const WORKER_URL = "https://your-worker.workers.dev";

function doPost(e) {
  // Validates AUTH_KEY, extracts target URL, forwards via WORKER_URL
}
The GAS relay:
  • Exposes a public HTTPS endpoint (
    /exec
    ) that acts as the domain-fronted relay
  • Validates
    AUTH_KEY
    on every request
  • Forwards validated requests to your Cloudflare Worker

javascript
const AUTH_KEY = "your-secret-password-here";      // 必须与config.json中的auth_key一致
const WORKER_URL = "https://your-worker.workers.dev";

function doPost(e) {
  // 验证AUTH_KEY,提取目标URL,通过WORKER_URL转发
}
GAS中继功能:
  • 暴露一个公开HTTPS端点(
    /exec
    )作为域名前置中继
  • 对每个请求验证
    AUTH_KEY
  • 将验证通过的请求转发至你的Cloudflare Worker

Verifying It Works

验证代理有效性

After starting the proxy and configuring your browser:
  1. Visit ipleak.net — your IP should show as a Cloudflare IP
  2. Visit whoer.net — should reflect Cloudflare's location
  3. Via curl:
    bash
    curl -x http://127.0.0.1:8085 https://ipleak.net/json/ | python3 -m json.tool
    Look for
    "ip"
    showing a Cloudflare address range.

启动代理并配置浏览器后:
  1. 访问ipleak.net — 你的IP应显示为Cloudflare IP
  2. 访问whoer.net — 应显示Cloudflare的地理位置
  3. 通过curl验证:
    bash
    curl -x http://127.0.0.1:8085 https://ipleak.net/json/ | python3 -m json.tool
    查看
    "ip"
    字段是否为Cloudflare地址段。

Troubleshooting

故障排查

Proxy starts but no traffic gets through

代理启动但无流量通过

  • Verify
    script_id
    in
    config.json
    is the Deployment ID, not the Script ID
  • Re-check that
    auth_key
    in
    config.json
    exactly matches
    AUTH_KEY
    in
    Code.gs
  • In GAS, confirm deployment is set to Execute as: Me and Who has access: Anyone
  • Try redeploying the GAS app — old deployments sometimes break
  • 确认
    config.json
    中的
    script_id
    部署ID,而非脚本ID
  • 再次检查
    config.json
    中的
    auth_key
    Code.gs
    中的
    AUTH_KEY
    完全一致
  • 在GAS中确认部署设置为执行身份:我访问权限:任何人
  • 尝试重新部署GAS应用 — 旧部署有时会失效

SSL errors

SSL错误

json
"verify_ssl": false
Set to
false
temporarily to diagnose. Re-enable for production use.
json
"verify_ssl": false
临时设置为
false
以排查问题。生产环境请重新启用。

pip install
fails (PyPI blocked)

pip install
失败(PyPI被屏蔽)

bash
pip install -r requirements.txt \
  -i https://mirror-pypi.runflare.com/simple/ \
  --trusted-host mirror-pypi.runflare.com
bash
pip install -r requirements.txt \
  -i https://mirror-pypi.runflare.com/simple/ \
  --trusted-host mirror-pypi.runflare.com

GAS quota exceeded

GAS配额耗尽

Google Apps Script has daily quotas (~20,000 URL fetch calls/day for free accounts). If the relay stops working mid-day:
  • Use a different Google account for a fresh GAS deployment
  • Deploy multiple GAS relays and alternate
    script_id
    values
Google Apps Script有每日配额(免费账户约20,000次URL调用/天)。若中继中途停止工作:
  • 使用其他Google账户重新部署GAS
  • 部署多个GAS中继并轮换
    script_id

Port already in use

端口已被占用

json
{
  "listen_port": 8086,
  "socks5_port": 1081
}
Change ports in
config.json
and update your browser/FoxyProxy settings.
json
{
  "listen_port": 8086,
  "socks5_port": 1081
}
config.json
中修改端口,并更新浏览器/FoxyProxy设置。

Cloudflare Worker errors (5xx)

Cloudflare Worker错误(5xx)

  • Check the worker is deployed and the
    WORKER_URL
    in
    Code.gs
    matches exactly
  • Visit
    https://your-worker.workers.dev
    directly in browser — should respond (even with an error page) rather than timeout
  • Check Cloudflare Worker logs in the dashboard under Workers & Pages > your worker > Logs
  • 检查Worker是否已部署,且
    Code.gs
    中的
    WORKER_URL
    完全匹配
  • 在浏览器中直接访问
    https://your-worker.workers.dev
    — 应能响应(即使是错误页面)而非超时
  • 在控制台的Workers & Pages > 你的worker > Logs中查看Cloudflare Worker日志

Debug logging

调试日志

json
"log_level": "DEBUG"
Restart
main.py
— you'll see each relay hop logged to stdout.

json
"log_level": "DEBUG"
重启
main.py
— 你将在标准输出中看到每个中继步骤的日志。

Environment Variable Pattern for Automation

自动化环境变量配置模式

When scripting deployment or CI, avoid hardcoding secrets. Use environment variables and generate config dynamically:
python
import json
import os

config = {
    "mode": "apps_script",
    "google_ip": "216.239.38.120",
    "front_domain": "www.google.com",
    "script_id": os.environ["GAS_DEPLOYMENT_ID"],
    "auth_key": os.environ["MHR_AUTH_KEY"],
    "listen_host": "127.0.0.1",
    "listen_port": int(os.environ.get("MHR_PORT", "8085")),
    "socks5_enabled": True,
    "socks5_port": 1080,
    "log_level": os.environ.get("MHR_LOG_LEVEL", "INFO"),
    "verify_ssl": True
}

with open("config.json", "w") as f:
    json.dump(config, f, indent=2)

print("config.json written")
Then run:
bash
export GAS_DEPLOYMENT_ID="AKfycbXXXXXXXXXXXXXX"
export MHR_AUTH_KEY="$(openssl rand -hex 32)"
python3 write_config.py
python3 main.py

编写部署脚本或CI流程时,避免硬编码密钥。使用环境变量动态生成配置:
python
import json
import os

config = {
    "mode": "apps_script",
    "google_ip": "216.239.38.120",
    "front_domain": "www.google.com",
    "script_id": os.environ["GAS_DEPLOYMENT_ID"],
    "auth_key": os.environ["MHR_AUTH_KEY"],
    "listen_host": "127.0.0.1",
    "listen_port": int(os.environ.get("MHR_PORT", "8085")),
    "socks5_enabled": True,
    "socks5_port": 1080,
    "log_level": os.environ.get("MHR_LOG_LEVEL", "INFO"),
    "verify_ssl": True
}

with open("config.json", "w") as f:
    json.dump(config, f, indent=2)

print("config.json written")
然后运行:
bash
export GAS_DEPLOYMENT_ID="AKfycbXXXXXXXXXXXXXX"
export MHR_AUTH_KEY="$(openssl rand -hex 32)"
python3 write_config.py
python3 main.py

Project File Reference

项目文件说明

FilePurpose
main.py
Entry point — starts HTTP and SOCKS5 proxy listeners
config.json
Runtime configuration (copy from
config.example.json
)
config.example.json
Template configuration with placeholder values
script/worker.js
Cloudflare Worker source — deploy to Cloudflare
script/Code.gs
Google Apps Script relay source — deploy to GAS
start.bat
Windows launcher
start.sh
Linux/macOS launcher
requirements.txt
Python dependencies
文件用途
main.py
入口文件 — 启动HTTP和SOCKS5代理监听
config.json
运行时配置(从
config.example.json
复制修改)
config.example.json
配置模板,包含占位符值
script/worker.js
Cloudflare Worker源码 — 部署至Cloudflare
script/Code.gs
Google Apps Script中继源码 — 部署至GAS
start.bat
Windows启动脚本
start.sh
Linux/macOS启动脚本
requirements.txt
Python依赖列表