Runbook · Балансировщик

Хост с автовыбором

Один хост в панели, который у клиента разворачивается в пул нод с автоматическим выбором лучшей.

Remnawave 3.4.4+ Xray JSON leastLoad

← Все руководства · Нода XHTTP SelfSteal · Нода-мост

ПАНЕЛЬ Виртуальный хост несёт шаблон хосты-участники · скрытые хосты-участники · видимые Нода 1 Нода 2 Нода 3 шаблон Xray JSON отбор по тегу У КЛИЕНТА Запись «Авто» BALANCER · LEASTLOAD proxy proxy-2 proxy-3 direct block вне пула
Виртуальный хост никуда не подключается — он несёт шаблон и служит той записью, которую выбирает пользователь. Ноды, перечисленные в шаблоне по UUID, попадают внутрь конфига как outbounds с генерируемыми тегами, а балансировщик выбирает между ними.

Настройка

Схема

Пользователь видит одну запись «Авто». Ноды скрыты, вручную выбрать нельзя.

Пользователь видит «Авто» плюс все ноды по отдельности и может выбрать конкретную страну.


01

Хосты-участники

Это обычные хосты на твоих нодах. Менять в них почти ничего не нужно.

ПолеЗначение
Hide hostвключить
Hide hostвыключить
Enabledвключён
Xray JSONне привязывать — шаблон нужен только виртуальному хосту

Собрать UUID

UUID берётся в карточке каждого хоста. Выпиши их в том порядке, в каком хочешь видеть теги outbounds: первый в списке станет proxy, второй proxy-2, третий proxy-3.

Порядок ни на что не влияет по существу — leastLoad всё равно сортирует по замерам. Но в логах удобнее, когда он осмысленный.

Добавил ноду — допиши UUID

Список в шаблоне фиксированный, сам он не пополняется. Новая нода попадёт в пул только после правки шаблона, и если подписок несколько — править нужно каждую.

Держи это в чек-листе при заведении новой ноды, иначе она будет стоять и не использоваться.

02

Виртуальный хост

Создай новый хост. Это та запись, которую увидит пользователь; никуда она не подключается.

ПолеЗначениеПочему
Hide hostвыключитьиначе пользователь не увидит запись с автовыбором
Enabledвключёнвыключенный не рендерится
RemarkАвтоподпись в клиенте
Address, Port, SNI, pbkзаведомо нерабочиепанель требует заполнения, но в конфиг они не попадут. Копировать сюда параметры живой ноды не надо — см. фазу 03
Inboundлюбой доступный пользователюнужен для проверки доступа по сквадам
Xray JSONконфиг из фазы 03без него балансировщика не будет вовсе
03

Шаблон Xray JSON

Балансировщик живёт целиком в шаблоне подписки. На нодах для него настраивать нечего — они не знают, что кто-то балансирует между ними.

Не путатьГде создаётсяК чему привязанЧто описывает
Config Profile
инбаунд
настройки ноднода и хостконфиг Xray на сервере
Xray JSON
шаблон
раздел Xray JSONвиртуальный хостконфиг, который получает клиент

Дальше речь только про второй. Это два отдельных шага: создать конфиг и привязать его к хосту. Одного создания недостаточно.

1 · Создать конфиг

Панель → Xray JSON → создать новый. Заменить нужно только UUID_ХОСТА_N на UUID из фазы 01 — строк в списке столько, сколько у тебя нод.

