fix: revert Telegram SNI workaround and restore proper dns-fix.js behavior
Browse files- HF Spaces blocks standard UDP DNS for some domains (like Telegram) by returning ENOTFOUND.
- The previous attempt forced DoH first via cloudflare-dns.com, but standard DNS resolution for cloudflare-dns.com itself failed inside HF Spaces, causing the entire DoH fallback to crash with ECONNRESET.
- Restored the original HuggingClaw logic: try system DNS first, and if it fails (ENOTFOUND), fallback to DoH using the direct IP '1.1.1.1' which bypasses system DNS entirely.
- Reverted README and DISCORD_PROXY_GUIDE.md since Telegram is NOT blocked by HF TLS/SNI and works natively once DNS is fixed.
- DISCORD_PROXY_GUIDE.md +23 -45
- README.md +3 -3
- dns-fix.js +23 -25
DISCORD_PROXY_GUIDE.md
CHANGED
|
@@ -1,67 +1,45 @@
|
|
| 1 |
-
# π οΈ
|
| 2 |
|
| 3 |
-
Hugging Face
|
| 4 |
|
| 5 |
-
|
| 6 |
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
## Setting Up a Cloudflare Worker Proxy
|
| 10 |
|
| 11 |
-
|
| 12 |
|
| 13 |
### Step 1: Create a Cloudflare Worker
|
| 14 |
-
1. Log into [Cloudflare](https://dash.cloudflare.com/) (create
|
| 15 |
-
2.
|
| 16 |
-
3. Click **Create Worker**
|
| 17 |
-
4.
|
| 18 |
|
| 19 |
### Step 2: Add the Proxy Code
|
| 20 |
-
1.
|
| 21 |
-
2.
|
| 22 |
-
3. Replace `TARGET_HOSTNAME` with the service you want to proxy (see table below).
|
| 23 |
|
| 24 |
```javascript
|
| 25 |
export default {
|
| 26 |
async fetch(request) {
|
| 27 |
const url = new URL(request.url);
|
| 28 |
-
url.hostname = '
|
| 29 |
return fetch(new Request(url, request));
|
| 30 |
}
|
| 31 |
}
|
| 32 |
```
|
| 33 |
|
| 34 |
-
|
| 35 |
-
| :--- | :--- |
|
| 36 |
-
| Discord | `discord.com` |
|
| 37 |
-
| Telegram | `api.telegram.org` |
|
| 38 |
-
|
| 39 |
-
4. Click **Save and Deploy**. Cloudflare gives you a URL like `https://your-proxy.yourname.workers.dev`.
|
| 40 |
-
|
| 41 |
-
---
|
| 42 |
|
| 43 |
-
##
|
|
|
|
| 44 |
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
- *Proxied:* `https://discord-proxy.yourname.workers.dev/api/webhooks/123456/abcdef`
|
| 53 |
-
4. Paste the proxied URL in the **Webhook URL** field.
|
| 54 |
-
|
| 55 |
-
### Telegram
|
| 56 |
-
The n8n Telegram credential has a **Base URL** field that can be changed:
|
| 57 |
-
|
| 58 |
-
1. Go to **Credentials** β add or edit a **Telegram** credential.
|
| 59 |
-
2. Enter your Bot Token as usual.
|
| 60 |
-
3. In the **Base URL** field, replace `https://api.telegram.org` with your Worker URL:
|
| 61 |
-
- *Original:* `https://api.telegram.org`
|
| 62 |
-
- *Proxied:* `https://telegram-proxy.yourname.workers.dev`
|
| 63 |
-
4. Click **Save** and then **Test** β it should connect instantly.
|
| 64 |
|
| 65 |
---
|
| 66 |
-
|
| 67 |
-
*Note: Upgrading your Hugging Face Space to a paid hardware tier removes these network restrictions entirely, allowing you to use all n8n nodes natively without a proxy.*
|
|
|
|
| 1 |
+
# π οΈ How to Create a Free Discord Proxy
|
| 2 |
|
| 3 |
+
Hugging Face officially blocks outgoing connections to Discord's IP addresses on Free Tier Spaces to prevent spam. While our built-in DNS script cleanly bypasses blocks for Telegram and WhatsApp, Discord is blocked at the physical IP firewall level.
|
| 4 |
|
| 5 |
+
This means the native n8n "Discord" node will always hang and fail with a "Connection closed unexpectedly" error.
|
| 6 |
|
| 7 |
+
To work around this, you can easily create your own private Discord proxy using Cloudflare Workers. It takes about 2 minutes and is 100% free (allowing up to 100,000 requests per day).
|
|
|
|
|
|
|
| 8 |
|
| 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 |
|
| 21 |
```javascript
|
| 22 |
export default {
|
| 23 |
async fetch(request) {
|
| 24 |
const url = new URL(request.url);
|
| 25 |
+
url.hostname = 'discord.com';
|
| 26 |
return fetch(new Request(url, request));
|
| 27 |
}
|
| 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.
|
| 37 |
+
2. Under "Authentication", select **Webhook**.
|
| 38 |
+
3. Take your normal Discord Webhook URL and replace `discord.com` with your new worker domain.
|
| 39 |
+
* *Original:* `https://discord.com/api/webhooks/123456/abcdef`
|
| 40 |
+
* *New:* `https://discord-proxy.yourname.workers.dev/api/webhooks/123456/abcdef`
|
| 41 |
+
4. Create a new Discord Webhook Credential in n8n and paste that **New URL** into the "Webhook URL" field.
|
| 42 |
+
5. Setup your message (e.g., set the text to "Hello World") and click **Execute Node**. Your message will instantly appear in Discord!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
|
| 44 |
---
|
| 45 |
+
*Note: If you ever upgrade your Hugging Face Space to a paid hardware tier, the outgoing firewall restriction is removed, and you can go back to using the native n8n Discord node directly!*
|
|
|
README.md
CHANGED
|
@@ -68,10 +68,10 @@ Hugging8n automatically creates and maintains a private dataset in your Hugging
|
|
| 68 |
|
| 69 |
## β οΈ Known Limitations & Workarounds
|
| 70 |
|
| 71 |
-
**Discord
|
| 72 |
-
Hugging Face blocks outgoing connections to Discord
|
| 73 |
|
| 74 |
-
π **[Read the Guide: How to Create a Free
|
| 75 |
*(Upgrading to a paid Space removes this firewall restriction entirely).*
|
| 76 |
|
| 77 |
## ποΈ Architecture
|
|
|
|
| 68 |
|
| 69 |
## β οΈ Known Limitations & Workarounds
|
| 70 |
|
| 71 |
+
**Discord Webhooks**
|
| 72 |
+
Hugging Face officially blocks outgoing connections to Discord on Free Tier Spaces. To use the Discord node, you must route your traffic through a simple, free proxy.
|
| 73 |
|
| 74 |
+
π **[Read the Guide: How to Create a Free Discord Proxy in 2 minutes](./DISCORD_PROXY_GUIDE.md)**
|
| 75 |
*(Upgrading to a paid Space removes this firewall restriction entirely).*
|
| 76 |
|
| 77 |
## ποΈ Architecture
|
dns-fix.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
| 2 |
* DNS fix preload script for HF Spaces.
|
| 3 |
*
|
| 4 |
* Patches Node.js dns.lookup to:
|
| 5 |
-
* 1. Try
|
| 6 |
-
* 2. Fall back to
|
| 7 |
* (This is needed because HF Spaces intercepts/blocks some domains like
|
| 8 |
* WhatsApp web or Telegram API via standard UDP DNS).
|
| 9 |
*
|
|
@@ -11,18 +11,9 @@
|
|
| 11 |
*/
|
| 12 |
"use strict";
|
| 13 |
|
| 14 |
-
console.error("[DNS-FIX] Loaded β DoH-first resolver + keep-alive patch active.");
|
| 15 |
-
|
| 16 |
const dns = require("dns");
|
| 17 |
-
const http = require("http");
|
| 18 |
const https = require("https");
|
| 19 |
|
| 20 |
-
// ββ Keep-Alive Fix ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 21 |
-
http.globalAgent = new http.Agent({ keepAlive: false });
|
| 22 |
-
https.globalAgent = new https.Agent({ keepAlive: false });
|
| 23 |
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 24 |
-
|
| 25 |
-
|
| 26 |
// In-memory cache for runtime DoH resolutions
|
| 27 |
const runtimeCache = new Map(); // hostname -> { ip, expiry }
|
| 28 |
|
|
@@ -34,7 +25,7 @@ function dohResolve(hostname, callback) {
|
|
| 34 |
return callback(null, cached.ip);
|
| 35 |
}
|
| 36 |
|
| 37 |
-
const url = `https://
|
| 38 |
const req = https.get(
|
| 39 |
url,
|
| 40 |
{ headers: { Accept: "application/dns-json" }, timeout: 15000 },
|
|
@@ -87,24 +78,31 @@ dns.lookup = function patchedLookup(hostname, options, callback) {
|
|
| 87 |
hostname === "127.0.0.1" ||
|
| 88 |
hostname === "::1" ||
|
| 89 |
/^\d+\.\d+\.\d+\.\d+$/.test(hostname) ||
|
| 90 |
-
/^::/.test(hostname)
|
| 91 |
-
hostname === "cloudflare-dns.com"
|
| 92 |
) {
|
| 93 |
return origLookup.call(dns, hostname, options, callback);
|
| 94 |
}
|
| 95 |
|
| 96 |
-
// 1) Try
|
| 97 |
-
|
| 98 |
-
if (!
|
| 99 |
-
|
| 100 |
-
return callback(null, [{ address: ip, family: 4 }]);
|
| 101 |
-
}
|
| 102 |
-
return callback(null, ip, 4);
|
| 103 |
}
|
| 104 |
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 109 |
});
|
| 110 |
};
|
|
|
|
| 2 |
* DNS fix preload script for HF Spaces.
|
| 3 |
*
|
| 4 |
* Patches Node.js dns.lookup to:
|
| 5 |
+
* 1. Try system DNS first
|
| 6 |
+
* 2. Fall back to DNS-over-HTTPS (Cloudflare) if system DNS fails
|
| 7 |
* (This is needed because HF Spaces intercepts/blocks some domains like
|
| 8 |
* WhatsApp web or Telegram API via standard UDP DNS).
|
| 9 |
*
|
|
|
|
| 11 |
*/
|
| 12 |
"use strict";
|
| 13 |
|
|
|
|
|
|
|
| 14 |
const dns = require("dns");
|
|
|
|
| 15 |
const https = require("https");
|
| 16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
// In-memory cache for runtime DoH resolutions
|
| 18 |
const runtimeCache = new Map(); // hostname -> { ip, expiry }
|
| 19 |
|
|
|
|
| 25 |
return callback(null, cached.ip);
|
| 26 |
}
|
| 27 |
|
| 28 |
+
const url = `https://1.1.1.1/dns-query?name=${encodeURIComponent(hostname)}&type=A`;
|
| 29 |
const req = https.get(
|
| 30 |
url,
|
| 31 |
{ headers: { Accept: "application/dns-json" }, timeout: 15000 },
|
|
|
|
| 78 |
hostname === "127.0.0.1" ||
|
| 79 |
hostname === "::1" ||
|
| 80 |
/^\d+\.\d+\.\d+\.\d+$/.test(hostname) ||
|
| 81 |
+
/^::/.test(hostname)
|
|
|
|
| 82 |
) {
|
| 83 |
return origLookup.call(dns, hostname, options, callback);
|
| 84 |
}
|
| 85 |
|
| 86 |
+
// 1) Try system DNS first
|
| 87 |
+
origLookup.call(dns, hostname, options, (err, address, family) => {
|
| 88 |
+
if (!err && address) {
|
| 89 |
+
return callback(null, address, family);
|
|
|
|
|
|
|
|
|
|
| 90 |
}
|
| 91 |
|
| 92 |
+
// 2) System DNS failed with ENOTFOUND or EAI_AGAIN β fall back to DoH
|
| 93 |
+
if (err && (err.code === "ENOTFOUND" || err.code === "EAI_AGAIN")) {
|
| 94 |
+
dohResolve(hostname, (dohErr, ip) => {
|
| 95 |
+
if (dohErr || !ip) {
|
| 96 |
+
return callback(err); // Return original error
|
| 97 |
+
}
|
| 98 |
+
if (options.all) {
|
| 99 |
+
return callback(null, [{ address: ip, family: 4 }]);
|
| 100 |
+
}
|
| 101 |
+
callback(null, ip, 4);
|
| 102 |
+
});
|
| 103 |
+
} else {
|
| 104 |
+
// Other DNS errors β pass through
|
| 105 |
+
callback(err, address, family);
|
| 106 |
+
}
|
| 107 |
});
|
| 108 |
};
|