Xray JSON – Advanced
Aperçu
Pour les modèles d'abonnement de type XRAY_JSON dans Remnawave, des directives Remnawave sont disponibles — des instructions spéciales que vous ajoutez au modèle JSON. Le panel les traite lors de la génération de l'abonnement et les supprime de la configuration finale — le client ne les verra jamais.
Actuellement, la directive injectHosts est disponible, permettant d'injecter dynamiquement les configurations outbound des hôtes dans le modèle. Cela est utile lorsque vous avez besoin de construire une configuration Xray complexe avec des équilibreurs de charge, un routage personnalisé ou plusieurs outbounds, les données de connexion (adresse, port, clés) étant insérées automatiquement depuis le panel.
Les configurations présentées ci-dessous sont des exemples pour démontrer le mécanisme d'injection. Adaptez-les à vos besoins.
Nécessite Remnawave version 2.6.3 ou plus récente.
Conditions de fonctionnement
- L'hôte virtuel (l'hôte auquel est assigné le modèle avec injection) doit être activé et non masqué.
- Les hôtes à injecter (sélectionnés via
selector) doivent être activés. Par défaut, seuls les hôtes masqués sont sélectionnés (le comportement peut être modifié viaselectFrom). - Tous les hôtes — aussi bien l'hôte virtuel que les hôtes à injecter — doivent être accessibles à l'utilisateur final : l'inbound auquel ils sont liés doit être inclus dans le squad de l'utilisateur.
- De l'hôte virtuel, la remarque (remark) et la description du serveur (Server Description, si définie) sont transférées dans la configuration finale.
Structure de remnawave
L'objet remnawave est ajouté au niveau racine du modèle JSON. Il prend en charge les champs suivants :
| Champ | Description |
|---|---|
injectHosts | Tableau de groupes d'injection. Chaque groupe contient un sélecteur pour la sélection des hôtes et des paramètres de formation des tags. |
addVirtualHostAsOutbound | Si true — l'hôte virtuel sera ajouté en tant qu'outbound avec le tag proxy au début du tableau outbounds. Par défaut false. Voir addVirtualHostAsOutbound. |
Le champ injectHosts est un tableau de groupes d'injection. Chaque groupe contient un sélecteur pour la sélection des hôtes et son propre tagPrefix :
"remnawave": {
"injectHosts": [
{
"selector": { "type": "uuids", "values": ["uuid-hote-1", "uuid-hote-2"] },
"tagPrefix": "proxy"
},
{
"selector": { "type": "remarkRegex", "pattern": "^RU-" },
"tagPrefix": "backup"
}
]
},
Chaque élément du tableau injectHosts :
| Champ | Description |
|---|---|
selector | Objet définissant quels hôtes seront sélectionnés. Champ obligatoire. |
selectFrom | Dans quel pool sélectionner les hôtes : "HIDDEN" (par défaut), "NOT_HIDDEN" ou "ALL". |
tagPrefix | Préfixe de tag pour les outbounds créés. Voir règles de formation des tags. |
useHostRemarkAsTag | Si true — le tag de l'outbound sera la remarque (remark) de l'hôte. |
useHostTagAsTag | Si true — le tag de l'outbound sera le tag de l'hôte (si aucun tag n'est défini, la remarque est utilisée). |
Il faut spécifier exactement un des trois champs : tagPrefix, useHostRemarkAsTag ou useHostTagAsTag.
Il peut y avoir un nombre quelconque de groupes — chacun forme son propre ensemble indépendant d'outbounds avec son propre préfixe. Cela permet, par exemple, de créer un équilibreur de charge séparé pour chaque groupe de serveurs.
Types de sélecteurs
uuids
Sélectionne les hôtes par une liste d'UUID. L'ordre des UUID détermine l'ordre des outbounds.
"selector": {
"type": "uuids",
"values": [
"8478b271-95d3-4312-85ae-ecf63fb53d1d",
"d31d6161-1315-4c1e-9a4b-141ab1c022f6"
]
}
remarkRegex
Sélectionne les hôtes dont la remarque (remark) correspond à l'expression régulière. Syntaxe — JavaScript RegExp.
"selector": {
"type": "remarkRegex",
"pattern": "^Balancer"
}
L'exemple ci-dessus sélectionnera tous les hôtes masqués dont la remarque commence par «Balancer» (par exemple, «Balancer #1», «Balancer RU»).
tagRegex
Sélectionne les hôtes dont le tag d'hôte (champ tag dans les paramètres de l'hôte) correspond à l'expression régulière.
"selector": {
"type": "tagRegex",
"pattern": "^balancer-"
}
L'exemple ci-dessus sélectionnera tous les hôtes masqués avec un tag commençant par balancer-.
sameTagAsRecipient
Sélectionne tous les hôtes masqués dont le tag d'hôte correspond au tag de l'hôte virtuel. Ne nécessite pas de paramètres supplémentaires.
"selector": {
"type": "sameTagAsRecipient"
}
Pratique lorsque vous souhaitez regrouper automatiquement les hôtes : il suffit d'attribuer le même tag à l'hôte virtuel et aux hôtes à injecter.
Par défaut, tous les sélecteurs ne travaillent qu'avec les hôtes masqués. Pour changer ce comportement, utilisez le champ selectFrom : la valeur "NOT_HIDDEN" sélectionnera uniquement les hôtes visibles (activés, mais non masqués), et "ALL" — tous les hôtes (activés, masqués).
Règles de formation des tags
Le tag d'un outbound est déterminé par lequel des trois champs est spécifié dans le groupe d'injection :
tagPrefix — Le premier hôte reçoit un tag égal à tagPrefix. Chaque suivant — {tagPrefix}-{N}, à partir de 2.
Exemple pour trois hôtes avec tagPrefix: "proxy" :
| Ordre | Tag de l'outbound |
|---|---|
| 1er | proxy |
| 2ème | proxy-2 |
| 3ème | proxy-3 |
useHostRemarkAsTag — Chaque outbound reçoit un tag égal à la remarque (remark) de l'hôte.
{
"selector": { "type": "tagRegex", "pattern": "^ru-" },
"useHostRemarkAsTag": true
}
Si les hôtes ont les remarques «Moscou», «Saint-Pétersbourg», «Kazan» — les outbounds recevront les tags Moscou, Saint-Pétersbourg, Kazan.
useHostTagAsTag — Chaque outbound reçoit un tag égal au tag de l'hôte. Si le tag de l'hôte n'est pas défini, sa remarque est utilisée.
{
"selector": { "type": "tagRegex", "pattern": "^ru-" },
"useHostTagAsTag": true
}
Correspondance par préfixe dans Xray
Les champs selector (dans routing.balancers) et subjectSelector (dans burstObservatory) dans Xray fonctionnent comme des comparateurs de préfixe — ils sont comparés au début du tag de l'outbound, pas à sa valeur exacte.
Par exemple, si la configuration contient des outbounds avec les tags proxy, proxy-2, proxy-3, direct :
| Valeur de selector / subjectSelector | Quels outbounds seront sélectionnés |
|---|---|
["proxy"] | proxy, proxy-2, proxy-3 |
["proxy-"] | proxy-2, proxy-3 |
"selector": ["proxy"]— capturera tous les outbounds injectés, y compris le premier."selector": ["proxy-"]— capturera tous sauf le premier (uniquementproxy-2,proxy-3, ...).
Le premier hôte sélectionné reçoit toujours un tag sans le suffixe -{N} (simplement proxy). Cela permet de l'utiliser comme fallbackTag dans l'équilibreur de charge : si tous les outbounds du selector sont indisponibles, le trafic ira vers le premier hôte. Pour cela, définissez "selector": ["proxy-"] (uniquement proxy-2, proxy-3, ...) et "fallbackTag": "proxy".
addVirtualHostAsOutbound
Par défaut, lors de l'utilisation de la directive remnawave, seuls les hôtes injectés entrent dans la configuration finale. L'hôte virtuel (recipient) lui-même n'est utilisé que comme source de remarks et serverDescription.
Si vous avez besoin que l'hôte virtuel devienne également un outbound avec le tag proxy, ajoutez le champ addVirtualHostAsOutbound: true au niveau de l'objet remnawave :
"remnawave": {
"addVirtualHostAsOutbound": true,
"injectHosts": [
{
"selector": { "type": "uuids", "values": ["uuid-hote-1", "uuid-hote-2"] },
"tagPrefix": "proxy"
},
{
"selector": { "type": "remarkRegex", "pattern": "^RU-" },
"tagPrefix": "backup"
}
]
}
Dans ce cas, le tableau outbounds final ressemblera à ceci :
- Outbound de l'hôte virtuel avec le tag
proxy. - Outbounds injectés (depuis
injectHosts). - Outbounds statiques du modèle (
direct,blocketc.).
Cela est utile lorsque dans les règles de routing "outboundTag": "proxy" est utilisé pour diriger le trafic via l'hôte principal, tandis que les hôtes injectés servent des groupes de trafic séparés (par exemple, via des équilibreurs de charge).
addVirtualHostAsOutbound peut être utilisé avec ou sans injectHosts. Si injectHosts n'est pas spécifié ou est vide, seul l'outbound de l'hôte virtuel sera ajouté à la configuration.
Exemple pas à pas : équilibreur de charge avec trois hôtes
Dans cet exemple, nous allons créer une configuration dans laquelle trois outbounds sont combinés dans un équilibreur de charge avec la stratégie leastLoad et surveillés par un observatory.
Étape 1. Créer les hôtes
Créez dans le panel les hôtes qui participeront à l'injection. Dans notre exemple, ce sont :
- Virtual Host — l'hôte virtuel auquel sera assigné le modèle avec injection. Il n'est pas masqué et c'est via lui que l'utilisateur final recevra la configuration.
- Balancer #1, Balancer #2, Balancer #3 — hôtes dont les outbounds seront insérés dans le modèle.
Étape 2. Masquer les hôtes à injecter
Ouvrez la fiche de chaque hôte équilibreur (Balancer #1, #2, #3), naviguez vers la section Avancé et activez le commutateur Masquer l'hôte.
Les hôtes masqués n'apparaissent pas dans l'abonnement habituel — ils ne sont accessibles que via le mécanisme d'injection.
Étape 3. Créer le modèle d'abonnement
Créez un modèle d'abonnement de type XRAY_JSON. Décrivez-y la configuration complète : dns, routing, inbounds, outbounds, burstObservatory et autres sections nécessaires.
Placez dans le tableau outbounds uniquement les outbounds statiques (direct, block) — les outbounds des hôtes à injecter seront ajoutés automatiquement.
Au niveau racine du JSON, ajoutez l'objet remnawave avec le sélecteur d'hôtes masqués.
Exemple de modèle
{
"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"
}
]
}
Notez :
"subjectSelector": ["proxy"]— l'observatory surveillera tous les outbounds dont le tag commence parproxy(c'est-à-direproxy,proxy-2,proxy-3)."selector": ["proxy"]— l'équilibreur de chargeSuper_Balancerdistribuera le trafic entre les mêmes outbounds.- Dans les
outboundsdu modèle, seulsdirectetblocksont indiqués — les outbounds des hôtes seront ajoutés automatiquement avant eux.
Étape 4. Assigner le modèle à l'hôte virtuel
Ouvrez la fiche de l'hôte virtuel (Virtual Host), naviguez vers la section Avancé et dans le champ Modèle Xray JSON sélectionnez le modèle créé.
Assurez-vous que le commutateur Masquer l'hôte pour l'hôte virtuel est désactivé — il doit être visible dans l'abonnement.
Étape 5. Résultat
Lors de la demande d'abonnement, le panel traite automatiquement :
- Prend le modèle assigné à l'hôte virtuel.
- Supprime l'objet
remnawavede celui-ci. - Pour chaque groupe dans
injectHosts, sélectionne les hôtes masqués parselectoret collecte leurs outbounds. - Insère les outbounds au début du tableau
outbounds. - Définit
remarksdepuis la remarque de l'hôte virtuel.
Configuration finale que recevra le client
[
{
"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"
}
]
Ce qui s'est passé :
- L'objet
remnawavea été supprimé de la configuration finale. - Trois outbounds (
proxy,proxy-2,proxy-3) ont été insérés au début du tableauoutbounds, avantdirectetblock. "selector": ["proxy"]dans l'équilibreur de charge a automatiquement capturé les trois outbounds, car leurs tags commencent parproxy(correspondance par préfixe)."subjectSelector": ["proxy"]dans l'observatory a également capturé les trois outbounds pour la surveillance."remarks": "Virtual Host"— pris depuis la remarque de l'hôte virtuel.
Adresse de l'hôte virtuel et inbound réel
L'hôte virtuel dans ce scénario sert d'«enveloppe» pour le modèle et les métadonnées (remarque, description du serveur), pas comme un vrai point de connexion.
Dans ses paramètres, on peut indiquer n'importe quelle adresse (par exemple, balancer.host.com) — elle ne participe pas à la connexion réelle de l'utilisateur.
Le vrai point d'entrée est l'inbound spécifique des hôtes injectés. Il est important que l'utilisateur demandant l'abonnement ait accès à cet inbound via les squads, sinon l'hôte virtuel n'apparaîtra pas du tout dans son abonnement.
Les paramètres de connexion réels (adresses, ports, clés, etc.) sont pris des hôtes injectés, dont les configurations outbound sont insérées dans la configuration finale côté client.
Remarques importantes
- L'hôte virtuel doit être activé et non masqué. C'est lui qui détermine quel modèle sera utilisé, et c'est de lui que sont tirés
remarksetdescription. - Les hôtes à injecter doivent être activés. Par défaut, seuls les hôtes masqués sont sélectionnés (
selectFrom: "HIDDEN"). Ce comportement peut être changé en"NOT_HIDDEN"ou"ALL". Si un hôte est désactivé ou introuvable par le sélecteur — il sera ignoré. - Tous les hôtes participants doivent être accessibles à l'utilisateur final — l'inbound auquel ils sont liés doit être inclus dans le squad de l'utilisateur.
- L'objet
remnawaveest supprimé de la configuration finale — le client ne le verra pas. - Les outbounds sont ajoutés au début du tableau
outbounds. SiaddVirtualHostAsOutboundest activé, l'outbound de l'hôte virtuel avec le tagproxyvient en premier, puis les injectés, puis les outbounds statiques du modèle (direct,block). - L'ordre des hôtes détermine l'ordre des outbounds et les tags qui leur sont attribués. Pour le sélecteur
uuids— l'ordre des UUID dans le tableauvalues. Au lieu detagPrefix, on peut utiliseruseHostRemarkAsTagouuseHostTagAsTagpour que les tags soient formés à partir des propriétés des hôtes. - La sélection du modèle et le masquage de l'hôte se trouvent dans la section Avancé dans la fiche de l'hôte.