# Marzban-node — آینه‌ی آفلاین

نصب Marzban-node بدون هیچ دسترسی به اینترنت بین‌الملل: اسکریپت، داکر، پلاگین
compose، ایمیج و باینری‌های جانبی همه از همین دامنه سرو می‌شوند.

## نصب

```bash
curl -fsSL --retry 5 --retry-delay 2 --connect-timeout 20 \
  https://git.nimbaha.org/marzban/marzban-node.sh -o /tmp/marzban-node.sh \
  && sudo bash /tmp/marzban-node.sh install
```

دستور بالادست این است:

```bash
sudo bash -c "$(curl -sL https://github.com/Gozargah/Marzban-scripts/raw/master/marzban-node.sh)" @ install
```

روی سرور ایرانی دو مشکل دارد: `raw.githubusercontent.com` (که GitHub به آن
ریدایرکت می‌کند) و `get.docker.com` و Docker Hub هر سه در دسترس نیستند.

### اگر DNS سرور ناپایدار است

```bash
curl -fsSL --resolve git.nimbaha.org:443:85.9.112.198 \
  https://git.nimbaha.org/marzban/marzban-node.sh -o /tmp/marzban-node.sh \
  && sudo bash /tmp/marzban-node.sh install
```

## چه چیزی تغییر کرده

| مورد | بالادست | اینجا |
|---|---|---|
| تشخیص IP سرور | `curl ifconfig.io` | `ip route get` — بدون هیچ درخواست شبکه |
| نصب داکر | `curl get.docker.com \| sh` | تاربال استاتیک ۲۹٫۹٫۳ + unit فایل systemd |
| پلاگین compose | از مخزن توزیع | باینری v5.7.0 در `cli-plugins` |
| ایمیج | `docker pull` از Hub | `docker load` از tar محلی + `pull_policy: never` |
| `jq` | `apt install jq` | باینری استاتیک ۱٫۸٫۲ |
| Xray-core | `api.github.com` + `github.com` | JSON ثابت + zip آینه‌شده |
| yq | GitHub releases | آینه‌شده (amd64/arm64/arm/386) |
| self-update | `github.com/$FETCH_REPO` | مسیر آینه |

نکته‌ی مهم درباره‌ی `NODE_IP`: آن خط در بالادست **قبل از** تفسیر دستور اجرا
می‌شود و اسکریپت با `set -e` است. یعنی روی سروری که `ifconfig.io` را نمی‌بیند،
حتی `marzban-node status` هم بی‌هیچ پیامی می‌مرد. حالا آدرس از خود کرنل
خوانده می‌شود.

## میرور موقت بسته‌های سیستمی

نصب `jq` و `curl` از مخزن توزیع انجام می‌شود. اگر آن مخزن در دسترس نباشد،
اسکریپت مخازن را **موقتاً** به میرور ایرانی سوییچ می‌کند و با `trap` روی
`EXIT INT TERM` بایت‌به‌بایت برمی‌گرداند — همان مکانیزم PasarGuard، با
بکاپ در `/var/backups/ir-mirror-sources`.

همچنین `$PKG_MANAGER update` در تابع تشخیص پکیج‌منیجر با `|| true` همراه شده؛
وگرنه با `set -e` اسکریپت قبل از رسیدن به مرحله‌ی میرور می‌مرد.

## نسخه‌ها

| مورد | نسخه |
|---|---|
| ایمیج | `gozargah/marzban-node:latest` |
| Docker | 29.9.3 (static) |
| Compose | v5.7.0 |
| Xray-core | v26.10.31 |
| jq | 1.8.2 (static) |

ایمیج برای `amd64` (۷۷MB) و `arm64` (۷۵MB) آینه شده است.

## محدودیت‌ها

- **یک نسخه‌ی Xray.** منوی `core-update` فقط `v26.10.31` را نشان می‌دهد، چون
  فقط همین نسخه آینه شده است. `M` (ورود دستی نسخه) هم فقط برای همین نسخه
  معتبر شمرده می‌شود.
- تگ ایمیج `latest` است؛ برای انتشار نسخه‌ی جدید `sync-marzban.sh` را اجرا کن.

## رله‌ی SNI برای `raw.githubusercontent.com`

از روی این سرور `github.com`، `api.github.com` و `download.docker.com` مستقیم
جواب می‌دهند، ولی `raw.githubusercontent.com` تایم‌اوت می‌شود — و اسکریپت
بالادست مرزبان دقیقاً روی همین هاست است. یک رله روی `85.9.112.219` همان SNI را
سرو می‌کند، پس درخواست با `--resolve` به آن پین می‌شود:

```bash
curl -fsSL --resolve raw.githubusercontent.com:443:85.9.112.219 \
  https://raw.githubusercontent.com/Gozargah/Marzban-scripts/master/marzban-node.sh
```

گواهی TLS همچنان با سرتیفیکیت واقعی همان دامنه اعتبارسنجی می‌شود
(`ssl_verify_result=0`)، یعنی رله محتوا را عوض نمی‌کند. سرعت اندازه‌گیری‌شده:
۳۱KB اسکریپت در ۰٫۴ ثانیه، ۱۶٫۷MB در ۱٫۶ ثانیه (≈۱۰MB/s).

اگر رله از کار بیفتد، sync با پیام `could not reach upstream` نسخه‌ی فعلی را
نگه می‌دارد و بقیه‌ی مراحل را ادامه می‌دهد — cron هرگز میرور را با فایل ناقص
خراب نمی‌کند. با `SNI_RELAY=<ip>` می‌توان رله‌ی دیگری داد.

## ساختار

```
marzban/
├── marzban-node.sh             ← نصب از این
├── github/Gozargah/…           مسیر بالادست، میزبان عوض شده
├── github/XTLS/…               Xray zip
├── github/mikefarah/yq/…       yq
├── api/repos/XTLS/Xray-core/releases     لیست نسخه‌ها (JSON)
├── api/xray-tags/v26.10.31               اعتبارسنجی نسخه
├── bin/docker-static/          داکر استاتیک، دو معماری
├── bin/compose/                پلاگین compose
├── bin/jq/                     jq استاتیک
├── images/                     ایمیج به صورت docker-archive
└── versions.json
```

## نگهداری

```bash
/usr/local/bin/sync-marzban.sh                     # ایمیج را چک کن و دوباره پچ کن
/usr/local/bin/sync-marzban.sh --script new.sh     # اسکریپت جدید بالادست
/usr/local/bin/verify-marzban.sh                   # اعتبارسنجی کامل
```

`patch-marzban.py` هر جایگزینی را assert می‌کند: اگر بالادست تغییر کند و
الگویی پیدا نشود، با خطا متوقف می‌شود.
