پیکربندی ماژول‌های Provisioning

← بازگشت به راهنما

پیکربندی ماژول‌های Provisioning



> version: 1.35 | last_updated: 2026-09-23 | audience: admin

ماژول‌های موجود



| کلید | کاربرد |
|------|--------|
| `manual` | فعال‌سازی دستی توسط اپراتور (مثلاً Dedicated بدون نصب خودکار) |
| `ibsng` | IBSng — FTTH/ADSL/Wireless (JSON-RPC) |
| `netbill` | NetBill Enterprise — AAA/Ghasedak |
| `radius` | RADIUS عمومی (simulated) |
| `cpanel` | هاستینگ (WHM) |
| `directadmin` | هاستینگ (DirectAdmin API) |
| `plesk` | هاستینگ (Plesk XML API) |
| `hestia` | هاستینگ (HestiaCP) |
| `cyberpanel` | هاستینگ (CyberPanel) |
| `webuzo` | هاستینگ (Webuzo) |
| `ispconfig` | هاستینگ (ISPConfig) |
| `aapanel` | هاستینگ (aaPanel) |
| `zpanel` | هاستینگ (zPanel / Sentora-style API) |
| `proxmox` / `virtualizor` / `vmware` / `autovm` | VPS / هایپروایزر |
| کلودهای عمومی (`hetzner`, `digitalocean`, `gcore`, …) | دستهٔ جدا «کلود عمومی» — [cloud-vps-provisioning.md](cloud-vps-provisioning.md) |
| `nocps` | Dedicated Server — نصب OS با NOC-PS |
| `domain` | ثبت دامنه |

دسته‌بندی در Select



در **سرور بیرونی جدید** و **محصول → تب فنی / Provision** گزینه‌ها گروه‌بندی می‌شوند:

| گروه | مثال |
|------|------|
| فروش اینترنت | ibsng, netbill, radius |
| فروش میزبانی | cpanel, plesk, … |
| VPS / هایپروایزر | proxmox, virtualizor, vmware, autovm |
| کلود عمومی | hetzner, digitalocean, gcore, … |
| فروش سرور اختصاصی / دامنه / انطباق | nocps, domain, shahkar |
| عمومی | manual |

پیاده‌سازی: `ProvisioningModuleOptions` — گزینه‌ها با پیشوند دسته (`کلود عمومی — Hetzner`) و Select **قابل‌جستجو** (نه native؛ native در RTL متن را نصف می‌کرد).

