---
title: "Node Unblocker چیست و چگونه آن را امن راه‌اندازی کنیم؟"
description: "Node Unblocker میان‌افزار Express است که سرور ⁦Node.js⁩ را به پروکسی وب بازنویسی‌کننده نشانی‌ها تبدیل می‌کند؛ سازوکار، کد آزموده و شیوه ایمن کردن آن."
url: https://proxynet.io/fa/blog/node-unblocker
date: 2026-10-11
author: "Acar Diveroli"
category: "آموزش‌ها, مبانی پروکسی"
lang: fa
---

# Node Unblocker چیست و چگونه آن را امن راه‌اندازی کنیم؟

یک برنامه کوچک Express را اجرا می‌کنید، نشانی `http://127.0.0.1:8080/proxy/https://example.com/` را در مرورگر باز می‌کنید و صفحه زیر نشانی سرور خودتان ظاهر می‌شود. لینک‌ها، تصویرها و فرم‌های آن حالا با `/proxy/` آغاز می‌شوند، پس هر کلیک دوباره از سرور شما می‌گذرد. این Node Unblocker است، یعنی بسته `unblocker` در npm: چند خط کد که سرور ⁦Node.js⁩ را به پروکسی وبی تبدیل می‌کند که هر کسی با یک مرورگر معمولی می‌تواند از آن استفاده کند. اگر همین چند خط بی‌محافظ بماند، غریبه‌ها هم می‌توانند از سرور شما استفاده کنند؛ نخستین نمونه آزمایشی ما صفحه مدیریتی را بیرون کشید که یک سرویس محلی فقط به `127.0.0.1` نشان می‌داد.

در این نوشته سازوکار آن، یک سرور ساده، نسخه‌ای ایمن‌شده که غریبه‌ها و نشانی‌های شبکه داخلی را بیرون نگه می‌دارد، استفاده از پروکسی بالادستی برای ترافیک خروجی و محدودیت‌های این بسته را بررسی می‌کنیم. همه نمونه‌ها را در 11 اکتبر 2026 با ⁦unblocker 2.3.1⁩، ⁦Express 4.22.3⁩ و ⁦Node.js 24.11.1⁩ اجرا کردیم. طرف دیگر آزمون‌ها یک سایت آزمایشی محلی، یک سرور اکو (echo) برای WebSocket و یک پروکسی آزمایشی بود که نام کاربری و رمز عبور می‌خواهد.

> **نکته: پاسخ کوتاه**
>
> Node Unblocker (بسته `unblocker` در npm) میان‌افزاری (middleware) سازگار با Express است که سرور ⁦Node.js⁩ را به پروکسی وب تبدیل می‌کند. بازدیدکننده `/proxy/https://site.example/` را باز می‌کند، سرور صفحه را می‌گیرد، لینک‌ها، کوکی‌ها و تغییر مسیرهای آن را طوری بازنویسی می‌کند که به `/proxy/` برگردند و صفحه را به مرورگر می‌فرستد. سایت آی‌پی سرور شما را می‌بیند، نه آی‌پی بازدیدکننده را. آن را هرگز بدون رمز ورود، فهرست سایت‌های مجاز (allowlist) و مسدود کردن نشانی‌های خصوصی روی اینترنت نگذارید، وگرنه هر کسی می‌تواند ترافیک خودش را از سرور شما عبور دهد.

## Node Unblocker چیست؟