схема со скрытыми хостамисхема с видимыми хостами
{
  "remnawave": {
    "injectHosts": [
      {
        "selector": {
          "type": "uuids",
          "values": [
            "UUID_ХОСТА_1",
            "UUID_ХОСТА_2",
            "UUID_ХОСТА_3"
          ]
        },
        "selectFrom": "HIDDEN",
        "selectFrom": "NOT_HIDDEN",
        "tagPrefix": "proxy"
      }
    ]
  },
  "log": { "loglevel": "warning" },
  "dns": {
    "servers": ["1.1.1.1", "1.0.0.1"],
    "queryStrategy": "UseIPv4",
    "disableCache": false
  },
  "policy": {
    "levels": {
      "0": {
        "handshake": 4,
        "connIdle": 180,
        "uplinkOnly": 1,
        "downlinkOnly": 1
      }
    }
  },
  "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"]
      }
    }
  ],
  "outbounds": [
    { "tag": "direct", "protocol": "freedom" },
    { "tag": "block", "protocol": "blackhole" }
  ],
  "burstObservatory": {
    "subjectSelector": ["proxy"],
    "pingConfig": {
      "destination": "https://www.gstatic.com/generate_204",
      "connectivity": "http://connectivitycheck.gstatic.com/generate_204",
      "interval": "30s",
      "timeout": "5s",
      "sampling": 6
    }
  },
  "routing": {
    "domainMatcher": "hybrid",
    "domainStrategy": "AsIs",
    "rules": [
      {
        "type": "field",
        "protocol": ["bittorrent"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "network": "udp",
        "port": 443,
        "outboundTag": "block"
      },
      {
        "type": "field",
        "network": "tcp,udp",
        "balancerTag": "auto"
      }
    ],
    "balancers": [
      {
        "tag": "auto",
        "selector": ["proxy"],
        "fallbackTag": "direct",
        "strategy": {
          "type": "leastLoad",
          "settings": {
            "maxRTT": "2s",
            "expected": 3,
            "baselines": ["150ms", "300ms", "600ms"],
            "tolerance": 0.15
          }
        }
      }
    ]
  }
}

Что здесь важно не сломать

МестоЗачем так
В outbounds только direct и blockНоды панель вставляет в начало массива сама. Писать их руками нельзя
selector: ["proxy"]Совпадение по префиксу. Теги получаются proxy, proxy-2, proxy-3 — первый без номера
selectFromУказан явно и обязан совпадать со схемой. Дефолт — HIDDEN, и если ноды видимые, пул окажется пустым при полностью правильном селекторе
Префикс не должен быть началом другого тегаВозьмёшь d — селектор затянет в пул direct
network: udp, port: 443 → blockРежет QUIC: поверх TCP-туннеля HTTP/3 работает хуже, чем HTTP/2
bittorrent → directТорренты идут мимо туннеля. Нужен запрет — меняй на block
connectivityПроверка локальной сети. Без неё обрыв Wi-Fi помечает все ноды мёртвыми разом
fallbackTag: direct — это утечка

Если живых нод не осталось, трафик пойдёт мимо туннеля, с реального IP, и пользователь не заметит.

Альтернатива — block: при пустом пуле не работает ничего, зато утечки нет. Цена — возможная пауза на холодном старте. Проверь это в фазе 05 и реши.

2 · Привязать к виртуальному хосту

Открой виртуальный хост из фазы 02 и выбери в нём созданный конфиг — в форме есть поле выбора Xray JSON.

Это отдельный обязательный шаг. Виртуальный хост и есть «получатель» инжекта: панель берёт его шаблон, находит по селектору остальные хосты и складывает их внутрь как outbounds.

Участникам этот конфиг не привязывать

Шаблон нужен только виртуальному хосту. Привяжешь его и нодам — каждая станет собственным балансировщиком и затянет в себя все остальные.

В схеме со скрытыми хостами участники сами по себе вообще не рендерятся. В схеме с видимыми — рендерятся обычными записями из своих полей, и шаблон им ни к чему.

Шлюз фазы

Открой ссылку подписки — не карточку хоста, она всегда показывает vless://-превью независимо от шаблона.

Должен прийти JSON, и в нём инжектированные ноды в начале outbounds. Если пришёл список vless:// — конфиг не привязан, вернись к шагу 2.

Не давай виртуальному хосту рабочие ключи

