Режим статических учётных данных для внешних хостов

Примечание: русская версия была переведена с английского с помощью ИИ. Оригинал на английском языке приведён ниже. Прошу простить возможные неточности в переводе.

Прежде всего, спасибо за подтверждение того, что ранее описанная ошибка со сбросом выделения хостов, а также функция allowlist для внутренних сквадов будут исправлены или добавлены в следующем релизе. Благодарю вас за работу над Remnawave и внимание к предложениям сообщества.

Описание задачи

Я хотел бы предложить возможность добавлять в подписку пользователя временный внешний прокси-сервер, который не управляется Remnawave Node.

Например, основные ноды могут временно быть:

  • недоступны;
  • заблокированы со стороны провайдера пользователя;
  • отключены из-за технических работ;
  • недоступны из определённого региона.

В такой ситуации администратор может иметь доступ к другому внешнему серверу с VLESS, Trojan, Shadowsocks или Hysteria2 и захотеть временно добавить его в подписки пользователей.

Этот внешний сервер не должен:

  • управляться через Remnawave Node;
  • получать список пользователей из панели;
  • использовать уникальные данные авторизации каждого пользователя;
  • передавать статистику трафика в Remnawave.

Он должен просто появляться в подписке как дополнительный временный вариант подключения.

Ограничение текущего поведения

Обычный Host уже может использовать произвольный адрес, а выбранные Nodes являются только визуальной привязкой. Поэтому сам адрес внешнего сервера не является проблемой.

Проблема заключается в учётных данных.

Сейчас при генерации подписки Remnawave автоматически использует индивидуальные данные пользователя:

  • VLESS — UUID пользователя;
  • Trojan — пароль пользователя;
  • Shadowsocks — пароль пользователя;
  • Hysteria2 — индивидуальное значение авторизации пользователя.

Внешний сервер с одним заранее настроенным статическим UUID или паролем не сможет принять эти индивидуальные данные.

Предлагаемое решение

Вместо создания полностью отдельной сущности External Host можно добавить в существующую форму Host настройку:

Источник учётных данных

  • Per-user credentials / Учётные данные пользователя — текущее поведение;
  • Static credentials / Статические учётные данные — новое поведение для внешнего или неуправляемого сервера.

По умолчанию все существующие и новые хосты должны использовать текущее значение Per-user credentials, чтобы сохранить полную обратную совместимость.

При выборе Static credentials форма может показать только одно дополнительное поле, соответствующее протоколу выбранного Inbound:

  • VLESS — статический UUID;
  • Trojan — статический пароль;
  • Shadowsocks — статический пароль или credential, соответствующий выбранному методу шифрования;
  • Hysteria2 — статическое значение auth или пароль.

Получение остальных параметров из Inbound

Чтобы не создавать новый сложный интерфейс для ручной настройки transport, TLS, REALITY, WebSocket, gRPC, XHTTP и других параметров, внешний Host может продолжить использовать существующий Inbound из Config Profile.

Выбранный Inbound будет использоваться только как источник конфигурации:

  • protocol;
  • transport;
  • security;
  • flow;
  • encryption method;
  • SNI;
  • path;
  • public key и short ID для REALITY;
  • TLS и остальные параметры подключения.

Адрес, порт и при необходимости существующие Host Overrides по-прежнему задаются в форме Host.

Такой Inbound не обязательно должен быть активирован на Remnawave Node. Администратор может создать Inbound, соответствующий конфигурации внешнего сервера, и использовать его только для генерации подписки.

Это позволит избежать разработки отдельного ручного конструктора всех протоколов и transport-параметров.

Генерация подписок

Статический Host должен добавляться рядом с обычными Host, а не заменять их.

Он должен поддерживаться во всех форматах подписки, в которых поддерживается выбранный протокол:

  • Xray Base64;
  • Xray JSON;
  • Mihomo;
  • Clash;
  • Stash;
  • Sing-box;
  • RAW subscription response.

Особенно важна поддержка Xray Base64, поскольку не все пользователи используют Mihomo или другие структурированные шаблоны.

Для Base64 Remnawave должен сгенерировать обычную ссылку с указанными статическими данными:

  • vless://STATIC-UUID@…
  • trojan://STATIC-PASSWORD@…
  • ss://…
  • hysteria2://STATIC-AUTH@…

Предположительно, для этого не потребуется отдельная реализация каждого генератора. После того как Host будет преобразован в обычный ResolvedProxyConfig со статическими учётными данными, существующие генераторы смогут обработать его так же, как остальные Host.

Разумеется, Host должен появляться только в тех форматах и клиентах, которые поддерживают выбранный протокол.

Доступ для внутренних сквадов

Для статического Host должны применяться те же правила видимости, что и для обычных Host:

  • доступ для всех подходящих сквадов;
  • исключение выбранных внутренних сквадов;
  • планируемый режим Allow only selected Internal Squads.

Это позволит:

  • показать аварийный Host всем пользователям;
  • показать его только определённым сквадам;
  • исключить конкретные сквады;
  • постепенно включать временный сервер только для затронутых групп пользователей.

Управление и отключение

Для управления можно использовать существующие функции Host:

  • Host Visibility;
  • Enable/Disable;
  • теги;
  • порядок отображения;
  • исключения по типу подписки;
  • Internal Squad visibility.

Администратор предполагается владельцем или оператором внешнего сервера. Поэтому после завершения аварийной ситуации он может:

  1. отключить статический Host в Remnawave;
  2. отозвать или изменить статический UUID/пароль непосредственно на внешнем сервере.

Таким образом, даже если клиент сохранил старую конфигурацию и ещё не обновил подписку, администратор сможет немедленно прекратить доступ, отозвав credential на внешнем сервере.

