From b3df1d382819fb9ed2d98b89df8a838a5933f24f Mon Sep 17 00:00:00 2001 From: Abolfazl Date: Mon, 4 May 2026 22:46:37 +0330 Subject: [PATCH] refactor: remove Val Town references and update exit node documentation --- README.md | 22 +++--- README_FA.md | 18 +++-- apps_script/valtown.ts | 88 ----------------------- docs/exit-node/EXIT_NODE_DEPLOYMENT.md | 30 +++----- docs/exit-node/EXIT_NODE_DEPLOYMENT_FA.md | 48 ++++++++----- src/relay/domain_fronter.py | 8 +-- 6 files changed, 56 insertions(+), 158 deletions(-) delete mode 100644 apps_script/valtown.ts diff --git a/README.md b/README.md index 66892ca..5e75d62 100644 --- a/README.md +++ b/README.md @@ -174,15 +174,14 @@ Some websites block Google datacenter IPs when traffic exits directly from Apps To fix that, configure an exit node so traffic path becomes: ```text -Browser -> Local Proxy -> Apps Script -> Exit Node (Val Town / Cloudflare / Deno) -> Target website +Browser -> Local Proxy -> Apps Script -> Exit Node (Cloudflare / Deno / VPS) -> Target website ``` -You can deploy any one of these free exit-node templates: +You can deploy any one of these exit-node backends: -1. Val Town: [`apps_script/valtown.ts`](apps_script/valtown.ts) -2. Cloudflare Workers: [`apps_script/cloudflare_worker.js`](apps_script/cloudflare_worker.js) -3. Deno Deploy: [`apps_script/deno_deploy.ts`](apps_script/deno_deploy.ts) -4. Your own VPS server +1. Cloudflare Workers: [`apps_script/cloudflare_worker.js`](apps_script/cloudflare_worker.js) +2. Deno Deploy: [`apps_script/deno_deploy.ts`](apps_script/deno_deploy.ts) +3. Your own VPS server Full step-by-step deployment guide (all providers): - [docs/exit-node/EXIT_NODE_DEPLOYMENT.md](docs/exit-node/EXIT_NODE_DEPLOYMENT.md) @@ -194,8 +193,8 @@ Then configure provider switching like this: ```json "exit_node": { "enabled": true, - "provider": "valtown", - "url": "https://YOUR-NAME.web.val.run", + "provider": "cloudflare", + "url": "https://YOUR-WORKER.YOUR-SUBDOMAIN.workers.dev", "psk": "CHANGE_ME_TO_A_STRONG_SECRET", "mode": "full", "hosts": [ @@ -218,7 +217,7 @@ Production recommendation: - Keep `verify_ssl: true` - Keep `listen_host: 127.0.0.1` unless LAN sharing is explicitly needed - Rotate both secrets periodically -- Never publish your live val URL with valid PSK +- Never publish your live exit-node URL with valid PSK ### Step 4: Run @@ -311,7 +310,7 @@ By default, the proxy only listens on `127.0.0.1` (localhost), meaning only your ## Modes Overview -This project is centered on the **Apps Script** relay (free, no VPS needed). For destinations that block Google egress, you can optionally chain a free edge exit node (Val Town, Cloudflare Workers, or Deno Deploy). +This project is centered on the **Apps Script** relay (free, no VPS needed). For destinations that block Google egress, you can optionally chain an edge exit node (Cloudflare Workers, Deno Deploy, or your own VPS). --- @@ -350,7 +349,7 @@ This project is centered on the **Apps Script** relay (free, no VPS needed). For | `direct_google_exclude` | see [config.example.json](config.example.json) | Google apps that must use the MITM relay path instead of the fast direct tunnel. | | `hosts` | `{}` | Manual DNS override: map a hostname to a specific IP. | | `youtube_via_relay` | `false` | Route YouTube (`youtube.com`, `youtu.be`, `youtube-nocookie.com`) through the Apps Script relay instead of the SNI-rewrite path. The SNI-rewrite path uses Google's frontend IP which enforces SafeSearch and can cause **"Video Unavailable"** errors. Setting this to `true` fixes playback at the cost of using more Apps Script executions and slightly higher latency. | -| `exit_node.provider` | `valtown` | Selected exit-node backend: `valtown`, `cloudflare`, `deno`, or `custom`. | +| `exit_node.provider` | `cloudflare` | Selected exit-node backend: `cloudflare`, `deno`, `vps`, or `custom`. | | `exit_node.url` | `""` | Beginner-friendly single URL for the selected provider. | ### Optional Dependencies @@ -472,7 +471,6 @@ MasterHttpRelayVPN/ ├── requirements.txt # Python dependencies ├── apps_script/ │ ├── Code.gs # The relay script you deploy to Google Apps Script -│ ├── valtown.ts # Exit node template for val.town │ ├── cloudflare_worker.js # Exit node template for Cloudflare Workers │ └── deno_deploy.ts # Exit node template for Deno Deploy ├── ca/ # Generated MITM CA (do NOT share) diff --git a/README_FA.md b/README_FA.md index 21d2595..f5da2c4 100644 --- a/README_FA.md +++ b/README_FA.md @@ -137,15 +137,14 @@ cp config.example.json config.json برای حل این مورد، نود خروجی (exit node) را فعال کنید تا مسیر این‌گونه شود: ```text -مرورگر -> پراکسی محلی -> Apps Script -> Exit Node (Val Town / Cloudflare / Deno) -> سایت مقصد +مرورگر -> پراکسی محلی -> Apps Script -> Exit Node (Cloudflare / Deno / VPS) -> سایت مقصد ``` -می‌توانید یکی از این template های رایگان را deploy کنید: +می‌توانید یکی از این backend های نود خروجی را deploy کنید: -1. Val Town: [apps_script/valtown.ts](apps_script/valtown.ts) -2. Cloudflare Workers: [apps_script/cloudflare_worker.js](apps_script/cloudflare_worker.js) -3. Deno Deploy: [apps_script/deno_deploy.ts](apps_script/deno_deploy.ts) -4. سرور VPS شخصی +1. Cloudflare Workers: [apps_script/cloudflare_worker.js](apps_script/cloudflare_worker.js) +2. Deno Deploy: [apps_script/deno_deploy.ts](apps_script/deno_deploy.ts) +3. سرور VPS شخصی راهنمای کامل مرحله‌به‌مرحله برای هر provider: - [docs/exit-node/EXIT_NODE_DEPLOYMENT_FA.md](docs/exit-node/EXIT_NODE_DEPLOYMENT_FA.md) (فارسی) @@ -158,8 +157,8 @@ cp config.example.json config.json ```json "exit_node": { "enabled": true, - "provider": "valtown", - "url": "https://YOUR-NAME.web.val.run", + "provider": "cloudflare", + "url": "https://YOUR-WORKER.YOUR-SUBDOMAIN.workers.dev", "psk": "CHANGE_ME_TO_A_STRONG_SECRET", "mode": "full", "hosts": [ @@ -294,7 +293,7 @@ json | `bypass_hosts` | `["localhost", ".local", ".lan", ".home.arpa"]` | هاست‌هایی که مستقیم می‌روند (بدون MITM و بدون رله). برای منابع داخلی شبکه یا سایت‌هایی که با MITM مشکل دارند. | | `direct_google_exclude` | مراجعه به [config.example.json](config.example.json) | اپ‌های Google که باید از مسیر MITM برای رله استفاده کنند به‌جای tunnel مستقیم. | | `youtube_via_relay` | `false` | مسیردهی YouTube (`youtube.com`، `youtu.be`، `youtube-nocookie.com`) از طریق رله Apps Script به‌جای مسیر SNI-rewrite. مسیر SNI-rewrite از IP فرانت‌اند Google عبور می‌کند که SafeSearch را اجباری می‌کند و می‌تواند باعث خطای **«ویدیو در دسترس نیست»** شود. با فعال کردن این گزینه، پخش ویدیو درست می‌شود اما تعداد اجراهای Apps Script بیشتر و تأخیر اندکی بالاتر می‌رود. | -| `exit_node.provider` | `valtown` | backend انتخاب‌شده برای exit node: `valtown`، `cloudflare`، `deno` یا `custom`. | +| `exit_node.provider` | `cloudflare` | backend انتخاب‌شده برای exit node: `cloudflare`، `deno`، `vps` یا `custom`. | | `exit_node.url` | `""` | آدرس ساده و اصلی برای provider انتخاب‌شده. | ### وابستگی‌های اختیاری @@ -411,7 +410,6 @@ MasterHttpRelayVPN/ ├── requirements.txt # وابستگی‌های اختیاری پایتون ├── apps_script/ │ ├── Code.gs # اسکریپت رله روی Google Apps Script -│ ├── valtown.ts # template نود خروجی برای val.town │ ├── cloudflare_worker.js # template نود خروجی برای Cloudflare Workers │ └── deno_deploy.ts # template نود خروجی برای Deno Deploy ├── ca/ # گواهی MITM (هرگز به اشتراک نگذارید) diff --git a/apps_script/valtown.ts b/apps_script/valtown.ts deleted file mode 100644 index 1e01bbd..0000000 --- a/apps_script/valtown.ts +++ /dev/null @@ -1,88 +0,0 @@ -const PSK = "CHANGE_ME_TO_A_STRONG_SECRET"; - -const STRIP_HEADERS = new Set([ - "host", - "connection", - "content-length", - "transfer-encoding", - "proxy-connection", - "proxy-authorization", - "x-forwarded-for", - "x-forwarded-host", - "x-forwarded-proto", - "x-forwarded-port", - "x-real-ip", - "forwarded", - "via", -]); - -function decodeBase64ToBytes(input: string): Uint8Array { - const bin = atob(input); - const out = new Uint8Array(bin.length); - for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i); - return out; -} - -function encodeBytesToBase64(bytes: Uint8Array): string { - let bin = ""; - for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]); - return btoa(bin); -} - -function sanitizeHeaders(h: unknown): Record { - const out: Record = {}; - if (!h || typeof h !== "object") return out; - for (const [k, v] of Object.entries(h as Record)) { - if (!k) continue; - if (STRIP_HEADERS.has(k.toLowerCase())) continue; - out[k] = String(v ?? ""); - } - return out; -} - -export default async function(req: Request): Promise { - try { - if (req.method !== "POST") { - return Response.json({ e: "method_not_allowed" }, { status: 405 }); - } - - const body = await req.json(); - if (!body || typeof body !== "object") { - return Response.json({ e: "bad_json" }, { status: 400 }); - } - - const k = String((body as any).k ?? ""); - const u = String((body as any).u ?? ""); - const m = String((body as any).m ?? "GET").toUpperCase(); - const h = sanitizeHeaders((body as any).h); - const b64 = (body as any).b; - - if (k !== PSK) return Response.json({ e: "unauthorized" }, { status: 401 }); - if (!/^https?:\/\//i.test(u)) return Response.json({ e: "bad url" }, { status: 400 }); - - let payload: Uint8Array | undefined; - if (typeof b64 === "string" && b64.length > 0) payload = decodeBase64ToBytes(b64); - - const resp = await fetch(u, { - method: m, - headers: h, - body: payload, - redirect: "manual", - }); - - const data = new Uint8Array(await resp.arrayBuffer()); - const respHeaders: Record = {}; - resp.headers.forEach((value, key) => { - respHeaders[key] = value; - }); - - return Response.json({ - s: resp.status, - h: respHeaders, - b: encodeBytesToBase64(data), - }); - } catch (err) { - const message = err instanceof Error ? err.message : String(err); - return Response.json({ e: message }, { status: 500 }); - } -} diff --git a/docs/exit-node/EXIT_NODE_DEPLOYMENT.md b/docs/exit-node/EXIT_NODE_DEPLOYMENT.md index f85144e..5a8e67b 100644 --- a/docs/exit-node/EXIT_NODE_DEPLOYMENT.md +++ b/docs/exit-node/EXIT_NODE_DEPLOYMENT.md @@ -1,4 +1,4 @@ -# Exit Node Deployment Guide (Val Town / Cloudflare / Deno / VPS) +# Exit Node Deployment Guide (Cloudflare / Deno / VPS) This guide explains how to deploy an exit node for MasterHttpRelayVPN on free platforms or your own VPS server. @@ -10,7 +10,6 @@ Use this when destinations block Google datacenter egress. ## 1) Choose One Provider -- Val Town (free, no server required) - Cloudflare Workers (free tier available) - Deno Deploy (free, not fully tested) - **Your Own VPS** (full control, Linux server — automated installer included) @@ -29,19 +28,7 @@ Important: - Use the same PSK in your local config under exit_node.psk. - Never share your deployed URL together with a valid PSK. -## 3) Deploy On Val Town - -Source file: apps_script/valtown.ts - -Steps: -1. Sign in at https://www.val.town -2. Create a new Val (TypeScript HTTP endpoint). -3. Paste content from apps_script/valtown.ts. -4. Set the PSK constant in the code. -5. Save and Add HTTP trigger. -6. Copy your public URL, usually like https://YOUR-NAME.web.val.run - -## 4) Deploy On Cloudflare Workers +## 3) Deploy On Cloudflare Workers Source file: apps_script/cloudflare_worker.js @@ -54,7 +41,7 @@ Steps: 6. Deploy. 7. Copy URL, usually like https://YOUR-WORKER.YOUR-SUBDOMAIN.workers.dev -## 5) Deploy On Deno Deploy (It's not tested Yet) +## 4) Deploy On Deno Deploy (It's not tested Yet) Source file: apps_script/deno_deploy.ts @@ -66,7 +53,7 @@ Steps: 5. Deploy. 6. Copy URL, usually like https://YOUR-PROJECT.deno.net -## 6) Deploy On Your Own VPS (Linux only) +## 5) Deploy On Your Own VPS (Linux only) Source files: - `apps_script/vps_exit_node.py` — the relay server @@ -94,16 +81,16 @@ The script automatically downloads `vps_exit_node.py` from GitHub, so no `git cl Note: - To rotate the PSK, edit `/etc/exit-node.env` and restart: `systemctl restart exit-node`. -## 7) Configure MasterHttpRelayVPN +## 6) Configure MasterHttpRelayVPN Update `config.json`: -For Val Town / Cloudflare / Deno: +For Cloudflare / Deno: ```json "exit_node": { "enabled": true, - "provider": "valtown", - "url": "https://YOUR-NAME.web.val.run", + "provider": "cloudflare", + "url": "https://YOUR-WORKER.YOUR-SUBDOMAIN.workers.dev", "psk": "CHANGE_ME_TO_A_STRONG_SECRET", "mode": "full", "hosts": [ @@ -133,7 +120,6 @@ For your own VPS: ``` Provider values: -- `valtown` - `cloudflare` - `deno` - `vps` diff --git a/docs/exit-node/EXIT_NODE_DEPLOYMENT_FA.md b/docs/exit-node/EXIT_NODE_DEPLOYMENT_FA.md index 1026cd6..9178853 100644 --- a/docs/exit-node/EXIT_NODE_DEPLOYMENT_FA.md +++ b/docs/exit-node/EXIT_NODE_DEPLOYMENT_FA.md @@ -1,4 +1,4 @@ -# راهنمای نصب نود خروجی (Val Town / Cloudflare / Deno) +# راهنمای نصب نود خروجی (Cloudflare / Deno / VPS) این راهنما توضیح می‌دهد چطور یک نود خروجی رایگان برای MasterHttpRelayVPN راه‌اندازی کنید. @@ -12,9 +12,9 @@ ## ۱) یک Provider انتخاب کنید -- Val Town - Cloudflare Workers - Deno Deploy +- VPS شخصی فقط به یکی از این‌ها نیاز دارید. @@ -32,19 +32,7 @@ const PSK = "CHANGE_ME_TO_A_STRONG_SECRET"; - همین PSK را در `config.json` زیر `exit_node.psk` وارد کنید. - URL عمومی را هرگز همراه با PSK معتبر به اشتراک نگذارید. -## ۳) نصب روی Val Town - -فایل: `apps_script/valtown.ts` - -مراحل: -1. در [https://www.val.town](https://www.val.town) ثبت‌نام کنید. -2. یک Val جدید بسازید (TypeScript HTTP endpoint). -3. محتوای `apps_script/valtown.ts` را paste کنید. -4. مقدار ثابت PSK را در کد تنظیم کنید. -5. ذخیره و deploy کنید. (Add HTTP trigger را فراموش نکنید) -6. URL عمومی خود را کپی کنید؛ معمولاً به شکل `https://YOUR-NAME.web.val.run` - -## ۴) نصب روی Cloudflare Workers +## ۳) نصب روی Cloudflare Workers فایل: `apps_script/cloudflare_worker.js` @@ -57,7 +45,7 @@ const PSK = "CHANGE_ME_TO_A_STRONG_SECRET"; 6. Deploy کنید. 7. URL را کپی کنید؛ معمولاً به شکل `https://YOUR-WORKER.YOUR-SUBDOMAIN.workers.dev` -## ۵) نصب روی Deno Deploy (هنوز تست نشده) +## ۴) نصب روی Deno Deploy (هنوز تست نشده) فایل: `apps_script/deno_deploy.ts` @@ -70,6 +58,28 @@ const PSK = "CHANGE_ME_TO_A_STRONG_SECRET"; 6. Deploy کنید. 7. URL را کپی کنید؛ معمولاً به شکل `https://YOUR-PROJECT.deno.dev` +## ۵) نصب روی VPS شخصی (فقط Linux) + +فایل‌ها: +- `apps_script/vps_exit_node.py` (سرور نود خروجی) +- `apps_script/setup_vps_exit_node.sh` (نصب خودکار - پیشنهادی) + +نیازمندی‌ها: +- یک VPS لینوکسی با دسترسی root/sudo +- Python 3.10+ + +دستور نصب سریع: + +```bash +curl -fsSL https://raw.githubusercontent.com/masterking32/MasterHttpRelayVPN/python_testing/apps_script/setup_vps_exit_node.sh | sudo bash +``` + +یا: + +```bash +wget -qO- https://raw.githubusercontent.com/masterking32/MasterHttpRelayVPN/python_testing/apps_script/setup_vps_exit_node.sh | sudo bash +``` + ## ۶) تنظیم MasterHttpRelayVPN فایل `config.json` را ویرایش کنید: @@ -77,8 +87,8 @@ const PSK = "CHANGE_ME_TO_A_STRONG_SECRET"; ```json "exit_node": { "enabled": true, - "provider": "valtown", - "url": "https://YOUR-NAME.web.val.run", + "provider": "cloudflare", + "url": "https://YOUR-WORKER.YOUR-SUBDOMAIN.workers.dev", "psk": "CHANGE_ME_TO_A_STRONG_SECRET", "mode": "full", "hosts": [ @@ -91,9 +101,9 @@ const PSK = "CHANGE_ME_TO_A_STRONG_SECRET"; ``` مقادیر provider: -- `valtown` - `cloudflare` - `deno` +- `vps` اگر `mode` برابر `selective` باشد، فقط دامنه‌های داخل `hosts` از نود خروجی عبور می‌کنند. اگر `mode` برابر `full` باشد، تمام ترافیک relay‌شده از نود خروجی عبور می‌کند. diff --git a/src/relay/domain_fronter.py b/src/relay/domain_fronter.py index 29f737b..ec208ca 100644 --- a/src/relay/domain_fronter.py +++ b/src/relay/domain_fronter.py @@ -1116,8 +1116,6 @@ class DomainFronter: def _normalize_exit_node_provider(raw: object) -> str: provider = str(raw or "custom").strip().lower() aliases = { - "val": "valtown", - "val-town": "valtown", "cloudflare_worker": "cloudflare", "worker": "cloudflare", "cf": "cloudflare", @@ -1150,11 +1148,7 @@ class DomainFronter: if direct: return direct - if provider == "valtown": - selected = _pick_from(en_cfg, "valtown_url", "val_url") or _pick_from( - providers, "valtown", "val_town", "val", - ) - elif provider == "cloudflare": + if provider == "cloudflare": selected = _pick_from( en_cfg, "cloudflare_url", "worker_url", "cf_url", ) or _pick_from(