إنتقل إلى المحتوى الرئيسي

Xray JSON – Advanced

نظرة عامة

بالنسبة لقوالب الاشتراك من النوع XRAY_JSON في Remnawave، تتوفر توجيهات Remnawave — وهي تعليمات خاصة تضيفها إلى قالب JSON. تعالجها اللوحة عند توليد الاشتراك وتحذفها من الإعداد النهائي — لن يراها العميل أبداً.

حالياً، يتوفر توجيه injectHosts الذي يتيح حقن إعدادات outbound للمضيفين في القالب بشكل ديناميكي. هذا مفيد عندما تحتاج إلى بناء إعداد Xray معقد يتضمن موازنات أحمال أو توجيهاً مخصصاً أو عدة outbounds، مع إدراج بيانات الاتصال (العنوان والمنفذ والمفاتيح) تلقائياً من اللوحة.

نصيحة

الإعدادات الواردة أدناه هي أمثلة لتوضيح آلية الحقن. كيّفها وفقاً لاحتياجاتك.

تنبيه

يتطلب ذلك إصدار Remnawave 2.6.3 أو أحدث.

شروط العمل

  • المضيف الافتراضي (المضيف الذي تم تعيين قالب الحقن له) يجب أن يكون مفعّلاً وغير مخفي.
  • المضيفون المحقونون (المحددون عبر selector) يجب أن يكونوا مفعّلين. بشكل افتراضي يُختار المضيفون المخفيون فقط (يمكن تغيير هذا السلوك عبر selectFrom).
  • جميع المضيفين — سواء الافتراضي أو المحقونون — يجب أن يكونوا متاحين للمستخدم النهائي: يجب أن يكون الـinbound الذي ارتبطوا به مضمّناً في squad المستخدم.
  • من المضيف الافتراضي ينتقل إلى الإعداد النهائي الملاحظة (remark) ووصف الخادم (Server Description، إن وُجد).

بنية remnawave

يُضاف كائن remnawave إلى المستوى الجذري لقالب JSON. ويدعم الحقول التالية:

الحقلالوصف
injectHostsمصفوفة من مجموعات الحقن. تحتوي كل مجموعة على محدد لاختيار المضيفين وبارامترات تكوين العلامات.
addVirtualHostAsOutboundإذا كانت true — سيُضاف المضيف الافتراضي كـoutbound بعلامة proxy في بداية مصفوفة outbounds. القيمة الافتراضية false. انظر addVirtualHostAsOutbound.

الحقل injectHosts هو مصفوفة من مجموعات الحقن. تحتوي كل مجموعة على محدد لاختيار المضيفين وtagPrefix خاص بها:

"remnawave": {
"injectHosts": [
{
"selector": { "type": "uuids", "values": ["uuid-المضيف-1", "uuid-المضيف-2"] },
"tagPrefix": "proxy"
},
{
"selector": { "type": "remarkRegex", "pattern": "^RU-" },
"tagPrefix": "backup"
}
]
},

كل عنصر في مصفوفة injectHosts:

الحقلالوصف
selectorكائن يحدد المضيفين الذين سيتم اختيارهم. حقل إلزامي.
selectFromمن أي مجموعة اختيار المضيفين: "HIDDEN" (افتراضياً)، أو "NOT_HIDDEN" أو "ALL".
tagPrefixبادئة العلامة لـoutbounds المنشأة. انظر قواعد تشكيل العلامات.
useHostRemarkAsTagإذا كانت true — ستكون علامة الـoutbound هي الملاحظة (remark) للمضيف.
useHostTagAsTagإذا كانت true — ستكون علامة الـoutbound هي علامة المضيف (إذا لم تُحدَّد العلامة، تُستخدم الملاحظة).
warning

يجب تحديد حقل واحد بالضبط من الحقول الثلاثة: tagPrefix، أو useHostRemarkAsTag، أو useHostTagAsTag.

يمكن أن يكون هناك أي عدد من المجموعات — تشكّل كل منها مجموعتها المستقلة من الـoutbounds ببادئتها الخاصة. هذا يتيح، على سبيل المثال، إنشاء موازن حمل منفصل لكل مجموعة من الخوادم.

