somratpro commited on
Commit
72ece3f
·
1 Parent(s): 6e18e02

feat: upgrade to universal outbound proxy with x-target-host header

Browse files
DISCORD_PROXY_GUIDE.md CHANGED
@@ -9,12 +9,14 @@ To work around this, you can easily create your own private Discord proxy using
9
  ## Step-by-Step Guide
10
 
11
  ### Step 1: Create a Cloudflare Worker
 
12
  1. Log into [Cloudflare](https://dash.cloudflare.com/) (create an account if you don't have one).
13
  2. On the left sidebar, go to **Workers & Pages**.
14
  3. Click **Create Worker** -> **Start with Hello World!**.
15
  4. Name it something memorable, like `discord-proxy`, and click **Deploy**.
16
 
17
  ### Step 2: Add the Proxy Code
 
18
  1. Once deployed, click the **Edit Code** button.
19
  2. In the online code editor, delete the existing code and replace it entirely with this 6-line snippet:
20
 
@@ -28,9 +30,10 @@ export default {
28
  }
29
  ```
30
 
31
- 3. Click **Save and Deploy** in the top right corner. Cloudflare will generate a unique URL for you (e.g., `https://discord-proxy.yourname.workers.dev`).
32
 
33
  ### Step 3: Use the Proxy in n8n
 
34
  Because the native Discord Node hardcodes connections to `discord.com` when using Bot tokens, you must use the **Webhook** method.
35
 
36
  1. Add the standard **Discord** node to your n8n workflow.
 
9
  ## Step-by-Step Guide
10
 
11
  ### Step 1: Create a Cloudflare Worker
12
+
13
  1. Log into [Cloudflare](https://dash.cloudflare.com/) (create an account if you don't have one).
14
  2. On the left sidebar, go to **Workers & Pages**.
15
  3. Click **Create Worker** -> **Start with Hello World!**.
16
  4. Name it something memorable, like `discord-proxy`, and click **Deploy**.
17
 
18
  ### Step 2: Add the Proxy Code
19
+
20
  1. Once deployed, click the **Edit Code** button.
21
  2. In the online code editor, delete the existing code and replace it entirely with this 6-line snippet:
22
 
 
30
  }
31
  ```
32
 
33
+ 1. Click **Save and Deploy** in the top right corner. Cloudflare will generate a unique URL for you (e.g., `https://discord-proxy.yourname.workers.dev`).
34
 
35
  ### Step 3: Use the Proxy in n8n
36
+
37
  Because the native Discord Node hardcodes connections to `discord.com` when using Bot tokens, you must use the **Webhook** method.
38
 
39
  1. Add the standard **Discord** node to your n8n workflow.
TASK_SUMMARY.md CHANGED
@@ -28,8 +28,9 @@ Enable `n8n` (running on Hugging Face Spaces) to connect to blocked external ser
28
 
29
  ### 5. Transparent Application-Level Proxy (Implemented)
30
  - **Status**: ✅ **Partially Fixed** (Requires External Worker)
31
- - **Method**: Implemented `outbound-fix.js` which patches `https.request` to redirect Telegram and Discord traffic through a Cloudflare Worker.
32
- - **Why it works**: By changing the target hostname to a custom Cloudflare Worker, we change the SNI (Server Name Indication). Since Cloudflare is not blocked by HF, the connection succeeds. The Worker then forwards the request to the real destination.
 
33
  - **Recursion Guard**: Uses a private property `_proxied: true` on the options object to ensure requests aren't intercepted twice.
34
 
35
  ## Final Conclusion & Recommendations
@@ -39,14 +40,14 @@ The connectivity issue on Hugging Face Spaces for `n8n` is now fully understood
39
  2. **Network/SNI Layer**: **Addressed** via `outbound-fix.js` (Transparent Proxy).
40
 
41
  ### Next Steps for User
42
- 1. **Deploy Cloudflare Worker**: Use the code provided in `telegram-proxy-worker.js`.
43
  2. **Set Environment Variable**: In HF Space Settings, set `OUTBOUND_PROXY_URL` to your worker's URL (e.g., `https://my-proxy.somrat.workers.dev`).
44
  3. **Restart Space**: The `n8n` instance will now automatically route all Telegram and Discord requests through your proxy without needing to change any workflow nodes.
45
 
46
  ## Current State of Repository
47
  - `dns-fix.js`: Robust DoH fallback with recursion guards.
48
- - `outbound-fix.js`: Transparent SNI-bypass proxy for Telegram/Discord.
49
- - `telegram-proxy-worker.js`: Cloudflare Worker code for the proxy.
50
  - `Dockerfile`: Configured to preload both fixes.
51
  - `access.md`: Contains test tokens and execution logs.
52
 
 
28
 
29
  ### 5. Transparent Application-Level Proxy (Implemented)
30
  - **Status**: ✅ **Partially Fixed** (Requires External Worker)
31
+ - **Method**: Implemented `outbound-fix.js` which patches `https.request` to redirect blocked traffic through a single **Universal Cloudflare Worker**.
32
+ - **Multi-Service Support**: The patch adds a `x-target-host` header to the request. The Worker reads this header to determine the final destination (Telegram, Discord, etc.), allowing one Worker to handle all blocked services.
33
+ - **Why it works**: By changing the target hostname to your custom Cloudflare Worker, we change the SNI (Server Name Indication). Since Cloudflare is not blocked by HF, the connection succeeds.
34
  - **Recursion Guard**: Uses a private property `_proxied: true` on the options object to ensure requests aren't intercepted twice.
35
 
36
  ## Final Conclusion & Recommendations
 
40
  2. **Network/SNI Layer**: **Addressed** via `outbound-fix.js` (Transparent Proxy).
41
 
42
  ### Next Steps for User
43
+ 1. **Deploy Cloudflare Worker**: Use the code provided in `outbound-proxy-worker.js`.
44
  2. **Set Environment Variable**: In HF Space Settings, set `OUTBOUND_PROXY_URL` to your worker's URL (e.g., `https://my-proxy.somrat.workers.dev`).
45
  3. **Restart Space**: The `n8n` instance will now automatically route all Telegram and Discord requests through your proxy without needing to change any workflow nodes.
46
 
47
  ## Current State of Repository
48
  - `dns-fix.js`: Robust DoH fallback with recursion guards.
49
+ - `outbound-fix.js`: Transparent SNI-bypass proxy with `x-target-host` support.
50
+ - `outbound-proxy-worker.js`: Universal Cloudflare Worker code for any blocked target.
51
  - `Dockerfile`: Configured to preload both fixes.
52
  - `access.md`: Contains test tokens and execution logs.
53
 
outbound-fix.js CHANGED
@@ -48,15 +48,17 @@ if (PROXY_URL) {
48
  // Mark to prevent recursion
49
  if (typeof newOptions === "object") {
50
  newOptions._proxied = true;
 
 
 
 
 
 
 
 
51
  newOptions.hostname = proxy.hostname;
52
  newOptions.host = proxy.host;
53
  newOptions.port = proxy.port || 443;
54
-
55
- // Fix headers
56
- if (newOptions.headers) {
57
- // Cloudflare needs the correct Host header to route to the worker
58
- newOptions.headers = { ...newOptions.headers, host: proxy.host };
59
- }
60
  }
61
 
62
  // Force HTTPS if it was HTTP (unlikely for these domains but good for safety)
 
48
  // Mark to prevent recursion
49
  if (typeof newOptions === "object") {
50
  newOptions._proxied = true;
51
+
52
+ // Set headers
53
+ newOptions.headers = {
54
+ ...(newOptions.headers || {}),
55
+ host: proxy.host,
56
+ "x-target-host": hostname // Tell the worker where to go
57
+ };
58
+
59
  newOptions.hostname = proxy.hostname;
60
  newOptions.host = proxy.host;
61
  newOptions.port = proxy.port || 443;
 
 
 
 
 
 
62
  }
63
 
64
  // Force HTTPS if it was HTTP (unlikely for these domains but good for safety)
telegram-proxy-worker.js → outbound-proxy-worker.js RENAMED
@@ -1,35 +1,44 @@
1
  /**
2
- * Cloudflare Worker: Simple Telegram/Discord Proxy
3
  *
4
  * Deployment:
5
  * 1. Go to dash.cloudflare.com -> Workers & Pages -> Create Worker.
6
  * 2. Paste this code and deploy.
7
- * 3. Use your worker URL (e.g., https://my-proxy.workers.dev) in Hugging8n.
 
 
8
  */
9
 
10
  export default {
11
  async fetch(request, env, ctx) {
12
  const url = new URL(request.url);
 
13
 
14
- // Determine target based on path or header
15
- // Default to telegram if path matches telegram pattern
16
  let targetBase = "";
17
- if (url.pathname.startsWith("/bot")) {
18
- targetBase = "https://api.telegram.org";
19
- } else if (url.pathname.startsWith("/api/webhooks") || url.pathname.startsWith("/api/v")) {
20
- targetBase = "https://discord.com";
21
  } else {
22
- return new Response("Invalid request. Target not recognized.", { status: 400 });
 
 
 
 
 
 
 
23
  }
24
 
25
  const targetUrl = targetBase + url.pathname + url.search;
26
 
27
- // Copy headers and remove Cloudflare-specific ones
28
  const headers = new Headers(request.headers);
29
  headers.delete("cf-connecting-ip");
30
  headers.delete("cf-ray");
31
  headers.delete("cf-visitor");
32
  headers.delete("x-real-ip");
 
33
 
34
  const modifiedRequest = new Request(targetUrl, {
35
  method: request.method,
@@ -39,7 +48,12 @@ export default {
39
  });
40
 
41
  try {
42
- return await fetch(modifiedRequest);
 
 
 
 
 
43
  } catch (e) {
44
  return new Response(`Proxy Error: ${e.message}`, { status: 502 });
45
  }
 
1
  /**
2
+ * Cloudflare Worker: Universal Outbound Proxy
3
  *
4
  * Deployment:
5
  * 1. Go to dash.cloudflare.com -> Workers & Pages -> Create Worker.
6
  * 2. Paste this code and deploy.
7
+ * 3. Use your worker URL (e.g., https://my-proxy.workers.dev) as OUTBOUND_PROXY_URL.
8
+ *
9
+ * This worker reads the 'x-target-host' header to determine where to forward the request.
10
  */
11
 
12
  export default {
13
  async fetch(request, env, ctx) {
14
  const url = new URL(request.url);
15
+ const targetHost = request.headers.get("x-target-host");
16
 
 
 
17
  let targetBase = "";
18
+
19
+ if (targetHost) {
20
+ // Use the host provided in the header (preferred)
21
+ targetBase = `https://${targetHost}`;
22
  } else {
23
+ // Fallback: Guess based on path (legacy support)
24
+ if (url.pathname.startsWith("/bot")) {
25
+ targetBase = "https://api.telegram.org";
26
+ } else if (url.pathname.startsWith("/api/webhooks") || url.pathname.startsWith("/api/v")) {
27
+ targetBase = "https://discord.com";
28
+ } else {
29
+ return new Response("Invalid request. 'x-target-host' header missing and target not recognized via path.", { status: 400 });
30
+ }
31
  }
32
 
33
  const targetUrl = targetBase + url.pathname + url.search;
34
 
35
+ // Copy headers and remove internal/Cloudflare-specific ones
36
  const headers = new Headers(request.headers);
37
  headers.delete("cf-connecting-ip");
38
  headers.delete("cf-ray");
39
  headers.delete("cf-visitor");
40
  headers.delete("x-real-ip");
41
+ headers.delete("x-target-host"); // Don't leak this to the target
42
 
43
  const modifiedRequest = new Request(targetUrl, {
44
  method: request.method,
 
48
  });
49
 
50
  try {
51
+ const response = await fetch(modifiedRequest);
52
+
53
+ // Special handling for Discord/Telegram which might return 403 on some CF IPs
54
+ // If needed, you can add retry logic here.
55
+
56
+ return response;
57
  } catch (e) {
58
  return new Response(`Proxy Error: ${e.message}`, { status: 502 });
59
  }