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>
11 KiB
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 یک handler کوچک HTTP به زبان TypeScript است که روی یک پلتفرم serverless TypeScript که خودت تأییدش میکنی 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) │
▼ │
exit node خودت (IP غیر گوگل) │
│ │
│ fetch(real_url) │
└──────────────────────────────────────────────────┘
Destination IP خروجی exit node رو میبینه، نه IP 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 براش ساخته شده، دست نمیخوره.
راهاندازی
handler در exit_node.ts plain TypeScript است که از
APIهای web-standard (Request، Response، fetch) استفاده میکنه و
روی هر پلتفرمی که serverless-fetch runtime داره اجرا میشه.
مراحل عمومی (روی هر host)
۱. فایل exit_node.ts رو باز کنید و PSK پیشفرض رو در
ابتدا عوض کنید:
const PSK = "<your-strong-secret>";
Strong secret تولید کنید با openssl rand -hex 32 از terminal.
placeholder رو در production نگذارید — کد عمداً fail-closed است
(در هر request 503 برمیگردونه) تا placeholder replace نشده، تا
جلوی serve شدن بهعنوان open relay accidentally گرفته بشه.
۲. فایل رو روی host انتخابی deploy کنید (گزینهها در ادامه).
۳. URL public deployment رو copy کنید.
۴. در config.json mhrv-rs، block exit_node اضافه کنید:
"exit_node": {
"enabled": true,
"relay_url": "https://your-deployed-exit-node.example.com",
"psk": "<همان PSK که در گام ۱ گذاشتید>",
"mode": "selective",
"hosts": ["chatgpt.com", "claude.ai", "x.com", "grok.com", "openai.com"]
}
۵. mhrv-rs رو restart کنید (Disconnect + Connect، یا kill +
restart binary).
۶. تست کنید — chatgpt.com یا grok.com رو از browser pointed به
mhrv-rs proxy باز کنید. صفحه login واقعی رو میبینید، نه CF
challenge.
config مثال کامل در
config.exit-node.example.json
در root repo.
گزینههای hosting
اسکریپت یک فایل self-contained است. هر host که میتوانید signup کنید + بهاش اعتماد دارید رو انتخاب کنید:
| Host | توضیحات |
|---|---|
| Deno Deploy (deno.com/deploy) | free tier برای personal use کافی است. با deployctl deploy --prod exit_node.ts یا GitHub Actions deploy کنید. همان web-standard API. |
| fly.io | free tier با محدودیت. handler رو در یک server thin بستهبندی کنید (Deno.serve(handler) برای Deno یا یک Express wrapper برای Node) + Dockerfile اضافه کنید. IP دائم، region جغرافیایی قابل انتخاب. |
| VPS شخصی خودت | deno run --allow-net wrapper.ts که wrapper.ts کارش Deno.serve({ port: 8443 }, handler) است. حداکثر کنترل، ~۳-۵ دلار در ماه. |
| Cloudflare Workers | کمک نمیکنه. CF Workers از IP space خود CF خروج میکنن، که CF anti-bot هنوز بهعنوان worker-internal flag میکنه. |
برای اکثر کاربرانی که مسیر local رو اجرا میکنن، Deno Deploy سریعترین setup است. برای deployment طولانیمدت تحت کنترل کامل خودت، VPS کوچک شخصی ایدهآل است.
انتخاب 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 خود سریعتر روی مسیر شبکه شما (rare). budget runtime host رو برای سایتهایی که نیاز ندارن میسوزونه. |
رفتار در صورت 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 تنها چیز است که مانع میشه endpoint deployed یک public open proxy بشه. مثل password برخورد کنید:
- commit نکنید PSK رو به source control. اکثر hostها بهطور default کد deployed رو private نگه میدارن؛ همانطور نگه دارید.
- publicly share نکنید PSK رو. هر کسی که هم URL هم PSK رو داره میتونه quota host شما رو بهعنوان proxy خود استفاده کنه.
- rotate اگر leak مشکوک هست. PSK رو در source deployed تغییر بدید،
redeploy کنید، سپس
pskدرconfig.jsonmhrv-rs رو update + restart.
اسکریپت همچنین شامل loop guard هست (refuse میکنه fetch host خود)
- placeholder check (در صورت
PSK === "CHANGE_ME_TO_A_STRONG_SECRET"return 503 میکنه) تا یک fresh deploy بدون setup نتونه بهطور accidentally بهعنوان open relay سرو بشه.
چرا default-on نیست
- ۲۰۰-۵۰۰ms به هر request اضافه میکنه (hop اضافی)
- budget bandwidth free-tier host رو میسوزونه
- برای سایتهایی که 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 در source
deployed match هست. whitespace + quoting مهم است.
exit node refused or errored: exit_node misconfigured: PSK is still the placeholder — فراموش کردید CHANGE_ME_TO_A_STRONG_SECRET رو
در source جایگزین کنید. فایل deployed رو edit + save + redeploy کنید.
exit node failed for ...: connection refused — URL اشتباه است
یا deployment live نیست. با hit کردن URL مستقیم از browser verify
کنید — باید {"e":"method_not_allowed"} برگردونه (handler expects
POST).
exit node failed for ...: timeout — outbound host slow است
یا destination slow. region متفاوت رو امتحان کنید، یا latency
trade-off رو accept کنید.
سایت همچنان CF challenge نشون میده بعد از enable exit node — CF
IP host شما رو هم flag کرده. بعضی hosting providerها outbound IP
spaceشون روی CF bot blocklist است. workarounds: host دیگه امتحان
کنید (VPS شخصی شما clean IP میده)، یا سایت رو به passthrough_hosts
اضافه کنید (MITM رو bypass میکنه؛ از real IP ISP شما استفاده
میکنه).
همچنین ببینید
- English version of this doc
exit_node.ts— منبع handler (با hardening)config.exit-node.example.json— config مثال کامل- Issue #382 — thread tracking canonical Cloudflare anti-bot
- Issue #309 — roadmap CF WARP integration (approach جایگزین، longer-horizon)