Поскольку статический credential является общим, Remnawave не должен пытаться рассчитывать индивидуальное потребление трафика или управлять пользователями этого внешнего сервера.

В интерфейсе можно показать небольшое предупреждение:

Этот Host использует общие статические учётные данные. Индивидуальный учёт трафика и отзыв доступа для отдельного пользователя недоступны.

Предлагаемый минимальный объём первой версии

Чтобы уменьшить объём разработки, первая версия может включать только:

  1. переключатель источника учётных данных;
  2. одно поле для статического UUID, пароля или auth;
  3. обязательный выбор существующего Inbound;
  4. использование существующих настроек Host и Internal Squad visibility;
  5. поддержку существующих генераторов подписок, включая Base64.

Полностью ручной редактор протокола, transport и security-параметров можно не добавлять.

Ожидаемое поведение

  • Существующие Host продолжают использовать индивидуальные данные пользователей.
  • Static Host использует один заданный администратором credential для всех получателей.
  • Static Host отображается рядом с обычными Host.
  • Остальные параметры подключения наследуются от выбранного Inbound.
  • Static Host не требует подключения к Remnawave Node.
  • Remnawave не добавляет пользователей на внешний сервер.
  • Трафик через внешний сервер не учитывается в статистике Remnawave.
  • Функция работает с Base64 и другими поддерживаемыми форматами.
  • Правила Internal Squad visibility применяются так же, как для обычных Host.
  • После отключения Host он исчезает при следующем обновлении подписки.
  • Администратор может немедленно отозвать credential непосредственно на внешнем сервере.

Возможное название

Название External Host может пересекаться по смыслу с уже существующими External Squads.

Возможные более точные варианты:

  • Static-Credential Host;
  • Unmanaged Host;
  • External Endpoint;
  • Subscription-Only Host.

На мой взгляд, наиболее понятным вариантом интерфейса будет не новый тип Host, а настройка:

Credential source: Per-user / Static

Я понимаю, что даже такой сокращённый вариант затрагивает backend, frontend, API-контракты и тестирование нескольких протоколов. Если реализация займёт слишком много времени или не соответствует текущим планам проекта, я полностью это понимаю.

Спасибо за рассмотрение предложения.

Думаю, что дополнительной реализации не требуется, так как уже существует Mapper в Advanced настройках Хоста.

Спасибо за объяснение. Я изучил схему Mapper и код генераторов. Насколько я понял, с помощью Mapper действительно можно задать фиксированные данные авторизации для структурированных форматов подписки. Например, фиксированный UUID VLESS можно установить в следующих полях:

  • Xray JSON: settings.vnext.0.users.0.id
  • Mihomo/Stash: uuid
  • sing-box: uuid

Однако я не смог найти способ сделать то же самое для Xray Base64. В описании Mapper указано, что операции base64 применяются только к query string сгенерированной ссылки.

В ссылке VLESS UUID находится вне query string:

vless://UUID@address:port?parameters#remark

Поэтому операция Mapper с параметром uuid, как мне кажется, только добавит ?uuid=…, но не заменит настоящий UUID перед символом @. Похожая проблема возникает с паролями Trojan и Hysteria2, а в Shadowsocks данные авторизации находятся в закодированной части ссылки перед @.

Возможно, я неправильно понимаю, как нужно использовать эту часть Mapper. Не могли бы вы привести пример, как с помощью Mapper заменить настоящий UUID VLESS в ссылке Xray Base64 на фиксированный UUID?

Предполагаемый сценарий использования — временный внешний endpoint, который использует одни и те же фиксированные данные авторизации для всех пользователей и добавляется в их подписки, включая Xray Base64, а не только Mihomo и другие структурированные форматы.

Если сейчас это невозможно, возможно, Mapper можно было бы расширить, чтобы он позволял изменять credential/authentication-компонент Base64-ссылки, а не только её query-параметры. Я полностью понимаю, если реализация этого сейчас не является приоритетной задачей.

English version

Thank you for the explanation. I looked through the Mapper schema and generator code. As I understand it, Mapper can set a fixed credential for structured subscription formats. For example, a fixed VLESS UUID can be written to:

  • Xray JSON: settings.vnext.0.users.0.id
  • Mihomo/Stash: uuid
  • sing-box: uuid

However, I could not find a way to do the same for Xray Base64. The Mapper description says that base64 operations are applied only to the query string of the generated share link.

In a VLESS link, the UUID is outside the query string:

vless://UUID@address:port?parameters#remark

Therefore, setting a uuid parameter through the Base64 Mapper appears to produce ?uuid=…, rather than replacing the actual UUID before @. The same issue appears to apply to Trojan and Hysteria2 credentials, while a Shadowsocks link stores its credentials in the encoded authority section.

Perhaps I am misunderstanding how this part of Mapper should be used. Could you please provide an example showing how to replace the actual VLESS UUID in an Xray Base64 share link with a fixed UUID?

The intended use case is an external temporary endpoint that uses the same fixed credential for every user and appears in their subscriptions, including Xray Base64—not only Mihomo or other structured formats.

If this is not currently possible, perhaps Mapper could be extended to modify the credential/authentication component of a Base64 share link, in addition to its query parameters. I completely understand if implementing this is not currently a priority.

Да, вы правы. В текущем виде невозможно для base64 заменить данные, которые не находятся в query-параметрах.

Вы можете запретить использование bas64 через Response Rules, чтобы ваши пользователи не получали подписку такого формата. Однако, разумеется, требуется чтобы клиентские приложение поддерживали другой формат подписки – Xray-Json и так далее.

Для base64, возможно, в следующей версии появятся дополнительные опции.

Реализация для изменения параметров в base64 готова. Будет доступна в следующей версии.