Node Unblocker کتابخانه‌ای متن‌باز برای ⁦Node.js⁩ است که Nathan Friedly آن را نوشته و با نام `unblocker` در npm منتشر شده است. در 11 اکتبر 2026 آخرین نسخه آن 2.3.1 بود که در ژوئن 2024 منتشر شد؛ به ⁦Node.js 16.17⁩ یا جدیدتر نیاز دارد و با مجوز ⁦AGPL-3.0⁩ عرضه می‌شود. [README آن در GitHub](https://github.com/nfriedly/node-unblocker) آن را کتابخانه‌ای همه‌منظوره برای عبور دادن صفحه‌های وب راه دور از پروکسی و بازنویسی آن‌ها معرفی می‌کند.

این بسته یک پروکسی وب (web proxy) است: وب‌سایتی که وب‌سایت‌های دیگر را برای شما بارگذاری می‌کند. بازدیدکننده هیچ تنظیمی را تغییر نمی‌دهد و فقط نشانی سرور شما را لازم دارد. در مقابل، پروکسی HTTP یا SOCKS5 در یک برنامه یا در سیستم‌عامل تنظیم می‌شود و ترافیک را بدون تغییر عبور می‌دهد. Node Unblocker فقط صفحه‌های وب و اتصال‌های WebSocket را جابه‌جا می‌کند و یک خروجی دارد: آی‌پی ماشینی که روی آن اجرا می‌شود. اگر آن را روی لپ‌تاپ خود اجرا کنید، سایت آی‌پی خانگی شما را می‌بیند.

## Node Unblocker چگونه کار می‌کند؟

هر درخواستی که مسیرش با پیشوند (به‌طور پیش‌فرض `/proxy/`) آغاز شود، این مراحل را طی می‌کند:

1. **مرورگر یک نشانی پروکسی را درخواست می‌کند**، مانند `GET /proxy/https://example.com/`. هر چیزی که پس از پیشوند بیاید نشانی هدف است. نشانی بدون طرح‌واره (scheme)، مانند `/proxy/example.com`، با کد `307` به `/proxy/http://example.com/` فرستاده می‌شود.
2. **میان‌افزارهای درخواست اجرا می‌شوند.** تابع‌های داخلی هدرهای `Host` و `Referer`، فشرده‌سازی و کوکی‌ها را اصلاح می‌کنند. سپس تابع‌هایی که خودتان در `requestMiddleware` گذاشته‌اید اجرا می‌شوند؛ بررسی‌های دسترسی جایشان همین‌جاست.
3. **سرور شما با هدرهای مرورگر به هدف وصل می‌شود**؛ اگر `httpAgent` یا `httpsAgent` تعریف کرده باشید، اتصال از همان agent می‌گذرد. هدف آی‌پی سرور شما را می‌بیند.
4. **میان‌افزارهای پاسخ، پاسخ را ویرایش می‌کنند.** هدرهای `Content-Security-Policy`، `Strict-Transport-Security` و `Public-Key-Pins` را حذف می‌کنند، تغییر مسیرها و نشانی‌های درون HTML و CSS را بازنویسی می‌کنند، کوکی‌ها را به مسیر `/proxy/<site>/` منتقل می‌کنند، یک اسکریپت به صفحه تزریق می‌کنند و تگ robots با مقدار `NOINDEX, NOFOLLOW` می‌افزایند.
5. **صفحه تکه‌به‌تکه به مرورگر برمی‌گردد.**
6. **لینک‌های جامانده بازیابی می‌شوند.** درخواستی که نسبت به ریشه سایت نوشته شده، مانند `/about`، بدون پیشوند می‌رسد؛ Node Unblocker هدر `Referer` را می‌خواند و با `307` آن را به نشانی کامل پروکسی می‌فرستد.

اسکریپت تزریق‌شده `fetch`، `XMLHttpRequest`، WebSocket، ساخت عنصرهای تازه و تغییرات تاریخچه (history) را رهگیری می‌کند تا نشانی‌هایی که جاوااسکریپت می‌سازد هم پیشوند بگیرند. خود فایل‌های جاوااسکریپت بازنویسی نمی‌شوند. صفحه آزمایشی ما، با یک لینک مطلق، یک لینک نسبی به ریشه، یک لینک نسبی، یک تصویر با نشانی بدون پروتکل و یک فرم، این‌طور برگشت:

```text
set-cookie: session=abc123; Path=/proxy/http://127.0.0.1:9000/; HttpOnly

<script src="/proxy/client/unblocker-client.js"></script>
<script>unblockerInit({"prefix":"/proxy/","url":"http://127.0.0.1:9000/"}, window);</script>
<title>Test page</title><meta name="ROBOTS" content="NOINDEX, NOFOLLOW"/>
<a href="/proxy/https://www.iana.org/help/example-domains">absolute</a>
<a href="/proxy/http://127.0.0.1:9000/about">root-relative</a>
<a href="contact">relative</a>
<img src="/proxy/http://cdn.example.net/logo.png">
<form action="/proxy/http://127.0.0.1:9000/login" method="post"></form>
```

لینک نسبی خودبه‌خود زیر مسیر پروکسی باز می‌شود، پس دست‌نخورده می‌ماند. هدرهای `Content-Security-Policy` و `Strict-Transport-Security` صفحه هم هرگز به مرورگر نرسیدند.

## چه فرقی با فوروارد پروکسی و ریورس پروکسی دارد؟

هر سه میان مرورگر و سایت قرار می‌گیرند. تفاوتشان در این است که چه کسی آن‌ها را راه‌اندازی می‌کند و آیا صفحه را تغییر می‌دهند یا نه.

| | Node Unblocker | فوروارد پروکسی | ریورس پروکسی |
|---|---|---|---|
| شیوه استفاده | باز کردن نشانی `/proxy/` | تنظیم `host:port` در برنامه یا سیستم‌عامل | رفتن به نشانی خود سایت |
| راه‌اندازی‌کننده | گرداننده سرور | کاربر یا شرکتش | صاحب سایت |
| تغییر صفحه | بله: لینک‌ها، کوکی‌ها، تغییر مسیرها | خیر | معمولاً نه |
| HTTPS | روی سرور شما رمزگشایی می‌شود | از تونل می‌گذرد و رمزگذاری‌شده می‌ماند | صاحب سایت رمزگشایی می‌کند |
| ترافیک | صفحه‌های وب و WebSocket | هر نوع HTTP؛ SOCKS5 حتی UDP | HTTP(S) به سرورهای سایت |

فوروارد پروکسی به هر برنامه‌ای که تنظیم پروکسی دارد خدمت می‌دهد و هرگز لازم نیست صفحه را بفهمد. ریورس پروکسی، مانند nginx، جلوی سایت خود شما می‌نشیند؛ نوشته [فوروارد پروکسی و ریورس پروکسی](/fa/blog/forward-vs-reverse-proxy) هر دو را توضیح می‌دهد. Node Unblocker در این میان استثناست: پروکسی بازنویسی‌کننده‌ای برای مرورگرهایی که نمی‌توانند یا نباید تنظیماتشان را تغییر دهند.

## چگونه یک سرور ساده Node Unblocker راه‌اندازی کنیم؟

در یک پوشه خالی، Express و این بسته را نصب کنید و سپس کد زیر را با نام `server.mjs` ذخیره کنید:

```bash
npm install express unblocker
```

```js
import express from "express";
import Unblocker from "unblocker";

const app = express();
const unblocker = new Unblocker({ prefix: "/proxy/" });

// Unblocker has to be one of the first app.use() calls and must sit at the root, not on a sub-path
app.use(unblocker);

app.get("/", (req, res) => res.send("Open /proxy/https://example.com/"));

// The upgrade listener lets Unblocker relay WebSocket connections
app.listen(8080, "127.0.0.1").on("upgrade", unblocker.onUpgrade);
```

فرمان `node server.mjs` را اجرا کنید و `http://127.0.0.1:8080/proxy/https://example.com/` را باز کنید. README می‌گوید این میان‌افزار نباید روی یک زیرمسیر قرار بگیرد و هشدار می‌دهد که `/` به‌عنوان پیشوند به حالت‌های مرزی دردسرساز می‌انجامد. بدون شنونده رویداد `upgrade`، چت‌ها و داشبوردهای زنده در صفحه‌هایی که از پروکسی می‌گذرند نمی‌توانند وصل شوند.

سرور روی `127.0.0.1` گوش می‌دهد، پس فقط رایانه خودتان به آن دسترسی دارد؛ همین‌طور نگهش دارید. در آزمون ما صفحه‌ها را بارگذاری کرد، تغییر مسیر `302` را بازنویسی کرد، `POST` یک فرم را رساند و پیام‌های WebSocket را برگرداند. همچنین `/proxy/http://127.0.0.1:9000/admin` را باز کرد؛ صفحه‌ای که سرویس آزمایشی ما فقط به همان ماشین نشان می‌دهد:

```text
INTERNAL ADMIN PAGE - only for 127.0.0.1
```

**نسخه ⁦Express 5⁩.** این بسته به ⁦Express 4⁩ وابسته است، پس آزمون را روی ⁦Express 5.3.0⁩ تکرار کردیم. صفحه‌ها، تغییر مسیرها، فرم‌ها و WebSocket همان‌طور کار کردند؛ npm یک نسخه جداگانه از ⁦Express 4⁩ درون خود بسته قرار داد.

## چرا باز گذاشتن سرور Node Unblocker خطرناک است؟

سرور باز به هر کسی اجازه می‌دهد از آی‌پی شما ترافیک بفرستد و به جاهایی برسد که فقط سرور شما به آن‌ها دسترسی دارد:

- **تقصیر به گردن آی‌پی شما می‌افتد.** هرزنامه فرم‌ها و تلاش‌های ورود با حدس رمز (brute-force) که از آن فرستاده شوند، از نشانی شما می‌آیند. سایت‌ها آن را مسدود می‌کنند یا به شرکت میزبانی شما شکایت می‌کنند و آن شرکت می‌تواند سرور را تعلیق کند.
- **شبکه داخلی شما در دسترس قرار می‌گیرد.** این همان جعل درخواست سمت سرور یا SSRF (Server-Side Request Forgery) است: فردی بیرونی سرور شما را وادار می‌کند نشانی‌ای را درخواست کند که خودش به آن دسترسی ندارد. در سرورهای ابری هدف کلاسیک `169.254.169.254` است، جایی که سرویس metadata اطلاعات دسترسی (credentials) را تحویل می‌دهد. [راهنمای پیشگیری از SSRF در OWASP](https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html) فهرست مجاز مقصدها و بررسی آی‌پی‌ای را که DNS برای هر نام برمی‌گرداند توصیه می‌کند.
- **سرور همه چیز را می‌خواند.** رمزگذاری HTTPS روی سرور شما تمام می‌شود، چون سرور برای بازنویسی صفحه‌ها باید آن‌ها را بخواند؛ پس رمزهایی که در سایت‌های عبوری از پروکسی تایپ می‌شوند به‌صورت متن ساده از آن می‌گذرند.
- **همه سایت‌ها یک مبدأ (origin) مشترک دارند.** مبدأ ترکیب پروتکل، دامنه و پورت است و مرورگر سایت‌ها را بر پایه آن از هم جدا می‌کند. سایت‌هایی که از پروکسی می‌گذرند فقط با مسیر کوکی از هم جدا می‌شوند و [به گفته MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie) `Path` سازوکاری امنیتی نیست. اسکریپتِ یک صفحه عبوری می‌تواند کوکی‌های سایت دیگری را که `HttpOnly` ندارند بخواند.

پروکسی وب به کسی حق تازه‌ای هم نمی‌دهد. استفاده از آن برای رسیدن به سایتی که شبکه مدرسه یا محل کار بسته است، یا برخلاف شرایط استفاده یک سایت، همچنان نقض همان قوانین است و `robots.txt` و محدودیت نرخ هر سایت درباره سرور شما هم مانند هر بازدیدکننده دیگری اعمال می‌شود.

## چگونه سرور Node Unblocker را ایمن کنیم؟

با آن مانند ابزاری داخلی برای افراد مشخص و فهرست کوتاهی از سایت‌ها رفتار کنید. نسخه ایمن‌شده این موارد را اضافه می‌کند:

1. **رمز ورود:** یک نام کاربری و رمز مشترک HTTP Basic برای تیم که با مقایسه زمان‌ثابت (constant-time) بررسی می‌شود.
2. **فهرست مجاز میزبان‌ها** فقط روی پورت‌های 80 و 443، که در `requestMiddleware` بررسی می‌شود.
3. **بررسی هر پاسخ DNS** در تابع `lookup` در agentها، چون هر دامنه‌ای می‌تواند به `127.0.0.1` اشاره کند. [`net.BlockList`](https://nodejs.org/api/net.html#class-netblocklist) در Node بازه‌های خصوصی را نگه می‌دارد و نشانی‌های IPv4 را که به شکل IPv6 نوشته شده‌اند هم تشخیص می‌دهد.
4. **حذف هدرها**، تا هدر `Authorization` تیم و آی‌پی کلاینت در `X-Forwarded-For` هرگز به سایت نرسند.
5. **محافظ WebSocket**، چون درخواست‌های upgrade از میان‌افزارهای Express عبور نمی‌کنند.
6. **محدودیت نرخ، یک سطر گزارش (log) و صفحه خطای ساده.**

```bash
npm install express unblocker express-rate-limit
```

سپس `server.mjs` را با این نسخه جایگزین کنید:

```js
import crypto from "node:crypto";
import dns from "node:dns";
import http from "node:http";
import https from "node:https";
import net from "node:net";
import express from "express";
import { rateLimit } from "express-rate-limit";
import Unblocker from "unblocker";

const { UI_USER, UI_PASS, PORT = "8080" } = process.env;
if (!UI_USER || !UI_PASS) throw new Error("Set UI_USER and UI_PASS");
const ALLOWED = ["example.com", "iana.org"]; // sites your team may open (subdomains included)

// 1. Address ranges the proxy must never connect to (loopback, private, link-local, cloud metadata)
const blocked = new net.BlockList();
for (const [range, bits] of [["0.0.0.0", 8], ["10.0.0.0", 8], ["100.64.0.0", 10], ["127.0.0.0", 8],
  ["169.254.0.0", 16], ["172.16.0.0", 12], ["192.168.0.0", 16]]) blocked.addSubnet(range, bits);
blocked.addAddress("::1", "ipv6");
blocked.addSubnet("fc00::", 7, "ipv6");
blocked.addSubnet("fe80::", 10, "ipv6");
const isBlockedIp = (ip) => blocked.check(ip, net.isIPv6(ip) ? "ipv6" : "ipv4");

// 2. Check every DNS answer before a socket opens, so an allowed name cannot point inside your network
function safeLookup(hostname, options, callback) {
  dns.lookup(hostname, options, (err, address, family) => {
    if (err) return callback(err);
    const answers = Array.isArray(address) ? address : [{ address, family }];
    if (answers.some((a) => isBlockedIp(a.address))) {
      return callback(new Error(`${hostname} resolves to a blocked address`));
    }
    callback(null, address, family);
  });
}

// 3. Only allowlisted hosts on the default ports 80/443
function isAllowed(target) {
  const { hostname, port } = new URL(target);
  return port === "" && ALLOWED.some((h) => hostname === h || hostname.endsWith(`.${h}`));
}

// Headers the site must not see: the team login and the client IP added by the reverse proxy
const STRIP = ["authorization", "forwarded", "x-forwarded-for", "x-forwarded-host", "x-forwarded-proto", "x-real-ip"];

function checkTarget(data) {
  const ok = isAllowed(data.url);
  console.log(new Date().toISOString(), ok ? "ALLOW" : "DENY", data.url);
  if (ok) {
    for (const h of STRIP) delete data.headers[h];
    return;
  }
  if (data.clientResponse) return data.clientResponse.status(403).send("This site is not on the allowlist.");
  throw new Error("Blocked WebSocket target"); // upgrade requests have no response object
}

// 4. One shared login for the team (HTTP Basic), compared in constant time
const hash = (s) => crypto.createHash("sha256").update(s).digest();
function loginOk(req) {
  const [scheme, value = ""] = (req.headers.authorization ?? "").split(" ");
  const given = Buffer.from(value, "base64").toString();
  return scheme === "Basic" && crypto.timingSafeEqual(hash(given), hash(`${UI_USER}:${UI_PASS}`));
}

const unblocker = new Unblocker({
  prefix: "/proxy/",
  requestMiddleware: [checkTarget],
  httpAgent: new http.Agent({ lookup: safeLookup }),
  httpsAgent: new https.Agent({ lookup: safeLookup }),
});

const app = express();
app.set("trust proxy", "loopback"); // the reverse proxy on this machine passes the real client IP
app.use(rateLimit({ windowMs: 60_000, limit: 600 })); // one page load can pull dozens of files
app.use((req, res, next) => {
  if (loginOk(req)) return next();
  res.set("WWW-Authenticate", 'Basic realm="preview"').status(401).send("Login required");
});
app.use(unblocker);
app.get("/", (req, res) => res.send("Open /proxy/https://example.com/"));
app.use((err, req, res, next) => {
  console.error(err.message);
  res.status(502).send("The site could not be loaded.");
});

// Listen on loopback only: HTTPS and the public port belong to the reverse proxy in front
const server = app.listen(Number(PORT), "127.0.0.1");
// Express middleware does not run for WebSocket upgrades, so check the login here as well
server.on("upgrade", (req, socket, head) => {
  if (!loginOk(req)) return socket.destroy();
  try {
    unblocker.onUpgrade(req, socket, head);
  } catch {
    socket.destroy();
  }
});
```

سرور را با اطلاعات ورود در متغیرهای محیطی اجرا کنید: `UI_USER=team UI_PASS='a-long-random-password' node server.mjs`. نتایج ما:

- بدون اطلاعات ورود، هر مسیری `401` همراه هدر `WWW-Authenticate: Basic` برگرداند.
- `example.com` و `www.iana.org` بارگذاری شدند. `example.org`، `evilexample.com`، `example.com:8443`، `127.0.0.1:9000` و `169.254.169.254` پاسخ `403` گرفتند.
- `localtest.me` دامنه‌ای عمومی است که به `127.0.0.1` اشاره می‌کند. وقتی آن را به فهرست مجاز یک نسخه آزمایشی افزودیم، درخواست `502` گرفت و در گزارش نوشته شد `localtest.me resolves to a blocked address`.
- اتصال WebSocket بدون اطلاعات ورود بسته شد. با اطلاعات ورود، اتصال به سرور اکو محلی ما با `DENY` ثبت و بسته شد؛ اتصال به `echo.websocket.org` که در فهرست مجاز بود کار کرد.
- وقتی در یک دقیقه 600 درخواست رسیده بود، درخواست‌های بعدی `429 Too Many Requests` همراه `Retry-After: 59` گرفتند.

دو تا از این لایه‌های دفاعی از آن رو وجود دارند که نسخه ساده‌تر شکست خورد. نمونه فهرست مجاز در README درخواست را با `data.clientResponse.status(403)` رد می‌کند؛ درخواست upgrade در WebSocket شیء پاسخ ندارد، پس سرور ما با `TypeError: Cannot read properties of null (reading 'status')` از کار افتاد. با بررسی null سرور از کار نیفتاد، اما WebSocket همچنان بدون اطلاعات ورود به هدف مسدودشده رسید. پرتاب خطا (throw) در `checkTarget` و گرفتن آن (catch) در handler رویداد upgrade جلوی این اتصال را می‌گیرد. و پیش از آنکه `STRIP` را اضافه کنیم، پروکسی آزمایشی ما هدر `Authorization: Basic` تیم و یک مقدار آزمایشی `X-Forwarded-For` را در راه رسیدن به سایت دید.

HTTPS را با nginx یا Caddy روی همان ماشین جلوی آن قرار دهید؛ در این حالت تنظیم `trust proxy` روی `loopback` آی‌پی واقعی کلاینت را به Express و محدودکننده نرخ می‌دهد. برای nginx، README تنظیم `merge_slashes off;` را توصیه می‌کند تا `//` در `/proxy/https://` حذف نشود. سطرهای گزارش `ALLOW` و `DENY` را نگه دارید؛ اگر سایتی بپرسد سرور شما چه کرده است، پاسخ در همین سطرهاست.

## چگونه ترافیک Node Unblocker را از پروکسی بالادستی عبور دهیم؟

پروکسی بالادستی (upstream) پروکسی‌ای است که سرور شما برای خروج به اینترنت از آن استفاده می‌کند. گزینه‌های `httpAgent` و `httpsAgent` هر agent در ⁦Node.js⁩ را می‌پذیرند، پس یک agent پروکسی نقطه خروج شما را به پروکسی منتقل می‌کند. `http-proxy-agent` و `https-proxy-agent` را نصب کنید و سپس دو سطر agent در سرور ایمن‌شده را جایگزین کنید:

```bash
npm install http-proxy-agent https-proxy-agent
```

```js
import { HttpProxyAgent } from "http-proxy-agent";
import { HttpsProxyAgent } from "https-proxy-agent";

const UPSTREAM = process.env.UPSTREAM_PROXY; // http://user:pass@pr.proxynet.io:8000

const unblocker = new Unblocker({
  prefix: "/proxy/",
  requestMiddleware: [checkTarget],
  httpAgent: new HttpProxyAgent(UPSTREAM), // http:// targets: absolute-URI requests to the proxy
  httpsAgent: new HttpsProxyAgent(UPSTREAM), // https:// targets: a CONNECT tunnel through the proxy
});
```

پروکسی آزمایشی ما `user:pass` می‌خواهد و برای هر هدف یک سطر گزارش ثبت کرد:

```text
[test-proxy] CONNECT example.com:443 auth=user
[test-proxy] GET http://example.com/ auth=user fwd-authorization=- x-forwarded-for=-
```

صفحه HTTPS از تونل `CONNECT` استفاده کرد، پس پروکسی فقط نام میزبان را دید؛ خط‌تیره‌ها نشان می‌دهند هدرهای حذف‌شده جا ماندند. با رمز نادرست، هر دو صفحه پاسخ `407 Proxy Authentication Required` پروکسی را برگرداندند. نویسه‌های `@`، `:` یا `/` را در رمز با `encodeURIComponent` کدگذاری کنید. کار با همین agentها در Axios، node-fetch و undici در نوشته [استفاده از پروکسی در ⁦Node.js⁩](/fa/blog/nodejs-proxy) آمده است.

با پروکسی بالادستی، `safeLookup` دیگر اجرا نمی‌شود، چون پروکسی نام‌ها را در شبکه خودش به آی‌پی تبدیل می‌کند؛ پس فهرست مجاز را سخت‌گیرانه نگه دارید. می‌توانید رمز را هم کنار بگذارید: آی‌پی عمومی سرورتان را در لیست سفید آی‌پی (IP whitelist) پنل کاربری وارد کنید (حداکثر 10 نشانی). [احراز هویت پروکسی: نام کاربری و رمز یا لیست سفید آی‌پی](/fa/blog/proxy-authentication-methods) این دو روش را مقایسه می‌کند.

[پروکسی دیتاسنتر](https://proxynet.io/fa/datacenter-proxy) برای تیم یک آی‌پی خروجی ثابت با ترافیک بدون سهمیه فراهم می‌کند. محصولات به‌ازای هر آی‌پی به‌طور پیش‌فرض دسترسی به مجموعه‌ای از وب‌سایت‌های هدف را دارند و دسترسی به همه وب‌سایت‌ها افزونه‌ای پولی است؛ پس بررسی کنید سایت‌های فهرست مجاز شما پوشش داده می‌شوند.

برای تست بومی‌سازی، یعنی دیدن صفحه همان‌طور که یک کاربر خانگی در کشوری دیگر می‌بیند، از خروجی [پروکسی مسکونی](https://proxynet.io/fa/residential-proxy) استفاده کنید که بر اساس کشور و شهر انتخاب می‌شود. نشست ثابت 1 تا 60 دقیقه‌ای خروجی را در طول یک فرایند چندمرحله‌ای یکسان نگه می‌دارد.

## Node Unblocker از پس چه کارهایی برنمی‌آید؟

این بسته بیشترین سازگاری را با صفحه‌های معمولی دارد که بخش عمده‌شان در سمت سرور ساخته می‌شود. README درباره بقیه موارد صریح است:

- **ورود با OAuth و `postMessage`.** ورود از طریق پنجره یک ارائه‌دهنده دیگر به احتمال زیاد کار نمی‌کند.
- **برنامه‌های تک‌صفحه‌ای بزرگ.** README چند پلتفرم شناخته‌شده چت، ویدیو و شبکه اجتماعی را نام می‌برد که کار نمی‌کنند. اسکریپت سمت کلاینت APIهای رایج درخواست را رهگیری می‌کند، اما `window.location`، `document.cookie` و `postMessage` هنوز در فهرست کارهای آینده آن هستند.
- **هر چیزی که صفحه وب نیست.** برنامه‌های دسکتاپ، کلاینت‌های ایمیل و ابزارهای خط فرمان به فوروارد پروکسی نیاز دارند.
- **نگهداری کُند.** نسخه ژوئن 2024 در اکتبر 2026 هنوز آخرین نسخه بود. فایل‌های میان‌افزار در `lib/` کوتاه‌اند؛ پیش از اینکه به این بسته تکیه کنید، آن‌ها را بخوانید.

## کاربردها

- ابزار پیش‌نمایش داخلی برای تیم QA یا بومی‌سازی که صفحه‌های خود شرکت را از راه خروجی مسکونی در کشور هدف باز می‌کند.
- کیوسکی که فقط مرورگر دارد و نمی‌تواند تنظیمات پروکسی را تغییر دهد، اما به چند سایت تأییدشده از راه یک پروکسی بالادستی دارای احراز هویت نیاز دارد.
- تیمی کوچک که از یک آی‌پی ثابت، که شریک تجاری آن را در فهرست مجاز خود گذاشته، به پورتال آن شریک وصل می‌شود.
- یادگیری سازوکار پروکسی‌های بازنویسی‌کننده: آن را با `DEBUG=unblocker:*` اجرا کنید و کار هر میان‌افزار را دنبال کنید.

در همه این موارد: فقط سایت‌هایی که اجازه استفاده از آن‌ها را دارید، با سرعتی که سایت تحملش را دارد، و هرگز برای گذشتن از یک محدودیت یا مسدودسازی.

## اشتباهات رایج

- **گوش دادن روی `0.0.0.0` بدون رمز ورود.** سرور به رله‌ای عمومی تبدیل می‌شود.
- **بررسی دسترسی فقط در میان‌افزار Express.** درخواست‌های upgrade در WebSocket هرگز به آن نمی‌رسند.
- **استفاده از `data.clientResponse` بدون بررسی در `requestMiddleware`.** این مقدار در درخواست‌های upgrade برابر `null` است و فرایند را از کار می‌اندازد.
- **اکتفا به بررسی نام میزبان.** آی‌پی‌ای را که DNS برگردانده در `lookup` مربوط به agent بررسی کنید.
- **فرستادن همه هدرهای مرورگر.** `Authorization` و `X-Forwarded-For` به هدف می‌رسند، مگر آنکه حذفشان کنید.
- **نگه داشتن صفحه خطای پیش‌فرض Express.** بیرون از حالت production، این صفحه به بازدیدکننده ما ردگیری پشته (stack trace) خطای `getaddrinfo ENOTFOUND` را نشان داد.
- **ورود به حساب‌های شخصی از طریق آن.** سرور هر رمزی را می‌بیند.

## راهنمای انتخاب

| نیاز | پیشنهاد |
|---|---|
| یادگیری سازوکار | سرور ساده روی `127.0.0.1` |
| تیمی کوچک که مجموعه ثابتی از سایت‌ها را باز می‌کند | سرور ایمن‌شده پشت ریورس پروکسی HTTPS |
| بررسی صفحه‌ها آن‌طور که بازدیدکنندگان کشوری دیگر می‌بینند | سرور ایمن‌شده با پروکسی بالادستی مسکونی |
| آی‌پی خروجی ثابتی که شریک تجاری بتواند در فهرست مجاز بگذارد | سرور ایمن‌شده، در صورت نیاز با پروکسی بالادستی دیتاسنتر |
| برنامه‌ها، اسکریپت‌ها یا کل مرورگر | فوروارد پروکسی (HTTP یا SOCKS5) |
| ورود با OAuth یا برنامه‌های وب بزرگ | مرورگر معمولی با فوروارد پروکسی |
| پروکسی عمومی برای همه | راه‌اندازی نکنید |

## پرسش‌های متداول

### آیا Node Unblocker یک VPN است؟

نه. VPN همه ترافیک یک دستگاه را از تونلی رمزگذاری‌شده عبور می‌دهد؛ Node Unblocker وب‌سایتی است که صفحه‌های دیگر را برای شما بارگذاری می‌کند. فقط آنچه زیر `/proxy/` باز می‌کنید از آن می‌گذرد و سرور آن را به‌صورت متن ساده می‌خواند.

### آیا Node Unblocker آی‌پی من را پنهان می‌کند؟

از دید سایت هدف، بله، اگر سرور جای دیگری اجرا شود: سایت آی‌پی سرور را می‌بیند. اما شما را از کسی که سرور را اداره می‌کند پنهان نمی‌کند، و پشت ریورس پروکسی آی‌پی شما در هدر `X-Forwarded-For` به سایت می‌رسد، مگر آنکه آن هدر حذف شود.

### آیا Node Unblocker با ⁦Express 5⁩ کار می‌کند؟

در آزمون ما، بله. با ⁦Express 5.3.0⁩ صفحه‌ها، تغییر مسیرها، ارسال فرم‌ها و WebSocket همان رفتاری را داشتند که روی ⁦Express 4.22.3⁩ داشتند؛ npm یک نسخه جداگانه از ⁦Express 4⁩ درون بسته نصب می‌کند.

### آیا Node Unblocker می‌تواند WebSocket را از پروکسی عبور دهد؟

بله، به شرطی که `unblocker.onUpgrade` به رویداد `upgrade` سرور متصل شده باشد. میان‌افزارهای Express آنجا اجرا نمی‌شوند، پس اطلاعات ورود و هدف را در همان handler هم بررسی کنید.

### آیا می‌توانم از Node Unblocker در محصولی تجاری استفاده کنم؟

بله، با رعایت مجوز ⁦AGPL-3.0⁩: اگر آن را تغییر دهید و نسخه تغییریافته را از راه شبکه در اختیار کاربران بگذارید، باید کد منبع آن را هم به آن‌ها عرضه کنید. به گفته README، مجوز تجاری هم از نویسنده قابل تهیه است.

### چرا ورود موفق است اما صفحه بعدی مرا از حساب خارج می‌کند؟

معمولاً سایت میان زیردامنه‌ها یا از HTTP به HTTPS جابه‌جا شده است. Unblocker کوکی‌های هر سایت را زیر مسیر جداگانه‌ای نگه می‌دارد و آن‌ها را با یک تغییر مسیر اضافه به مسیر تازه کپی می‌کند؛ به گفته کد منبع آن، ویژگی‌هایی مانند زمان انقضا در این میان از دست می‌روند.

## خلاصه

Node Unblocker سرور Express را به پروکسی وبی تبدیل می‌کند که صفحه‌ها را برای یک مرورگر معمولی بازنویسی می‌کند: بازدیدکننده `/proxy/<url>` را باز می‌کند، سرور صفحه را از آی‌پی خودش می‌گیرد، لینک‌ها، کوکی‌ها و تغییر مسیرها را بازنویسی می‌کند و آن را برمی‌گرداند. سرور ساده روی ⁦Express 4⁩ یا 5 با چند خط آماده می‌شود؛ کار اصلی ایمن کردن آن است: رمز ورود، فهرست مجاز، بررسی آی‌پی‌ای که DNS برمی‌گرداند، حذف هدرها و handler محافظت‌شده WebSocket، همه پشت HTTPS. وقتی خروجی باید جای دیگری باشد، گزینه‌های agent ترافیک را از پروکسی بالادستی عبور می‌دهند و [پروکسی‌های ما](/fa/proxy) خروجی‌های دیتاسنتر، مسکونی، موبایل و ISP ثابت را پوشش می‌دهند.