مستندات:
  • [IBSng](ibsng-provisioning.md)

  • [NetBill](netbill-provisioning.md)

  • [VPS (Proxmox/Virtualizor/VMware/AutoVM)](vps-provisioning.md)

  • [Dedicated + NOC-PS](dedicated-nocps-provisioning.md)

  • [Product Custom Fields](product-custom-fields.md)


  • صف ساخت سرویس (Create)



    ساخت اکانت روی سرور مقصد **هم‌زمان با پرداخت/fulfill سفارش اجرا نمی‌شود**. بعد از سفارش:

  • ردیف در جدول `provisioning_queue` با `action=create` و `status=queued` درج می‌شود

  • اشتراک روی `pending` و `provisioning_status=queued` می‌ماند؛ سفارش می‌تواند fulfilled باشد

  • Worker هر دقیقه (`provisioning:process-queue`) تا ۳ بار تلاش می‌کند (backoff ۱ / ۵ / ۱۵ دقیقه)

  • چک لایسنس ماژول از **tenant همان اشتراک** است (نه فقط TenantContext درخواست وب) تا خطای کاذب «ماژول در لایسنس مجاز نیست» در صف نیاید

  • **موفق:** ردیف به `provisioning_completed` منتقل می‌شود و اشتراک Active می‌شود

  • **۳ شکست:** `status=exhausted` و `provisioning_status=failed` — اشتراک **Terminated نمی‌شود**

  • منوی tenant **Provisioning → صف ساخت سرویس**: لیست همه وضعیت‌ها (فیلتر اختیاری)، بج تعداد exhausted، اکشن‌های **ارسال مجدد** و **لغو** (ارسال مجدد برای queued / processing گیرکرده / exhausted؛ بعد از آپدیت دیگر خطای `fresh() → null` نمی‌دهد)


  • **لغو از منو:** اگر اکانت ریموت ساخته نشده باشد، اشتراک Terminated می‌شود تا دامنه آزاد گردد.

    Suspend / Unsuspend / Terminate همچنان هم‌زمان (sync) هستند؛ **Create** و **ChangePackage** (تغییر پلن میان‌دوره) صف می‌شوند.

    صف تغییر پلن (`change_package`)



    بعد از پرداخت سفارش میان‌دوره:

  • فاکتور/بستانکاری مالی همان موقع ثبت می‌شود

  • پلن در پنل مشتری **عوض نمی‌شود**؛ `metadata.pending_plan_change` + ردیف صف با `action=change_package` و `payload`

  • Worker همان `provisioning:process-queue` پکیج ریموت را عوض می‌کند

  • **موفق:** `product_offering` / نام محصول مشتری به‌روز می‌شود و pending پاک می‌شود. تنظیمات محصول با `mergeProductConfigIntoProvisioningData` روی `provisioning_data` می‌نشیند (scrub مقادیر «null» رشته‌ای؛ **رمز و هویت instance بازنویسی نمی‌شود**)

  • **شکست:** پلن مشتری همان قبلی می‌ماند؛ job در منوی صف برای Retry/Cancel دیده می‌شود


  • صف تمدید دوره (`renew`)



    بعد از پرداخت فاکتور تمدید خودکار (کرون): کار `action=renew`:

  • اگر ماژول `supportsRemoteRenew()=true` → اول API تمدید سرور مقصد (`renew`)

  • سپس جلو بردن `ends_at` / `next_billing_at` در BSS

  • اگر ماژول API تمدید ندارد (`false`، پیش‌فرض) → فقط BSS


  • فعلاً: `netbill` = true؛ هاستینگ/manual/VPS و … = false (در صورت نیاز روی همان ماژول override کنید).

    جزئیات: [subscription-renewal.md](subscription-renewal.md)

    دکمه‌های «Provisioning» روی سفارش/اشتراک همان صف را پر می‌کنند و یک تلاش فوری می‌زنند.

    ```bash
    php artisan provisioning:process-queue --limit=20
    ```

    Scheduler باید در crontab باشد (`schedule:run` هر دقیقه) — [cron-jobs.md](cron-jobs.md). ADR: ADR-048.

    تنظیم سرور بیرونی



    منو: **تنظیمات → پیکربندی سرورهای بیرونی**

    | ترتیب | زیرمنو | کار |
    |-------|--------|-----|
    | ۱ | **سرورهای بیرونی** | ثبت سرور (popup وسط صفحه) + تست اتصال |
    | ۲ | **گروه‌بندی سرورها** | ساخت گروه (popup وسط صفحه) و assign سرور با اولویت |

  • اول سرور را بسازید (نام، ماژول، `config`)

  • **تست اتصال** از لیست یا صفحهٔ ویرایش؛ همیشه به API واقعی می‌زند (حتی اگر Sandbox روشن باشد)

  • بعد گروه بسازید و سرور را به گروه اضافه کنید


  • اگر Sandbox روشن باشد، تست اتصال همچنان واقعی است؛ فقط عملیات ایجاد/تعلیق اکانت واقعی اجرا نمی‌شود و در پیام موفقیت یادآوری می‌شود.

    cPanel / WHM — احراز هویت



    کلیدهای اتصال در `config` سرور:

    | کلید | توضیح |
    |------|--------|
    | `whm_host` | آدرس WHM **با `https://`** (مثال: `https://server.example.com`) — بدون scheme تست فریبنده می‌شود |
    | `whm_port` | پورت (پیش‌فرض `2087`) |
    | `whm_username` | نام کاربری (معمولاً `root`) |
    | `whm_token` | API Token — اگر پر باشد رمز نادیده گرفته می‌شود |
    | `whm_password` | رمز عبور WHM — فقط وقتی توکن خالی است |
    | `verify_ssl` | `0` / `1` |

  • با **توکن**: هدر `Authorization: whm USER:TOKEN`

  • با **رمز**: Basic Auth (`USER` / `PASSWORD`)


  • تست اتصال فقط وقتی موفق است که WHM JSON معتبر و شمارهٔ نسخه برگرداند. رمز/توکن غلط → `Access denied`. ریدایرکت به صفحهٔ ورود (مثلاً host بدون `https://`) دیگر «موفق» حساب نمی‌شود.

    حداقل یکی از `whm_token` یا `whm_password` لازم است.

    DirectAdmin — اتصال و پکیج



    کلیدهای اتصال سرور:

    | کلید | توضیح |
    |------|--------|
    | `host` | آدرس **بدون پورت** (مثال: `http://1.2.3.4` یا `https://da.example.com`) |
    | `port` | پیش‌فرض `2222` |
    | `username` / `password` | Admin یا Reseller با دسترسی API |
    | `verify_ssl` | `0` / `1` (گواهی self-signed → `0`) |

    | عملیات | API |
    |--------|-----|
    | تست | `CMD_API_SHOW_RESELLER_IPS` (fallback: `CMD_API_PACKAGES_USER`) |
    | لیست پکیج | `CMD_API_PACKAGES_USER` |
    | ساخت اکانت | `CMD_API_ACCOUNT_USER` |
    | تعلیق / رفع | `CMD_API_MODIFY_USER` (`suspended=yes/no`) |
    | حذف | `CMD_API_SELECT_USERS` |
    | تغییر پکیج | `CMD_API_CHANGE_USER_PACKAGE` |
    | Login As | `CMD_API_LOGIN_KEYS` |

    روی محصول با ماژول `directadmin`، بعد از انتخاب **گروه سرور**، فیلد `plan` مثل cPanel به‌صورت Select از API پر می‌شود (مثلاً `1GB` / `5GB` / `10GB`).

    **نکته:** یوزر/رمز اتصال سرور (`username`/`password`) برای لاگین API است؛ نام کاربری اکانت مشتری از دامنه ساخته می‌شود. اگر Reseller مقدار `shared` را برای IP نپذیرد، ماژول خودکار اولین IP از `CMD_API_SHOW_RESELLER_IPS` را می‌فرستد.

    سایر پنل‌های هاستینگ — پکیج و مصرف



    سرویس یکپارچهٔ `HostingPackageOptions` برای همهٔ ماژول‌های هاستینگ زیر، بعد از انتخاب **گروه سرور**، فیلد `plan` را به‌صورت Select از `listPackages` همان سرور پر می‌کند:

    | ماژول | لیست پکیج (خلاصه) | مصرف زنده (خلاصه) | سطح اطمینان |
    |--------|-------------------|-------------------|-------------|
    | `cpanel` | WHM `listpkgs` | `StatsBar::get_stats` | کامل (تأییدشده) |
    | `directadmin` | `CMD_API_PACKAGES_USER` | `SHOW_USER_USAGE` + `CONFIG` (GET) | کامل (تأییدشده) |
    | `plesk` | XML service-plan | `domain --info` (دیسک/ترافیک) | کامل روی API استاندارد |
    | `hestia` | `v-list-user-packages` JSON | `v-list-user` JSON | کامل روی API استاندارد |

    نکتهٔ Hestia: endpoint باید `…/api/` **با اسلش انتهایی** باشد. بدون اسلش nginx ۳۰۱ می‌دهد، POST به GET تبدیل می‌شود و پاسخ `HTTP 405 data received is null or invalid` می‌آید. کلاینت BSS همیشه `/api/` می‌زند. IP سرور BSS هم باید در whitelist API پنل Hestia باشد.
    | `cyberpanel` | `fetchPackages` / مشابه | محدود — اغلب فقط دیسک دامنه | best-effort |
    | `webuzo` | `listplans` / `list_plans` | آمار اکانت از API | وابسته به نسخه |
    | `ispconfig` | `client_templates_get_all` | `client_get` (quota) | session API شکننده بین نسخه‌ها |
    | `aapanel` | `get_site_types` / plugin package | دیسک سایت (پهنای باند اغلب نیست) | وابسته به نسخه |
    | `zpanel` | `get_packages` | `get_account` | وابسته به فورک API |

    ISPConfig — اتصال و SSL



    | کلید | توضیح |
    |------|--------|
    | `host` | آدرس با `https://` (مثال: `https://89.45.68.167`) — ارقام فارسی در UI نرمال می‌شوند |
    | `port` | Remote API (پیش‌فرض `8080`) → مسیر `/remote/json.php` |
    | `username` / `password` | **Remote User** از System → Remote Users (نه لزوماً ادمین پنل) |
    | `verify_ssl` | `0` یا `1` — برای گواهی self-signed حتماً **`0`** |

    اگر مقدار `verify_ssl` رشتهٔ `"null"` / خالی / `"false"` باشد، BSS آن را **خاموش** می‌گیرد (قبلاً `(bool)"null"` در PHP برابر true بود و خطای cURL ۶۰ می‌داد).

    خطای `SSL certificate problem: self signed certificate` → `verify_ssl=0` و ذخیره مجدد سرور، سپس **تست اتصال**.

    API این نسخه متد را در **query** می‌خواهد (`POST …/remote/json.php?login`)، نه فیلد `method` داخل JSON. کلاینت BSS همین سبک را استفاده می‌کند؛ پیام «Method not provided in json call» یعنی فراخوانی اشتباه بوده و اصلاح شده است.

    اگر بعد از رفع SSL/متد پیام «ورود ناموفق / Username or password wrong» آمد، یوزر/رمز Remote API را در ISPConfig چک کنید و دسترسی‌های لازم برای `client_*` / `sites_*` را بدهید.

    **ساخت اکانت:** `client_add` + `sites_web_domain_add`. فیلدهای اجباری `language` (مثلاً `en`) و `ssh_chroot` (مثلاً `no`) و `web_php_options` از قالب مشتری کپی می‌شوند. خطای `language_error_empty` / `ssh_chroot_notempty` یعنی این فیلدها خالی رفته‌اند (در BSS دیگر پیش‌فرض دارند). پلن محصول باید نام قالب ISPConfig باشد (مثلاً `1GB` / `5GB` / `10GB`).

    CRUD مشترک روی کلاینت‌ها: `createAccount` / `suspendAccount` / `unsuspendAccount` / `terminateAccount` (+ تغییر پکیج/SSO جایی که ماژول قبلاً داشته). شکل نرمال مصرف برای پورتال:

    ```php
    [
    'disk_used_mb' => float,
    'disk_limit_mb' => ?float, // null = نامحدود
    'bandwidth_used_mb' => float,
    'bandwidth_limit_mb' => ?float,
    'counters' => [['key','label','used','limit'], ...],
    ]
    ```

    `HostingUsageService` برای همهٔ کلیدهای بالا گیج دیسک/پهنای باند (و نوار شمارنده‌ها در صورت وجود) می‌سازد. اگر API پنل داده ندهد، پیام خطا در ویجت مصرف نشان داده می‌شود — نه گیج خالی ساکت.

    اتصال به محصول



  • **تنظیمات → محصولات و پلن‌ها**

  • فیلد **provisioning_module** = `radius` / `cpanel` / `plesk` / ...

  • **گروه سرور** را انتخاب کنید

  • **provisioning_config** — تنظیمات اختصاصی محصول


  • انتخاب پکیج از API سرور



    برای هر ماژول هاستینگ در جدول بالا، بعد از انتخاب **گروه سرور**، فیلد `plan` به‌صورت Select از API همان سرور پر می‌شود (نه تایپ دستی). اگر اتصال قطع باشد، پیام خطا زیر تنظیمات Provision نمایش داده می‌شود.

    برای ماژول **Proxmox** همان الگو روی `node` / `storage` / `template_vmid` / `iso_image` / `bridge` است (`ProxmoxInventoryOptions`). `bridge` اگر خالی باشد `vmbr0` است. قالب‌های متعدد در فیلد سفارش `iso` برای مشتری می‌آیند (خودکار با انتخاب گروه سرور). با انتخاب قالب محصول، `disk_key` و `cloudinit_drive` از تنظیمات VM پر می‌شوند. اگر `iso` سفارش یا `iso_image` محصول volid فایل ISO باشد، VM خالی با CD-ROM ساخته می‌شود (نصب از کنسول). جزئیات: [vps-provisioning.md](vps-provisioning.md).

    در **تنظیمات Provision** محصول فقط `plan`، `ns1`، `ns2` (و فیلدهای خاص ماژول در صورت وجود) دیده می‌شود — فیلد `domain` اینجا نیست. دامنه هنگام **خرید** از فیلد سفارش `domain` گرفته می‌شود. اگر `ns1`/`ns2` پر شوند، در اطلاعات فنی سرویس مشتری (و ریسلر) نمایش داده می‌شوند. بعد از provision، نام کاربری و رمز در مدیریت سرویس مشتری نمایش داده می‌شود.

    مصرف زنده در مدیریت هاست (پورتال / ریسلر)



    صفحهٔ «مدیریت هاست» و جزئیات سرویس (`HostingPanelSsoService` + `HostingUsageService`) مصرف را زنده از پنل می‌خواند — جدول بالا. نمایش: گیج مایع دیسک و پهنای باند ماهانه + در صفحهٔ جزئیات، نوار ایمیل / دیتابیس / FTP / دامنه (در صورت پشتیبانی پنل).


    **یکتایی دامنه:** اگر همان دامنه روی سرویس با وضعیت `pending` / `active` / `suspended` (یا سفارش باز draft/acknowledged/in_progress) باشد، خرید رد می‌شود با پیام ثابت «این دامنه در سیستم وجود دارد…». چک زنده هنگام تایپ در فیلد دامنه (`GET /hosting/domain-check`). سرویس `terminated` دامنه را آزاد می‌کند.

    **ایمیل تماس WHM:** هنگام `createacct` فیلد `contactemail` از ایمیل ثبت‌نامی مشتری (`party` / کاربر پورتال) پر می‌شود.

    **لغو سرویس:** از صفحه سفارش/اشتراک با «لغو سرویس». اگر اکانت در WHM ساخته نشده باشد (pending/failed)، فقط در BSS لغو می‌شود و وقتی همهٔ اشتراک‌های سفارش تمام شوند وضعیت سفارش هم `cancelled` می‌شود.

    نام کاربری WHM از بخش اول دامنه ساخته می‌شود (مثلاً `mahdi.com` → `mahdi`) و با قوانین WHM (فقط حروف کوچک و عدد، حداکثر ۱۶ کاراکتر) sanitize می‌شود. رمز عبور قوی تولید می‌شود تا از فیلتر strength رد نشود.

    **یکتایی دامنه:** اشتراک‌های `active` / `suspended` و `pending` (از جمله صف `queued` / `failed`) دامنه را اشغال می‌کنند؛ `terminated` آزاد است. آیتم سفارش باز فقط تا قبل از ساخت اشتراک قفل می‌کند — بعد از ساخت اشتراک، چک سفارش همان آیتم را تداخل حساب نمی‌کند (باگ ORD-038).

    مدیریت سرویس (از سفارش)



    **سفارش و اشتراک → سفارش‌ها → مشاهده** — بخش «سرویس»

  • **Provisioning** — قرار دادن در صف ساخت + یک تلاش فوری

  • **تعلیق / فعال‌سازی / لغو سرویس**


  • **Provisioning → صف ساخت سرویس** — موارد exhausted / در صف؛ ارسال مجدد یا لغو

    لاگ



    هر عملیات در جدول `provisioning_logs` ثبت می‌شود و در UI دیده می‌شود:

    | سطح | مسیر نمایش |
    |------|------------|
    | ادمین tenant | **اشتراک → مشاهده** — بخش «لاگ Provisioning» |
    | ادمین tenant | **سفارش → مشاهده** — زیر هر سرویس، لیست لاگ همان اشتراک |
    | ادمین tenant | **صف ساخت سرویس** — آخرین خطای job؛ آرشیو موفق در `provisioning_completed` |
    | پورتال مشتری | **سفارش‌ها → جزئیات** و **سرویس‌ها → جزئیات** |
    | پنل ریسلر | **سفارش → جزئیات** و **سرویس مشتری → جزئیات** |

    ستون‌ها: عملیات (برچسب فارسی)، وضعیت (موفق/ناموفق)، پیام، زمان شمسی.

    نکته



  • `ibsng` و `netbill`: اتصال webservice واقعی + **sandbox** برای تست

  • `radius`: ماژول generic شبیه‌سازی‌شده (legacy)