أنواع المحددات

uuids

يختار المضيفين حسب قائمة UUID. يحدد ترتيب UUID ترتيب الـoutbounds.

"selector": {
"type": "uuids",
"values": [
"8478b271-95d3-4312-85ae-ecf63fb53d1d",
"d31d6161-1315-4c1e-9a4b-141ab1c022f6"
]
}

remarkRegex

يختار المضيفين الذين تتطابق ملاحظتهم (remark) مع التعبير النمطي. الصيغة — JavaScript RegExp.

"selector": {
"type": "remarkRegex",
"pattern": "^Balancer"
}

يختار المثال أعلاه جميع المضيفين المخفيين الذين تبدأ ملاحظتهم بـ«Balancer» (مثل «Balancer #1»، «Balancer RU»).

tagRegex

يختار المضيفين الذين تتطابق علامة المضيف (حقل tag في إعدادات المضيف) مع التعبير النمطي.

"selector": {
"type": "tagRegex",
"pattern": "^balancer-"
}

يختار المثال أعلاه جميع المضيفين المخفيين ذوي علامة تبدأ بـbalancer-.

sameTagAsRecipient

يختار جميع المضيفين المخفيين الذين تتطابق علامة مضيفهم مع علامة المضيف الافتراضي. لا يتطلب معاملات إضافية.

"selector": {
"type": "sameTagAsRecipient"
}

مفيد عندما تريد تجميع المضيفين تلقائياً: يكفي تعيين نفس العلامة للمضيف الافتراضي والمضيفين المحقونين.

تلميح

افتراضياً، تعمل جميع المحددات مع المضيفين المخفيين فقط. لتغيير هذا السلوك، استخدم حقل selectFrom: القيمة "NOT_HIDDEN" تختار المضيفين المرئيين فقط (المفعّلين وغير المخفيين)، بينما "ALL" — جميع المضيفين (المفعّلون، المخفيون).

قواعد تشكيل العلامات

تتحدد علامة الـoutbound وفقاً للحقل المحدد في مجموعة الحقن:

tagPrefix — يحصل المضيف الأول على علامة مساوية لـtagPrefix. كل تالٍ — {tagPrefix}-{N}، ابتداءً من 2.

مثال لثلاثة مضيفين مع tagPrefix: "proxy":

الترتيبعلامة الـoutbound
الأولproxy
الثانيproxy-2
الثالثproxy-3

useHostRemarkAsTag — يحصل كل outbound على علامة مساوية لـملاحظة (remark) المضيف.

{
"selector": { "type": "tagRegex", "pattern": "^ru-" },
"useHostRemarkAsTag": true
}

إذا كانت ملاحظات المضيفين «موسكو»، «سانت بطرسبرغ»، «قازان» — فستحصل الـoutbounds على العلامات Moscow، Petersburg، Kazan.

useHostTagAsTag — يحصل كل outbound على علامة مساوية لـعلامة المضيف. إذا لم تُحدَّد علامة المضيف، تُستخدم ملاحظته.

{
"selector": { "type": "tagRegex", "pattern": "^ru-" },
"useHostTagAsTag": true
}

المطابقة بالبادئة في Xray

حقلا selector (في routing.balancers) وsubjectSelector (في burstObservatory) في Xray يعملان كـمحددات بادئة — تتطابق مع بداية علامة الـoutbound، وليس قيمتها الدقيقة.

على سبيل المثال، إذا كان الإعداد يحتوي على outbounds بعلامات proxy، proxy-2، proxy-3، direct:

قيمة selector / subjectSelectorالـoutbounds التي ستُختار
["proxy"]proxy، proxy-2، proxy-3
["proxy-"]proxy-2، proxy-3
  • "selector": ["proxy"] — سيلتقط جميع الـoutbounds المحقونة، بما في ذلك الأول.
  • "selector": ["proxy-"] — سيلتقط الجميع ما عدا الأول (فقط proxy-2، proxy-3، ...).
الـFallback عبر المضيف الأول

المضيف الأول المختار يحصل دائماً على علامة بدون لاحقة -{N} (مجرد proxy). هذا يتيح استخدامه كـfallbackTag في موازن الحمل: إذا كانت جميع الـoutbounds من selector غير متاحة، سيتجه الحركة إلى المضيف الأول. لذلك حدد "selector": ["proxy-"] (فقط proxy-2، proxy-3، ...) و"fallbackTag": "proxy".

addVirtualHostAsOutbound

بشكل افتراضي، عند استخدام توجيه remnawave، فقط المضيفون المحقونون يدخلون الإعداد النهائي. المضيف الافتراضي نفسه (recipient) يُستخدم فقط كمصدر لـremarks وserverDescription.

إذا كنت تريد أن يصبح المضيف الافتراضي أيضاً outbound بعلامة proxy، أضف حقل addVirtualHostAsOutbound: true على مستوى كائن remnawave:

"remnawave": {
"addVirtualHostAsOutbound": true,
"injectHosts": [
{
"selector": { "type": "uuids", "values": ["uuid-المضيف-1", "uuid-المضيف-2"] },
"tagPrefix": "proxy"
},
{
"selector": { "type": "remarkRegex", "pattern": "^RU-" },
"tagPrefix": "backup"
}
]
}

في هذه الحالة، ستبدو مصفوفة outbounds النهائية كما يلي:

  1. Outbound المضيف الافتراضي بعلامة proxy.
  2. الـoutbounds المحقونة (من injectHosts).
  3. الـoutbounds الثابتة من القالب (direct، block وغيرها).

هذا مفيد عندما تُستخدم "outboundTag": "proxy" في قواعد الـrouting لتوجيه الحركة عبر المضيف الرئيسي، بينما تخدم المضيفون المحقونون مجموعات حركة منفصلة (مثلاً عبر موازنات الحمل).

تلميح

يمكن استخدام addVirtualHostAsOutbound مع injectHosts أو بدونه. إذا لم يُحدَّد injectHosts أو كان فارغاً، سيُضاف outbound المضيف الافتراضي فقط إلى الإعداد.

مثال تفصيلي: موازن حمل بثلاثة مضيفين

في هذا المثال، سننشئ إعداداً يُجمع فيه ثلاثة outbounds في موازن حمل باستراتيجية leastLoad ويُراقَب بواسطة observatory.

الخطوة 1. إنشاء المضيفين

أنشئ في اللوحة المضيفين الذين سيشاركون في الحقن. في مثالنا هذا:

  • Virtual Host — المضيف الافتراضي الذي سيُعيَّن إليه قالب الحقن. إنه غير مخفي وعبره سيحصل المستخدم النهائي على الإعداد.
  • Balancer #1، Balancer #2، Balancer #3 — المضيفون الذين ستُحقَن الـoutbounds الخاصة بهم في القالب.
قائمة المضيفين

الخطوة 2. إخفاء المضيفين المحقونين

افتح بطاقة كل مضيف موازن (Balancer #1، #2، #3)، انتقل إلى قسم المتقدمة وفعّل مفتاح إخفاء المضيف.

المضيفون المخفيون لا يظهرون في الاشتراك العادي — إنهم متاحون فقط عبر آلية الحقن.

إخفاء مضيفي الموازن

الخطوة 3. إنشاء قالب الاشتراك

أنشئ قالب اشتراك من النوع XRAY_JSON. صف فيه الإعداد الكامل: dns، routing، inbounds، outbounds، burstObservatory وغيرها من الأقسام المطلوبة.

ضع في مصفوفة outbounds الـoutbounds الثابتة فقط (direct، block) — ستُضاف الـoutbounds الخاصة بالمضيفين المحقونين تلقائياً.

على المستوى الجذري لـJSON أضف كائن remnawave بمحدد المضيفين المخفيين.

مثال القالب

{
"remnawave": {
"injectHosts": [
{
"selector": {
"type": "uuids",
"values": [
"8478b271-95d3-4312-85ae-ecf63fb53d1d",
"d31d6161-1315-4c1e-9a4b-141ab1c022f6",
"5749f69e-cd1b-4012-9407-450434085196"
]
},
"tagPrefix": "proxy"
}
]
},
"burstObservatory": {
"pingConfig": {
"timeout": "3s",
"interval": "1m",
"sampling": 1,
"destination": "http://www.gstatic.com/generate_204",
"connectivity": ""
},
"subjectSelector": ["proxy"]
},
"dns": {
"servers": ["1.1.1.1", "1.0.0.1"],
"queryStrategy": "UseIP"
},
"routing": {
"balancers": [
{
"tag": "Super_Balancer",
"selector": ["proxy"],
"strategy": {
"type": "leastLoad",
"settings": {
"maxRTT": "1s",
"expected": 2,
"baselines": ["1s"],
"tolerance": 0.01
}
},
"fallbackTag": "direct"
}
],
"rules": [
{
"protocol": ["bittorrent"],
"outboundTag": "direct"
},
{
"network": "tcp,udp",
"balancerTag": "Super_Balancer"
}
],
"domainMatcher": "hybrid",
"domainStrategy": "IPIfNonMatch"
},
"inbounds": [
{
"tag": "socks",
"port": 10808,
"listen": "127.0.0.1",
"protocol": "socks",
"settings": {
"udp": true,
"auth": "noauth"
},
"sniffing": {
"enabled": true,
"routeOnly": false,
"destOverride": ["http", "tls", "quic"]
}
},
{
"tag": "http",
"port": 10809,
"listen": "127.0.0.1",
"protocol": "http",
"settings": {
"allowTransparent": false
},
"sniffing": {
"enabled": true,
"routeOnly": false,
"destOverride": ["http", "tls", "quic"]
}
}
],
"outbounds": [
{
"tag": "direct",
"protocol": "freedom"
},
{
"tag": "block",
"protocol": "blackhole"
}
]
}

لاحظ:

  • "subjectSelector": ["proxy"] — سيراقب الـobservatory جميع الـoutbounds التي تبدأ علامتها بـproxy (أي proxy، proxy-2، proxy-3).
  • "selector": ["proxy"] — سيوزع موازن الحمل Super_Balancer الحركة بين نفس الـoutbounds.
  • في outbounds القالب مذكورة فقط direct وblock — ستُضاف الـoutbounds الخاصة بالمضيفين تلقائياً قبلها.

الخطوة 4. تعيين القالب للمضيف الافتراضي

افتح بطاقة المضيف الافتراضي (Virtual Host)، انتقل إلى قسم المتقدمة وفي حقل قالب Xray JSON اختر القالب المنشأ.

تأكد من أن مفتاح إخفاء المضيف للمضيف الافتراضي معطّل — يجب أن يكون مرئياً في الاشتراك.

تعيين القالب للمضيف الافتراضي

الخطوة 5. النتيجة

عند طلب الاشتراك تقوم اللوحة تلقائياً بـ:

  1. أخذ القالب المعيَّن للمضيف الافتراضي.
  2. حذف كائن remnawave منه.
  3. لكل مجموعة في injectHosts، اختيار المضيفين المخفيين حسب selector وجمع الـoutbounds الخاصة بهم.
  4. إدراج الـoutbounds في بداية مصفوفة outbounds.
  5. تعيين remarks من ملاحظة المضيف الافتراضي.

الإعداد النهائي الذي سيحصل عليه العميل

[
{
"dns": {
"servers": ["1.1.1.1", "1.0.0.1"],
"queryStrategy": "UseIP"
},
"routing": {
"rules": [
{
"protocol": ["bittorrent"],
"outboundTag": "direct"
},
{
"network": "tcp,udp",
"balancerTag": "Super_Balancer"
}
],
"balancers": [
{
"tag": "Super_Balancer",
"selector": ["proxy"],
"strategy": {
"type": "leastLoad",
"settings": {
"maxRTT": "1s",
"expected": 2,
"baselines": ["1s"],
"tolerance": 0.01
}
},
"fallbackTag": "direct"
}
],
"domainMatcher": "hybrid",
"domainStrategy": "IPIfNonMatch"
},
"inbounds": [
{
"tag": "socks",
...omitted...
},
{
"tag": "http",
...omitted...
}
],
"outbounds": [
{
"tag": "proxy",
"protocol": "vless",
"settings": {...omitted...},
"streamSettings": {...omitted...}
},
{
"tag": "proxy-2",
"protocol": "vless",
"settings": {...omitted...},
"streamSettings": {...omitted...}
},
{
"tag": "proxy-3",
"protocol": "vless",
"settings": {...omitted...},
"streamSettings": {...omitted...}
},
{
"tag": "direct",
"protocol": "freedom"
},
{
"tag": "block",
"protocol": "blackhole"
}
],
"burstObservatory": {
"pingConfig": {
"timeout": "3s",
"interval": "1m",
"sampling": 1,
"destination": "http://www.gstatic.com/generate_204",
"connectivity": ""
},
"subjectSelector": ["proxy"]
},
"remarks": "Virtual Host"
}
]

ما حدث:

  • تم حذف كائن remnawave من الإعداد النهائي.
  • تم إدراج ثلاثة outbounds (proxy، proxy-2، proxy-3) في بداية مصفوفة outbounds، قبل direct وblock.
  • التقط "selector": ["proxy"] في موازن الحمل تلقائياً جميع الـoutbounds الثلاثة، لأن علاماتها تبدأ بـproxy (المطابقة بالبادئة).
  • التقط "subjectSelector": ["proxy"] في الـobservatory بالمثل جميع الـoutbounds الثلاثة للمراقبة.
  • "remarks": "Virtual Host" — مأخوذة من ملاحظة المضيف الافتراضي.
ملاحظة

عنوان المضيف الافتراضي والـinbound الحقيقي

يعمل المضيف الافتراضي في هذا السيناريو كـ«غلاف» للقالب والبيانات الوصفية (الملاحظة، وصف الخادم)، وليس نقطة اتصال حقيقية. في إعداداته يمكن تحديد أي عنوان (مثلاً balancer.host.com) — إنه لا يشارك في الاتصال الفعلي للمستخدم. نقطة الدخول الفعلية هي الـinbound المحدد للمضيفين المحقونين. المهم أن يكون للمستخدم الذي يطلب الاشتراك وصول إلى هذا الـinbound عبر الـsquads، وإلا فلن يظهر المضيف الافتراضي في اشتراكه أصلاً. تُؤخذ بارامترات الاتصال الفعلية (العناوين والمنافذ والمفاتيح وغيرها) من المضيفين المحقونين، حيث تُحقَن إعدادات الـoutbound الخاصة بهم في الإعداد النهائي على جانب العميل.

ملاحظات مهمة

  • يجب أن يكون المضيف الافتراضي مفعّلاً وغير مخفي. إنه الذي يحدد القالب المُستخدَم، ومنه تُؤخذ remarks وdescription.
  • يجب أن يكون المضيفون المحقونون مفعّلين. بشكل افتراضي يُختار المضيفون المخفيون فقط (selectFrom: "HIDDEN"). يمكن تغيير هذا السلوك إلى "NOT_HIDDEN" أو "ALL". إذا كان المضيف معطّلاً أو لم يُعثر عليه بالمحدد — فسيُتخطى.
  • جميع المضيفين المشاركين يجب أن يكونوا متاحين للمستخدم النهائي — الـinbound الذي ارتبطوا به يجب أن يكون مضمّناً في squad المستخدم.
  • كائن remnawave يُحذَف من الإعداد النهائي — لن يراه العميل.
  • تُضاف الـoutbounds في بداية مصفوفة outbounds. إذا كانت addVirtualHostAsOutbound مفعّلة، يأتي outbound المضيف الافتراضي بعلامة proxy أولاً، ثم المحقونة، ثم الـoutbounds الثابتة من القالب (direct، block).
  • ترتيب المضيفين يحدد ترتيب الـoutbounds والعلامات المعيَّنة لها. بالنسبة للمحدد uuids — ترتيب UUIDs في مصفوفة values. بدلاً من tagPrefix يمكن استخدام useHostRemarkAsTag أو useHostTagAsTag لتشكيل العلامات من خصائص المضيفين.
  • اختيار القالب وإخفاء المضيف موجودان في قسم المتقدمة في بطاقة المضيف.