Соблазнительно сделать виртуальный хост копией рабочей ноды — панель требует заполнить Address, SNI, pbk. Но если скопировать оттуда всё, а шаблон при этом окажется не привязан, получится ссылка, которая выглядит настоящей: клиент подключится по TCP, покажет пинг и не будет работать.

Отлаживать такое долго. Поставь виртуальному хосту адрес, который никуда не ведёт, и произвольный pbk — тогда при неприменённом шаблоне соединение честно упадёт сразу, и ошибка будет видна за секунду.

04

Настройка выбора

Значения в шаблоне рабочие. Этот раздел нужен, если поведение не устроит.

Окно наблюдателя

sampling × interval — сколько времени помнит наблюдатель.

samplingintervalОкноОдна потеряПоведение
160s1 мин100%Любой потерянный пакет выбивает ноду на минуту
330s1,5 мин33%Реагирует быстро, но нервно
630s3 мин17%В шаблоне. Терпит джиттер, ловит деградацию за минуту
1060s10 мин10%Стабильно, но упавшую ноду держит долго
sampling: 1 — главная ошибка чужих конфигов

При окне из одной пробы доля ошибок принимает два значения: 0% или 100%. В связке с низким tolerance любой потерянный пакет выбивает ноду из пула до следующей пробы. На мобильной сети ноды выпадают пачками, и балансировщик проваливается в fallback.

Параметры стратегии

ПараметрЧто делает
tolerance: 0.15Допустимая доля неудачных проб. При sampling 6 одна потеря прощается, две подряд нет
maxRTT: 2sПотолок. Ставить 1s рискованно — на плохой сети теряется весь пул
baselinesТри ступени приоритета. Набирает expected нод из первой, не хватило — добирает из следующей
expected: 3Сколько нод оставить в выборе. Больше одной — меньше переключений

Что крутить

05

Проверка

1 · Подписка

Открой ссылку подписки в браузере. В JSON должно быть:

Считай outbounds — это главная проверка

Только direct и block — инжект не сработал. Проверь: участники включены → их видимость совпадает со схемой и с selectFrom → UUID скопированы без опечаток → у пользователя есть доступ через сквад.

На один больше — виртуальный хост попал в свой же пул. Смени его тег.

Меньше — часть хостов не прошла по сквадам.

2 · Клиент

3 · Отказ

Выключи в панели ту ноду, которую выбрал балансировщик. Соединение должно восстановиться за 30–60 секунд.

Затем перезапусти клиент полностью и проверь, работает ли сеть в первые 30 секунд. Это определяет, можно ли ставить fallbackTag: "block" вместо direct.

Почему leastLoad

СтратегияКритерийСлабое место
leastLoadстабильность задержки, по отклонению RTTчетыре параметра, которые надо настроить
leastPingминимальный средний RTTигнорирует потери: нода с 20 мс и 10% потерь выглядит лучше стабильной на 60 мс
roundRobinпо очередиразные соединения идут через разные IP
randomслучайното же плюс непредсказуемая задержка
random и roundRobin ломают сессии

Они выбирают ноду на каждое соединение, а не на сессию. Страница грузится через одну ноду, картинки через другую, запрос к API с третьего IP. Результат — вылеты из аккаунтов, капчи, отказы платёжных форм.

Если встало

Пинг есть, интернета нет

Самый частый симптом и самый обманчивый: клиент показывает задержку, значит «работает», но трафик не идёт. Разбирается по порядку, каждый шаг отсекает часть причин.

Шаг 1 · открой ссылку подписки в браузере

Это отвечает сразу на три вопроса. Смотри, что там:

  • Список vless:// вместо JSON — шаблон не привязан к виртуальному хосту. Клиент подключается к его адресу-заполнителю, а пинг показывает до этого адреса. Возвращайся к фазе 03
  • JSON, но в outbounds только direct и block — инжект дал ноль хостов. Сверь UUID с карточками хостов и проверь selectFrom
  • JSON и ноды на месте — переходи к шагу 2
Один автохост работает, другой нет

