mirror of
https://github.com/therealaleph/MasterHttpRelayVPN-RUST.git
synced 2026-05-18 05:44:35 +03:00
4aac9a793f
Two changes addressing user-reported issues today:
1. Exit-node feature ported from upstream masterking32@464a6e1d, with
hardening. Cloudflare-protected sites (chatgpt.com, claude.ai,
grok.com, x.com, openai.com) flag Google datacenter IPs as bots and
return Turnstile / CAPTCHA / 502 challenges. Apps Script's UrlFetchApp
exits from those IPs, so v1.9.3 surfaces these as "Relay error: json:
key must be a string..." with no apps_script-mode workaround.
Now a small TypeScript HTTP endpoint (assets/exit_node/valtown.ts)
deployed on val.town / Deno Deploy sits between Apps Script and the
destination. Chain: client → Apps Script (Google IP) → val.town
(non-Google IP) → destination. Destination sees val.town's IP, no
CF challenge.
Config:
"exit_node": {
"enabled": true,
"relay_url": "https://...web.val.run",
"psk": "<openssl rand -hex 32>",
"mode": "selective",
"hosts": ["chatgpt.com", "claude.ai", "x.com", "grok.com", "openai.com"]
}
Hardening over upstream: PSK fail-closed if still placeholder (fresh
deploy can't be open relay), loop guard (refuses fetch of own host),
explicit 503 on misconfigured. Fallback to direct Apps Script on exit
node failure (CF-affected sites fail, others keep working). Setup
docs in English + Persian at assets/exit_node/README*.md. Example
config at config.exit-node.example.json.
2. Removed the legacy `telegram` job from release.yml. With
TELEGRAM_NOTIFY_ENABLED repo var set to true, every release was
producing two duplicate APK posts on the main Telegram channel: the
old bundled-APK-on-main job AND the newer per-file files-channel
posts (telegram-publish-files.yml). Only the per-file flow is wanted.
Legacy job and its helper telegram_release_notify.py are gone.
Recoverable from git log if anyone needs the bundled pattern back.
169 mhrv-rs lib tests + 33 tunnel-node tests + UI build clean.
175 lines
9.8 KiB
Markdown
175 lines
9.8 KiB
Markdown
# Exit node — دور زدن CF anti-bot برای ChatGPT / Claude / Grok / X
|
|
|
|
بسیاری از سرویسهای پشت Cloudflare، traffic از رنج IP datacenter
|
|
گوگل را بهعنوان bot flag میکنن + بهجای صفحه واقعی یک Turnstile /
|
|
CAPTCHA / 502 challenge میفرستن. `UrlFetchApp.fetch()` در Apps
|
|
Script از همان رنج IP datacenter Google خروج میکنه، پس برای سایتهایی مانند:
|
|
|
|
- **chatgpt.com / openai.com**
|
|
- **claude.ai**
|
|
- **grok.com / x.com**
|
|
|
|
…مسیر apps_script-mode عادی mhrv-rs ارورهایی مثل
|
|
`Relay error: json: key must be a string at line 2 column 1` یا
|
|
`502 Relay error` میده چون Code.gs در حال wrap کردن صفحهی HTML
|
|
challenge CF است که کلاینت نمیتونه parse کنه.
|
|
|
|
**Exit node** یک endpoint کوچک TypeScript HTTP است که روی یک پلتفرم
|
|
serverless (val.town، Deno Deploy، fly.io، …) deploy میشه + بین Apps
|
|
Script و destination قرار میگیره. مسیر traffic این میشه:
|
|
|
|
```
|
|
Browser ─┐ ┌─→ Destination
|
|
│ │ (chatgpt.com)
|
|
▼ │
|
|
mhrv-rs │
|
|
│ │
|
|
│ TLS به Google IP، SNI=www.google.com (DPI cover)│
|
|
▼ │
|
|
Apps Script (Google datacenter) │
|
|
│ │
|
|
│ UrlFetchApp.fetch(EXIT_NODE_URL) │
|
|
▼ │
|
|
val.town (non-Google IP) │
|
|
│ │
|
|
│ fetch(real_url) │
|
|
└──────────────────────────────────────────────────┘
|
|
```
|
|
|
|
Destination IP val.town رو میبینه، نه Google datacenter. heuristic
|
|
anti-bot CF نمیسوزه + صفحه واقعی برمیگرده.
|
|
|
|
**نکته مهم:** leg user-side (Iran ISP → Apps Script) **بدون تغییر**
|
|
است. ISP فقط TLS به Google IP میبینه — second hop کاملاً درون
|
|
outbound Apps Script اجرا میشه، invisible از شبکهی کاربر. پس DPI
|
|
evasion property که mhrv-rs براش ساخته شده، دست نمیخوره.
|
|
|
|
## راهاندازی
|
|
|
|
1. **در [val.town](https://val.town) ثبتنام کنید** (free tier کافی
|
|
است — bandwidth outbound free tier برای personal use کافی).
|
|
2. **یک HTTP val جدید بسازید** (TypeScript). در val.town: New → HTTP.
|
|
3. **محتوای `valtown.ts`** از این directory رو paste کنید.
|
|
4. **PSK رو در بالای فایل تنظیم کنید**:
|
|
```ts
|
|
const PSK = "<your-strong-secret>";
|
|
```
|
|
Strong secret تولید کنید با `openssl rand -hex 32` از terminal.
|
|
**placeholder رو در production نگذارید** — کد val.town عمداً
|
|
fail-closed است (در هر request 503 برمیگردونه) تا placeholder
|
|
replace نشده، تا جلوی serve شدن بهعنوان open relay accidentally
|
|
گرفته بشه.
|
|
5. **Save** کنید val رو. URL public val رو copy کنید — به این شکل:
|
|
`https://your-handle-mhrv.web.val.run`.
|
|
6. **در `config.json` mhrv-rs**، block `exit_node` اضافه کنید:
|
|
```json
|
|
"exit_node": {
|
|
"enabled": true,
|
|
"relay_url": "https://your-handle-mhrv.web.val.run",
|
|
"psk": "<همان PSK که در گام 4 گذاشتید>",
|
|
"mode": "selective",
|
|
"hosts": ["chatgpt.com", "claude.ai", "x.com", "grok.com", "openai.com"]
|
|
}
|
|
```
|
|
7. **mhrv-rs رو restart کنید** (Disconnect + Connect، یا `kill` +
|
|
restart binary).
|
|
8. **تست کنید** — `chatgpt.com` یا `grok.com` رو از browser pointed به
|
|
mhrv-rs proxy باز کنید. صفحه login واقعی رو میبینید، نه CF challenge.
|
|
|
|
config مثال کامل در
|
|
[`config.exit-node.example.json`](../../config.exit-node.example.json)
|
|
در root repo.
|
|
|
|
## انتخاب `selective` vs `full`
|
|
|
|
| Mode | چی میکنه | کی استفاده کنید |
|
|
|---|---|---|
|
|
| `selective` (default) | فقط hosts در `hosts` از طریق exit node میرن؛ بقیه از مسیر Apps Script عادی | توصیه میشه. exit-node hop ~۲۰۰-۵۰۰ms به هر request اضافه میکنه — برای سایتهایی reserve کنید که نیاز به non-Google IP دارن. |
|
|
| `full` | همهی requestها از طریق exit node میرن | فقط زمانی که کل workload شما CF-anti-bot affected است، یا exit node خود از Apps Script سریعتر روی مسیر شبکه شما (rare). budget runtime val.town رو برای سایتهایی که نیاز ندارن میسوزونه. |
|
|
|
|
## رفتار در صورت failure
|
|
|
|
اگر exit node در دسترس نباشه، 5xx برمیگردونه، یا response malformed
|
|
بفرسته، mhrv-rs **بهطور خودکار به Apps Script relay عادی fallback
|
|
میکنه**. در log یک خط `warn: exit node failed for ... — falling back
|
|
to direct Apps Script` میبینید. سایتهایی که نیاز به exit node دارن در آن
|
|
case fail میگیرن (CF challenge)، ولی سایر سایتها کار میکنن — یک
|
|
exit node down شما رو fully offline نمیکنه.
|
|
|
|
## Security model
|
|
|
|
PSK تنها چیز است که مانع میشه val.town endpoint یک public open proxy
|
|
بشه. مثل password برخورد کنید:
|
|
|
|
- **commit نکنید** PSK رو به source control. منبع val.town بهطور
|
|
default برای account شما private است؛ همانطور نگه دارید.
|
|
- **publicly share نکنید** PSK رو. هر کسی که هم URL هم PSK رو داره
|
|
میتونه quota val.town شما رو بهعنوان proxy خود استفاده کنه.
|
|
- **rotate** اگر leak مشکوک هست. PSK رو در val.town source تغییر بدید،
|
|
save کنید، سپس `psk` در `config.json` mhrv-rs رو update + restart.
|
|
|
|
اسکریپت val.town شامل **loop guard** هم هست (refuse میکنه fetch host
|
|
خود) + **placeholder check** (در صورت `PSK === "CHANGE_ME_TO_A_STRONG_SECRET"`
|
|
return 503 میکنه) تا یک fresh deploy بدون setup نتونه بهطور
|
|
accidentally بهعنوان open relay سرو بشه.
|
|
|
|
## پلتفرمهای جایگزین
|
|
|
|
اسکریپت `valtown.ts` plain TypeScript است که از web-standard APIs
|
|
(`Request`، `Response`، `fetch`) استفاده میکنه. اجرا میشه روی:
|
|
|
|
- **val.town** — سادهترین، free tier کافی برای personal use
|
|
- **Deno Deploy** — API مشابه؛ deploy با `deployctl`
|
|
- **fly.io** — نیاز به `Dockerfile` wrapper؛ region geographic ثابت
|
|
- **Cloudflare Workers** — کمک نمیکنه (CF Workers از IP space خود CF
|
|
خروج میکنن، که CF anti-bot هنوز بهعنوان worker-internal flag میکنه)
|
|
|
|
برای اکثر کاربران، val.town انتخاب درست است. Deno Deploy اگر option
|
|
non-val.town برای redundancy میخواید.
|
|
|
|
## چرا default-on نیست
|
|
|
|
- ۲۰۰-۵۰۰ms به هر request اضافه میکنه (hop اضافی)
|
|
- budget bandwidth free-tier val.town رو میسوزونه
|
|
- برای سایتهایی که CF anti-bot ندارن benefit نداره
|
|
- Setup یک account جداگانه روی پلتفرم third-party میخواد
|
|
|
|
پس `enabled: false` default است. کاربرانی که خصوصاً به ChatGPT / Claude /
|
|
Grok اهمیت میدن opt in؛ همهی دیگران lighter اجرا میکنن.
|
|
|
|
## Troubleshooting
|
|
|
|
**`exit node refused or errored: unauthorized`** — PSK mismatch.
|
|
بررسی کنید `psk` در `config.json` دقیقاً با `PSK` constant در val.town
|
|
match هست. whitespace + quoting مهم است.
|
|
|
|
**`exit node refused or errored: exit_node misconfigured: PSK is still
|
|
the placeholder`** — فراموش کردید `CHANGE_ME_TO_A_STRONG_SECRET` رو
|
|
در val.town جایگزین کنید. val رو edit + save کنید.
|
|
|
|
**`exit node failed for ...: connection refused`** — URL val.town
|
|
اشتباه است یا val deploy نشده. با hit کردن URL مستقیم از browser
|
|
verify کنید — باید `{"e":"method_not_allowed"}` برگردونه (val expects
|
|
POST).
|
|
|
|
**`exit node failed for ...: timeout`** — outbound val.town slow است
|
|
یا destination slow. region val.town متفاوت رو امتحان کنید، یا latency
|
|
trade-off رو accept کنید.
|
|
|
|
**سایت همچنان CF challenge نشون میده بعد از enable exit node** — CF
|
|
IP val.town رو هم flag میکنه. برخی customers CF صراحتاً val.town رو
|
|
blocklist کردن. workarounds: Deno Deploy رو امتحان کنید، یا سایت رو
|
|
به `passthrough_hosts` اضافه کنید (MITM رو bypass میکنه؛ از real
|
|
IP ISP شما استفاده میکنه).
|
|
|
|
## همچنین ببینید
|
|
|
|
- [English version](README.md) of this doc
|
|
- [`valtown.ts`](valtown.ts) — منبع val.town (با hardening)
|
|
- [`config.exit-node.example.json`](../../config.exit-node.example.json)
|
|
— config مثال کامل
|
|
- Issue [#382](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/issues/382)
|
|
— thread tracking canonical Cloudflare anti-bot
|
|
- Issue [#309](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/issues/309)
|
|
— roadmap CF WARP integration (approach جایگزین، longer-horizon)
|