mhr-cfw: The Proxy That Hides Behind Google, Then Escapes Through Cloudflare

A deep dive into a two-hop domain-fronting relay that turns Google Apps Script and Cloudflare Workers into a censorship workaround, with HTTP/2 multiplexing, SNI rotation, and latency tricks that make the disguise usable.

10 min read View on GitHub More from denuitt1

A wide editorial scene shows a traveler carrying a sealed packet through a public counter labeled Google, then out through a second corridor labeled Cloudflare, while a censor watches only the first entrance. The image explains the project’s core idea: the visible destination is not the real exit.
The trick is not just hiding traffic. It is separating the visible front door from the actual exit.
Key Takeaways

The proxy that looks like Google

The unusual thing about mhr-cfw is not that it proxies traffic. It is that the proxy is deliberately split across surfaces that look ordinary to a censor. A local client talks to a local proxy, the proxy disguises the request as Google-bound traffic, Google Apps Script forwards it, and Cloudflare Worker finishes the job.

That shape matters more than the individual hops. If you only look for a single exit node, you miss the point. The system is trying to make blocking decisions expensive, politically awkward, and technically messy.

One request mutates as it moves. The visible front and the real exit are intentionally separated.

A Domain-Fronting Relay that routes traffic though GAS (Google Apps Script) and forwards it to Cloudflare Workers. Designed to bypass DPI.

denuitt1, Project Author · denuitt1/mhr-cfw README

Why this shape is hard to block

Single-hop relays are easier to reason about and easier to ban. This project adds a second cloud boundary, which means the censor is no longer staring at a neat single target. It is choosing between broad collateral damage and a narrower block that may fail to catch the real path.

OptionBlocking riskSetup burdenPerformanceFit for hostile networks
Worker-only proxyOne provider can be targeted directlyLowUsually goodModerate
GAS-only proxyGoogle surface can be targeted or quota-limitedLow to mediumOften unevenModerate
mhr-cfwTwo huge providers must be handled togetherHighBetter than it sounds after optimizationHigh
Tor MeekDepends on Tor fronting infrastructureMedium to highVariableHigh
GoodbyeDPINo remote provider to blockLowFast locally, limited by network modelMedium

How the local proxy works

The local side is practical rather than glamorous. `proxy_server.py` handles proxying, while `mitm.py` generates certificates on the fly so HTTPS traffic can be decrypted, repackaged, and forwarded. That MITM step is not optional. You cannot front encrypted traffic you cannot inspect.

The local cache matters too. Static assets are expensive to relay repeatedly, so the proxy keeps common responses around instead of paying the full path cost every time. That is the difference between a proof of concept and a tool someone can actually live with.

The relay engine is the real invention

`domain_fronter.py` is where the project stops being a wrapper and becomes an engine. It rotates SNI values, races multiple Apps Script endpoints in parallel, and takes the fastest successful relay. The goal is not just to pass traffic. It is to shorten the ugly tail that usually makes censorship work feel unusable.

A close-up switchboard shows several narrow relay lanes sprinting toward one target channel while a broken clock hangs above them. One lane lights up first and flips a selector lever, illustrating how the system races multiple Google Apps Script paths and chooses the fastest result.
The project is not only hiding traffic. It is also racing candidate relays to cut tail latency.

Why HTTP/2 matters here

`h2_transport.py` is the efficiency layer that keeps the whole design from collapsing under its own ceremony. A persistent TLS tunnel carrying many requests changes the economics of the connection. You are not paying the handshake tax over and over, and you are not advertising a new connection pattern for every asset.

That is why the project feels more engineered than improvised. The obvious trick is domain fronting. The less obvious trick is making the disguised path behave enough like a normal service session that it can survive real use.

The cloud-side relay chain

On the cloud side, `Code.gs` and `worker.js` split the work. Google Apps Script batches and forwards. Cloudflare Worker fetches the target, handles binary data with Base64, and guards against loops with relay-hop checks. The result is a chain that can absorb traffic without forcing every stage to understand everything.

LayerJobWhy it exists
Google Apps ScriptBatch, validate, forwardIt gives the traffic a Google-shaped front door.
Cloudflare WorkerFetch the target and return bytesIt provides a separate exit that is hard to isolate cleanly.
Local MITM proxyDecrypt and repackage trafficIt makes HTTPS relayable without giving up inspection.
HTTP/2 tunnelMultiplex many requestsIt reduces overhead and smooths the traffic signature.

What it beats, and what it does not

mhr-cfw is strongest when the problem is not raw speed but survivable access. It is more resilient than a single-provider proxy because its blocking surface is split. It is more specialized than broad privacy tools because it assumes you are already in a hostile network and willing to accept setup pain.

ToolMain strengthMain weakness
mhr-cfwTwo-hop disguise with latency optimizationComplex setup and dependence on two platforms
Cloudflare Worker-only relaySimple deploymentEasy to target at one provider boundary
Google Apps Script-only relayUseful fronting surfaceQuotas and performance ceiling
Tor MeekMature censorship-evasion modelHeavier ecosystem and different use case
GoodbyeDPINo remote infrastructureLess effective against stronger filtering

The tradeoff is the point

This is not casual infrastructure. It is a specialist response to networks that treat normal encrypted traffic as suspect. The project is compelling because it shows how far you can get by repurposing trusted SaaS surfaces and then spending real engineering effort to make that disguise fast enough to use.

That is the lesson here. Clever routing is easy to admire. Making it survive contact with a real user is the hard part.