Если у тебя несколько виртуальных хостов и часть работает, сравни у них только одну строкуselectFrom. Разница почти всегда там, а не в селекторе.

selectFrom не связан с типом селектора и по умолчанию равен HIDDEN. Конфиг с "selectFrom": "ALL" работает при любой видимости нод; конфиг без этой строки при видимых нодах даёт пустой пул, даже если селектор написан идеально.

Быстрый фикс — поставь "selectFrom": "ALL" в неработающий конфиг. Сработает всегда. Потом заменишь на точное значение под свою схему.

Шаг 2 · подключись к одной ноде напрямую

В схеме с видимыми хостами это делается в два тапа. В схеме со скрытыми — временно сними Hide host с одной ноды.

  • Нода напрямую тоже не работает — дело не в балансировщике. Проверяй сам хост: пустой ли Flow, поддерживает ли клиент транспорт ноды
  • Напрямую работает, «Авто» нет — дело в шаблоне, шаг 3
Шаг 3 · сверь три тега в выданном JSON

Открой JSON подписки и проверь, что они согласованы между собой:

  • теги инжектированных outbounds — proxy, proxy-2, proxy-3
  • balancers[0].selector["proxy"]
  • burstObservatory.subjectSelector["proxy"]

Расхождение между subjectSelector и selector даёт ровно этот симптом: наблюдатель замеряет ноды и показывает пинг, а балансировщик пул не находит.

Заодно сверь balancerTag в правиле роутинга с tag балансировщика — оба должны быть auto.

Шаг 4 · убери блок dns из шаблона

При domainStrategy: "AsIs" он клиенту не нужен: домены уходят на сервер и резолвятся там. А вреда может принести — запросы к 1.1.1.1 попадают под правило-перехватчик и уходят в балансировщик. Получается замкнутый круг: чтобы отрезолвить адрес ноды, нужен туннель, а чтобы поднять туннель, нужен адрес.

Симптом при этом характерный: пинг по IP проходит, а всё, что требует имён, не работает. Удали секцию dns целиком и переподключись.

Шаг 5 · сними лишние правила

Временно убери правило блокировки QUIC и правило bittorrent, оставь только правило-перехватчик с balancerTag. Если заработало — возвращай по одному.

Если не помогло, включи в клиенте показ лога Xray. И Happ, и INCY это умеют — там будет видно, на чём именно рвётся соединение.

Остальное

СимптомЧто смотреть
В подписке только direct и blockОпечатка в UUID, selectFrom не совпадает с видимостью нод, либо нет доступа через сквад
Подписка отдаёт vless://, а не JSONШаблон не привязан к виртуальному хосту
Outbounds на один больше, чем нодВиртуальный хост подошёл под свой селектор. Смени его тег
Часть нод не попала в пулСквады: у пользователя нет доступа к инбаунду этой ноды
Ноды инжектятся, клиент не подключаетсяselector балансировщика не совпадает с tagPrefix
Перескакивает между нодамиsampling мал или tolerance строг. Фаза 04
Трафик пошёл с реального IPПул опустел, сработал fallbackTag: "direct"
Балансировщик не переключается вообщеПроверка connectivity не проходит в твоей сети. Убери эту строку
Клиент ругается на конфигЧасть прослоек ждёт "stats": {} рядом с burstObservatory. Добавить безвредно

Клиенты

КлиентПоддержка
Happда, даёт выбрать балансировщик в интерфейсе
INCYда, полный конфиг включая burstObservatory
v2rayN / v2rayNGда, в JSON-режиме
Streisandда
Hiddifyшаблон не подходит — своя балансировка на sing-box

Если подписка отдаёт JSON всем без разбора, пользователи Hiddify получат непригодный для них конфиг. Либо отдельная ссылка, либо отдача шаблона по User-Agent.

Чек-лист


Механика injectHosts — по документации Remnawave, параметры leastLoad — по документации Xray и практике настройки. Выбор схемы и значения полей хранятся только в этом браузере.