mirror of
https://github.com/therealaleph/MasterHttpRelayVPN-RUST.git
synced 2026-05-18 05:44:35 +03:00
c12ffd4dd4
The val.town founder asked us not to promote using their service. This commit removes every val.town reference from the codebase and rewrites the exit-node guides to be platform-agnostic. Changes: - Renamed assets/exit_node/valtown.ts → assets/exit_node/exit_node.ts. TypeScript itself is unchanged — same web-standard Request/Response/ fetch API that runs on any serverless runtime. - Rewrote assets/exit_node/README.md and README.fa.md to recommend Deno Deploy as the primary host for users who want a free serverless TS endpoint, with fly.io and your-own-VPS as alternatives. CF Workers is explicitly called out as not-helpful (CF outbound is still on CF's flagged IP space). - Updated all val.town mentions in source comments (src/config.rs, src/domain_fronter.rs, src/bin/ui.rs) to neutral wording. - Updated config.exit-node.example.json `_comment` strings and the example URL. - Updated main README.md FAQ entries (Persian + English) and docs/guide.md / docs/guide.fa.md. - Old changelog files (v1.9.4 / v1.9.5 / v1.9.9) had val.town mentions retroactively replaced too — same redaction principle. - Bumped to v1.9.10 with a changelog noting the rename + Telegram channel brief format from earlier today. Users who already have an exit node deployed (on whichever host they picked) don't need to change anything — the wire protocol is identical and the renamed script is byte-identical to the old one. Tests: 179 lib + 35 tunnel-node green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
184 lines
8.5 KiB
Markdown
184 lines
8.5 KiB
Markdown
# Exit node — bypassing CF anti-bot for ChatGPT / Claude / Grok / X
|
|
|
|
Many Cloudflare-fronted services flag traffic from Google datacenter
|
|
IPs as bots and serve a Turnstile / CAPTCHA / 502 challenge instead of
|
|
the real page. `UrlFetchApp.fetch()` in Apps Script always exits from
|
|
Google's datacenter IP space, so for sites like:
|
|
|
|
- **chatgpt.com / openai.com**
|
|
- **claude.ai**
|
|
- **grok.com / x.com**
|
|
|
|
…mhrv-rs's normal apps_script-mode path returns errors like `Relay
|
|
error: json: key must be a string at line 2 column 1` or `502 Relay
|
|
error` because Code.gs is wrapping a CF challenge HTML page that the
|
|
client can't parse as relay JSON.
|
|
|
|
The **exit node** is a small TypeScript HTTP handler you deploy on a
|
|
serverless TypeScript host you control. It sits between Apps Script
|
|
and the destination, so the request chain becomes:
|
|
|
|
```
|
|
Browser ─┐ ┌─→ Destination
|
|
│ │ (chatgpt.com)
|
|
▼ │
|
|
mhrv-rs │
|
|
│ │
|
|
│ TLS to Google IP, SNI=www.google.com (DPI cover)│
|
|
▼ │
|
|
Apps Script (Google datacenter) │
|
|
│ │
|
|
│ UrlFetchApp.fetch(EXIT_NODE_URL) │
|
|
▼ │
|
|
your exit node (non-Google IP) │
|
|
│ │
|
|
│ fetch(real_url) │
|
|
└──────────────────────────────────────────────────┘
|
|
```
|
|
|
|
The destination sees the exit node's outbound IP, not a Google
|
|
datacenter IP. CF's anti-bot heuristic doesn't fire and the real page
|
|
comes back.
|
|
|
|
**Important property preserved:** the user-side leg (Iran ISP →
|
|
Apps Script) is unchanged. The ISP only sees TLS to a Google IP — the
|
|
second hop happens entirely inside Apps Script's outbound, invisible
|
|
from the user's network. The DPI evasion property mhrv-rs is built
|
|
around stays intact.
|
|
|
|
## Setup
|
|
|
|
The handler in [`exit_node.ts`](exit_node.ts) is plain TypeScript that
|
|
uses only web-standard APIs (`Request`, `Response`, `fetch`). It runs
|
|
on any platform with a serverless-fetch runtime.
|
|
|
|
### Generic steps (apply to every host)
|
|
|
|
1. **Open `exit_node.ts`** and replace the placeholder PSK at the top:
|
|
```ts
|
|
const PSK = "<your-strong-secret>";
|
|
```
|
|
Generate a strong secret with `openssl rand -hex 32`. **Do not leave
|
|
the placeholder** — the script is deliberately fail-closed (returns
|
|
503 on every request until the placeholder is replaced) so a fresh
|
|
deploy without configuration can't accidentally serve as an open
|
|
relay.
|
|
2. **Deploy** to your chosen host (see options below).
|
|
3. **Copy the public URL** of the deployed handler.
|
|
4. **In `mhrv-rs` config.json**, add an `exit_node` block:
|
|
```json
|
|
"exit_node": {
|
|
"enabled": true,
|
|
"relay_url": "https://your-deployed-exit-node.example.com",
|
|
"psk": "<the same PSK you set in step 1>",
|
|
"mode": "selective",
|
|
"hosts": ["chatgpt.com", "claude.ai", "x.com", "grok.com", "openai.com"]
|
|
}
|
|
```
|
|
5. **Restart mhrv-rs** (Disconnect + Connect, or kill + restart the
|
|
binary).
|
|
6. **Test** — open `chatgpt.com` or `grok.com` from a browser pointed
|
|
at mhrv-rs's proxy. You should see the real login page, not a CF
|
|
challenge.
|
|
|
|
A complete example config is at
|
|
[`config.exit-node.example.json`](../../config.exit-node.example.json)
|
|
in the repo root.
|
|
|
|
### Hosting options
|
|
|
|
The script is one self-contained file. Pick whichever host you can
|
|
sign up for and trust:
|
|
|
|
| Host | Notes |
|
|
|---|---|
|
|
| **Deno Deploy** ([deno.com/deploy](https://deno.com/deploy)) | Free tier covers personal use. Deploy via `deployctl deploy --prod exit_node.ts` or via GitHub Actions. Same web-standard API as the script expects. |
|
|
| **fly.io** | Free tier with limits. Wrap the handler in a thin server (`Deno.serve(handler)` for Deno or an Express wrapper for Node) + add a Dockerfile. Persistent IPs, picks geographic region. |
|
|
| **Your own VPS** | Run `deno run --allow-net wrapper.ts` where `wrapper.ts` does `Deno.serve({ port: 8443 }, handler)`. Most control, ~$3-5/mo. |
|
|
| **Cloudflare Workers** | **Doesn't help.** CF Workers exit through CF's own IP space, which CF anti-bot still flags as worker-internal traffic. |
|
|
|
|
For most users running locally, Deno Deploy is the fastest setup. For
|
|
a long-term deployment you control end-to-end, your own small VPS is
|
|
ideal.
|
|
|
|
## `selective` vs `full`
|
|
|
|
| Mode | What it does | When to use |
|
|
|---|---|---|
|
|
| `selective` (default) | Only hosts in `hosts` route via the exit node; everything else takes the normal Apps Script path | Recommended. The exit-node hop adds ~200-500ms per request, so reserve it for sites that actually need a non-Google IP. |
|
|
| `full` | Every request routes via the exit node | Only when your entire workload is CF-anti-bot affected, or when your exit node is faster than Apps Script on your network path (rare). Burns the exit node's runtime budget on sites that don't need it. |
|
|
|
|
## Behaviour on failure
|
|
|
|
If the exit node is unreachable, returns 5xx, or returns a malformed
|
|
response, mhrv-rs **automatically falls back to the regular Apps
|
|
Script relay**. The log shows a `warn: exit node failed for ... —
|
|
falling back to direct Apps Script` line. The CF-affected sites then
|
|
fail (CF challenge), but every other site keeps working — a downed
|
|
exit node doesn't take you fully offline.
|
|
|
|
## Security model
|
|
|
|
The PSK is the only thing keeping the deployed endpoint from being a
|
|
public open proxy. Treat it like a password:
|
|
|
|
- **Don't commit** the PSK to source control. Most TypeScript hosts
|
|
default deployed code to private; keep it that way.
|
|
- **Don't share publicly.** Anyone with both the URL and the PSK can
|
|
use the deployment as their own proxy and burn your runtime quota.
|
|
- **Rotate** if you suspect a leak. Change the PSK in the deployed
|
|
source, redeploy, then update `psk` in `mhrv-rs` config.json and
|
|
restart.
|
|
|
|
The script also includes a **loop guard** (refuses to fetch its own
|
|
host) and a **placeholder check** (returns 503 if `PSK ===
|
|
"CHANGE_ME_TO_A_STRONG_SECRET"`) so a fresh deploy without
|
|
configuration can't be accidentally served as an open relay.
|
|
|
|
## Why isn't this on by default?
|
|
|
|
- Adds ~200-500ms per request through the exit-node hop
|
|
- Burns the host's free-tier runtime quota
|
|
- No benefit for sites that don't have CF anti-bot
|
|
- Requires signing up for a separate third-party platform
|
|
|
|
So `enabled: false` is the default. Users who specifically need
|
|
ChatGPT / Claude / Grok opt in; everyone else runs lighter.
|
|
|
|
## Troubleshooting
|
|
|
|
**`exit node refused or errored: unauthorized`** — PSK mismatch.
|
|
Double-check `psk` in `config.json` matches the `PSK` constant in your
|
|
deployed source character-for-character. Whitespace and quoting
|
|
matter.
|
|
|
|
**`exit_node misconfigured: PSK is still the placeholder`** — you
|
|
forgot to replace `CHANGE_ME_TO_A_STRONG_SECRET` in the source. Edit
|
|
the deployed file, save, redeploy.
|
|
|
|
**`exit node failed for ...: connection refused`** — the URL is wrong
|
|
or the deployment isn't live. Verify by hitting the URL in a browser
|
|
— it should respond with `{"e":"method_not_allowed"}` (the script
|
|
expects POST).
|
|
|
|
**`exit node failed for ...: timeout`** — the host's outbound or the
|
|
destination is slow. Try a different region, or accept the latency
|
|
trade-off.
|
|
|
|
**Site still shows a CF challenge after enabling the exit node** —
|
|
CF has flagged your host's IP too. Some hosting providers' outbound
|
|
IP space is on CF's bot blocklist. Workarounds: try a different host
|
|
(your own VPS gives you a clean IP), or add the affected site to
|
|
`passthrough_hosts` to bypass the MITM and use your real ISP IP.
|
|
|
|
## See also
|
|
|
|
- [Persian (راهنمای فارسی)](README.fa.md) version of this doc
|
|
- [`exit_node.ts`](exit_node.ts) — the handler source (with hardening)
|
|
- [`config.exit-node.example.json`](../../config.exit-node.example.json)
|
|
— complete example mhrv-rs config
|
|
- Issue [#382](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/issues/382)
|
|
— canonical thread tracking Cloudflare anti-bot
|
|
- Issue [#309](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/issues/309)
|
|
— roadmap for CF WARP integration (alternative approach, longer-horizon)
|