Обзор
SMProxy App — это бесплатный кроссплатформенный клиент для Vless/Reality, VMess, Trojan, Shadowsocks, Socks, WireGuard и AmneziaWG на ядре Xray. Приложение не поставляет серверы и не предоставляет VPN-сервис — пользователь импортирует подписку (конфигурацию) от провайдера и подключается. Доступно на iOS, iPadOS, macOS, Apple TV, Android, Android TV, Windows и Linux.
Это универсальный клиент: он импортирует конфигурацию и подключается. Всё остальное — брендинг, маршрутизация, срок действия, статистика — определяется тем, что провайдер присылает в ответе на запрос подписки и настройками аккаунта провайдера.
Документация опубликована в машинно-читаемом виде: Claude Code, Cursor, Codex и другие MCP-клиенты читают настоящие форматы заголовков и ссылок, а не выдумывают их.
claude mcp add --transport http smproxy-docs https://gitmcp.io/SMProxy/docsДобавление подписки
Три способа импорта:
Тело подписки может быть списком ссылок vless://…, base64-блобом или JSON-конфигами. Вся маршрутизация, брендинг и срок действия приходят в заголовках ответа (раздел 04).
Deep-links (smproxy://)
smproxy://add?url=<url-encoded https URL>smproxy://add/<https URL> · add/<base64 URL>smproxy://crypt1/<base64 AES-GCM зашифрованного URL>smproxy://addhw/<base64 AES-GCM {"u":url,"h":hwid}>smproxy://import/<data>smproxy://onadd/<url>smproxy://connect · opensmproxy://disconnect · closesmproxy://togglesmproxy://statusШифрование использует общий ключ AES-256-GCM; addhw привязывает ссылку к одному устройству (защита от «расшаривания»). Тап по ссылке проходит через обработчик deep-links; вставка в форму добавления разрешает те же формы.
Ссылки других клиентов — вставленные или отсканированные. Формы выше принимаются с любой схемой, если ссылку вставили в форму добавления или отсканировали камерой приложения: happ://add/<url>, incy://import/<data>, v2raytun://import/<url>, streisand://import/<url>, <что угодно>://install-sub?url=…, sub://<base64 url> (Shadowrocket). Зашифрованные ссылки других клиентов (happ://crypt4/, incy://crypt1/) расшифровать нельзя — приложение так и скажет. Приложение не перехватывает happ:// / incy:// в системе на Android, iOS и macOS; на Windows и Linux регистрирует их только если другого обработчика нет, так что установленный Happ или INCY свои ссылки не теряет.
Заголовки запроса (клиент → сервер)
Каждый запрос подписки несёт эти заголовки, чтобы панель могла опознать устройство и привязать к нему подписку (скачивание профиля маршрутизации несёт только User-Agent, скачивание гео-баз — ничего):
X-Hwidaddhw. У каждого клиентского приложения своя схема HWID, поэтому устройство, привязанное в другом клиенте, для панели будет другим HWID.X-Device-OsAndroid · iOS · macOS · tvOS · Windows · LinuxX-Ver-Os16, 18.6, 10.0.26200X-Device-ModelSM-S942B, iPhone16,2, PCX-Device-Localeru_RU и т.п. — язык и регион устройстваX-App-Version2.0.5 (422) — маркетинговая версия + билд одной строкойX-App-Build422 — номер билда отдельно — по нему и ориентироваться (Android 423+, Apple 313+, desktop 199+; старые сборки шлют только X-App-Version и User-Agent)User-AgentSMProxy/<версия>/<билд>-<ОС> — например SMProxy/2.0.5/422-Android. Используйте, когда разным сборкам нужно отдавать разный контентИмена заголовков регистронезависимы.
User-Agent — один формат на всех платформах
SMProxy/<маркетинговая версия>/<билд>-<ОС>SMProxy/2.0.5/422-AndroidSMProxy/2.0.9/312-iOSSMProxy/2.0.9/312-macOSSMProxy/2.0.9/312-tvOSSMProxy/2.0.2/198-WindowsSMProxy/2.0.2/198-LinuxОтправляется при каждом запросе подписки и при скачивании профиля маршрутизации по URL. Ориентироваться нужно на номер билда — третий сегмент растёт с каждым релизом и никогда не повторяется, а маркетинговая версия может не меняться несколько билдов подряд. Панель, которая отдаёт разным сборкам разный контент, разбирает его так:
^SMProxy/[^/]+/(\d+)-(Android|iOS|macOS|tvOS|Windows|Linux)$Метаданные подписки
Ответ эндпоинта подписки — это тело (список серверов) плюс метаданные (брендинг, срок действия, обновления). Метаданные можно передать двумя способами, и клиент читает оба.
Profile-Title: My VPN
#profile-title: My VPN
#key: value в теле используется, только если одноимённого заголовка нет. Это позволяет отдавать метаданные тем, кто не может задавать заголовки (статический хостинг, файлы в Telegram и т.п.).
1 / on / true / yes означают включено, а 0 / off / false / no — выключено.
s-fragment, s-dns, s-noise, s-resolve — присланное вами значение важнее собственного переключателя пользователя, включая off. Переключатель пользователя работает только тогда, когда вы не прислали ничего. Так сделано намеренно: эти параметры обязаны совпадать с тем, что ожидает ваш сервер, и самостоятельное включение пользователем просто разорвало бы соединение.
Живые обновления подписки
Провайдер может менять настройки обхода и маршрутизацию подписки, не дожидаясь следующего перезапроса подписки: изменения, сделанные в кабинете провайдера, доходят до подключённых устройств за считаные минуты и применяются без переподключения — новые значения вступают в силу при следующем подключении. Действуют те же правила, что и для HTTP-заголовков выше, — в частности, они учитываются только пока провайдер активен. Механизм доставки внутренний для приложения: на стороне эндпоинта подписки ничего реализовывать не нужно.
Синтаксис строки в теле
- •Начинается с # , затем ключ [A-Za-z0-9-]+ , затем значение.
- •Двоеточие необязательно — #profile-title My VPN тоже сработает.
- •Ключ регистронезависим.
- •Первое вхождение ключа побеждает, повторы игнорируются.
- •Тело сканируется и как есть, и после полного base64-декодирования — работает и для текста, и для одного base64-блоба (обычный формат vless-ссылок).
- •Из тела читаются только ключи из таблицы ниже; строки с другими ключами игнорируются.
Текстовые поля можно закодировать, добавив префикс base64: — работает и в заголовке, и в теле. Применимо к profile-title, s-title, announce, sub-expire-button-text.
#profile-title: base64:0JzQvtC5IFZQTg== → «Мой VPN»
Ключи
Каждый ключ работает и как заголовок Ключ: значение, и как строка тела #ключ: значение. Все — бесплатно.
Брендинг и ссылки
profile-title / s-titles-sitename🔒s-siteurl🔒s-tgbot / x-tgbot🔒support-urlannounceannounce-url🔒support-email🔒profile-web-page-urlСтатус подписки и продление
subscription-userinfosub-expire / s-showexpire🔒sub-expire-button-text🔒sub-expire-button-link-site🔒sub-expire-button-link-tg🔒notification-subs-expire🔒Обновление и данные
profile-update-intervalfallback-url🔒geoipurl / geositeurlsort-order🔒Миграция и доступ
new-url🔒new-domain🔒fallback-domains🔒hide-settings🔒Идентификация
providerid / s-provideridsubidОбход блокировок
s-noise🔒s-resolve🔒s-fragment🔒s-dns🔒Баннер провайдера — banner-*
Баннер на карточке подписки, показывается только при активном provider id (совместимо с INCY). Цвета — только #RRGGBB; всё остальное игнорируется, и берётся цвет темы приложения. Цвет надписи на кнопке подбирается автоматически по яркости кнопки, поэтому остаётся читаемым и на светлом, и на тёмном фоне.
banner-text🔒base64: — текст баннера, до 5 строкbanner-button-text🔒base64:, до 25 символов — надпись на кнопкеbanner-button-url🔒banner-bg-color🔒#RRGGBB — фон баннераbanner-button-color🔒#RRGGBB — фон кнопкиПараметры обхода — сводка
Сводка по четырём заголовкам обхода; подробный разбор каждого — в разделе 08.
s-fragmenton | off | packets=<tlshello|1-3|all>;length=<min-max>;interval=<min-max>[;maxsplit=<n>] · по умолчанию, если прислано только on: packets=tlshello;length=50-100;interval=10-20s-noise (s-noises)on | off | type=<rand|str|hex>;packet=<value>;delay=<min-max> · по умолчанию, если прислано только on: type=rand;packet=50-100;delay=10-20s-resolveon | off | <doh-url>[;ip=<bootstrap>][, …] · по умолчанию, если прислано только on: встроенный резолверs-dnson | off | <doh-url> · по умолчанию, если прислано только on: встроенный резолвер (dnsforge.de)Совместимость с именами заголовков INCY / Happ
Если вы уже настраиваете другой клиент, приложение понимает и его отдельные ключи и сворачивает их в эквивалентную настройку. Наш заголовок s-* всегда важнее — ключи ниже читаются только когда соответствующего s-* нет. *-enable: 0 — явное выключение.
fragmentation-enable · fragmentation-packets · fragmentation-length · fragmentation-interval · fragmentation-maxsplits-fragmentnoises-enable · noises-type / noises-packet-type · noises-packet · noises-delay · noises-rands-noiseserver-address-resolve-enable · server-address-resolve-dns-domain · server-address-resolve-dns-ips-resolvenoises-rand: <n> превращается в type=rand;packet=<n>. noises-rand-range не поддерживается.
Откуда может прийти значение и что важнее: 1) HTTP-заголовок ответа — высший приоритет; 2) строка #ключ: значение в теле (а для команд маршрутизации — строка *://routing/… без префикса) — используется, если заголовка нет; 3) собственная настройка приложения — если провайдер ничего не присылает. Для четырёх заголовков обхода значение провайдера важнее переключателя пользователя, включая off.
Текстовые значения принимаются как обычный UTF-8 или с префиксом base64:; любое значение заголовка может прийти и зашифрованным как crypt1/.
Миграция URL: new-url / new-domain
Перенацеливают сохранённый URL подписки — провайдер может переехать, а пользователю не нужно добавлять подписку заново.
- •
new-url— заменяет URL целиком (любой формат), один и тот же для всех подписок. - •
new-domain— меняет только хост (схема, порт, путь, query сохраняются); каждая подписка хранит свой путь/токен — безопасно для персональных URL. Если присланы оба — побеждаетnew-url.
Применяется, только если в том же ответе есть providerid И у этого провайдера provider_active == true. Мигрируются все локальные подписки с этим providerId. Флаг locked сохраняется: подписка из crypt1/addhw остаётся заблокированной на новом URL.
Алиасы для совместимости (Happ / INCY)
Заголовки, которые используют другие клиенты, читаются как их аналоги в SMProxy, когда заголовка SMProxy нет — панель, написанная под Happ или INCY, работает без изменений. Алиасы принимаются и в HTTP-заголовках, и в теле подписки в форме #key: value.
subscription-nameprofile-title — запасное имя INCYcontent-disposition: attachment; filename="x.txt"profile-title — имя файла без .txt / .yaml / .yml; самый низкий приоритетhomepageprofile-web-page-url — INCYhide-urlhide-settings — 1/true скрывает, 0/false открываетsub-info-textbanner-text — Happ «расширенные объявления»; 0 = баннера нетsub-info-button-text / sub-info-button-linkbanner-button-text / banner-button-urlsub-info-color (red · blue · green)banner-bg-color — переводится в hex-цветsub-expire-button-linksub-expire-button-link-tg для t.me / tg://, иначе sub-expire-button-link-site — одиночная форма Happrouting-enable: 0routing: routing/off — Happ «выключить маршрутизацию»subscription-userinfo: 0expire=<миллисекунды> в subscription-userinfoПри наличии обоих заголовков побеждает заголовок SMProxy.
↑ К оглавлениюОписание сервера
Подпись для конкретного сервера, которая показывается под его названием вместо стандартной метки протокола (VLESS | TCP | Reality). Пригодится, чтобы сказать то, чего метка не скажет — Netflix / стриминг, для игр, 10 Гбит/с. В отличие от ключей выше передаётся не на всю подписку, а вместе с каждым отдельным сервером.
s-fragment и s-dns. Без активного Provider ID приложение показывает метку протокола.
serverDescriptionВ share-ссылках
Внутри #fragment, после названия, через ?:
vless://uuid@host:443?security=reality&type=tcp#🇳🇱 Нидерланды?serverDescription=0J3QsNC00ZHQttC90YvQuQ==Тот же синтаксис работает для vless://, trojan://, ss:// и socks://.
В vmess-ссылках
Поле внутри base64-закодированного JSON:
{ "ps": "🇳🇱 Нидерланды", "add": "host", "port": "443", "serverDescription": "0J3QsNC00ZHQttC90YvQuQ==" }В JSON-конфигах
Внутри объекта meta рядом с remarks — здесь значение указывается обычным текстом, без base64:
{
"remarks": "🇳🇱 Нидерланды",
"meta": { "serverDescription": "Netflix / стриминг" },
"outbounds": [ … ]
}В ссылках значение, которое не является корректным base64 или декодируется в пустоту, игнорируется — сервер сохраняет метку протокола, а не показывает сломанный текст.
↑ К оглавлениюСкрытие URL подписки — hide-settings
hide-settings: 1 не даёт URL подписки и её содержимому покинуть устройство. Подписка переходит ровно в то же состояние, что зашифрованная (crypt1) или привязанная к устройству (addhw): внутри приложение считает «заблокирована» и «скрыта провайдером» одним и тем же условием.
Что блокируется
Что продолжает работать
Подключение, пинг, статистика трафика, обновление подписки, список серверов, выбор сервера, профили маршрутизации, интерфейс окончания подписки — пользователь просто не видит адрес и не может его выгрузить.
Значения и поведение
10crypt1 с этой подписки, если провайдер её ставил. Так задумано: ссылка принадлежит провайдеру, поэтому явный 0 от активного провайдера открывает подписку полностью.0.Любое значение, кроме 1 и 0, игнорируется и пишется в лог как «значение не распознано» — on / off / true / false здесь не принимаются.
Принимается как HTTP-заголовок ответа, как #hide-settings: 1 в теле и из кабинета провайдера. Работает только при активном provider id — неактивный или неизвестный провайдер не может ни скрыть, ни раскрыть ничего.
Два канала, одно правило: кто задал значение, тот его и снимает
Одни и те же ключи могут приходить двумя путями — в ответе подписки (HTTP-заголовок или строка #ключ:) и из кабинета провайдера (доходит до подключённых устройств за считаные минуты). Работает одно правило:
Коротко: кто записал последним — тот и прав, а убрать значение может только та сторона, которая его поставила. Именно так снимается объявление или баннер — очистите его в кабинете, и он исчезнет при следующем обновлении; ответ подписки продолжает отдавать то, что в нём есть.
Поля без «пустого» состояния — название подписки, брендовые ссылки, hide-settings — автоматически не очищаются: чтобы изменить их, пришлите новое значение.
⚠️ Правило действует для всех ключей, включая обход (s-fragment, s-noise, s-resolve, s-dns) и маршрутизацию: если вы задали s-fragment в кабинете, а потом убрали его там, фрагментация выключится при следующем обновлении.
Provider ID
Provider ID связывает подписку с аккаунтом провайдера, чтобы провайдер видел статистику использования своей подписки. Он ничего не ограничивает — приложение полностью работает и без него. Бесплатно.
…?providerid=<ProviderID>#providerid <ProviderID>providerid: или s-providerid:Если указано несколько — приоритет у HTTP-заголовка. Свой Provider ID (и возможность задать свой произвольный) вы получаете в кабинете провайдера — см. раздел 08.
🔒Требует активного Provider ID
s-fragment s-noise s-noises s-resolve s-dns — и их аналоги из INCY/Happ fragmentation-* noises-* server-address-resolve-*new-url new-domain fallback-url fallback-domainss-siteurl s-sitename s-tgbot x-tgbot sort-order serverDescriptionbanner-text banner-button-text banner-button-url banner-bg-color banner-button-color announce-url support-emailsub-expire s-showexpire sub-expire-button-text sub-expire-button-link-site sub-expire-button-link-tg notification-subs-expirehide-settings✓Работает и без Provider ID
profile-title / s-titleprofile-update-intervalprofile-web-page-urlannounceannounce-url (кликабельность) требует активного провайдераsupport-urlsubscription-userinfosubidrouting autorouting routing-update-url routing-update-interval routing-profilegeoipurl / geositeurlГейт работает одинаково независимо от того, как пришло значение: HTTP-заголовок, строка #ключ: в теле или кабинет провайдера.
Подтверждение домена — статистика без Provider ID
Статистика работает только тогда, когда приложение знает ваш Provider ID. Если сборка его не отправляет — старый релиз, клиент, который вы не контролируете, конфиг, добавленный вручную — такие check-in никуда не попадают, и вы теряете из виду собственных пользователей.
Подтвердите домен, с которого раздаются ваши подписки, и check-in без Provider ID будут автоматически засчитываться вам — по URL подписки, который сообщает приложение.
Name: smproxy-verification.your-domain.com
Value: 8f3a91c24b774c1e9a025e6d1f0b7c33Что покрывается
Поддомены включены. Подтверждение example.com покрывает sub.example.com, eu.sub.example.com и любую другую глубину — добавлять их отдельно не нужно.
Сопоставление идёт по регистрируемому домену, поэтому многоуровневые суффиксы обрабатываются корректно: example.co.uk — домен, которым можно владеть, co.uk — нет, а evil-example.com никогда не совпадёт с example.com.
Домен принадлежит одному провайдеру. Если его уже подтвердил кто-то другой, повторное добавление отклоняется.
Приоритет — Provider ID важнее
Подтверждение домена никогда не перебивает явный Provider ID — оно только закрывает пробел, когда его нет или он непригоден.
Где виден домен
- •Статистика — разбивка Домены подписок: сколько устройств использует каждый хост, и хост под
subidкаждого устройства. Хосты показываются полностью, поэтомуsub.example.comотличим отsub3.example.com. - •Сообщения — можно отправить сообщение на домен:
*.example.com— домен и все его поддомены, либо отдельный хост — только его пользователям.
Показывается только хост — токены подписки из URL не отображаются никогда.
↑ К оглавлениюПеревод пользователей на другой домен
Домен подписок заблокировали — или вы просто переезжаете на новый. Оба случая решаются из кабинета: в панели менять ничего не нужно, пользователям заново добавлять подписку тоже.
Оба правила привязаны к домену, на который пришёл запрос, поэтому их можно держать несколько одновременно — по одному на поддомен — и удалять по отдельности.
Переезд — new-domain
Откройте provider.smproxy.io/provider/domains, нажмите Перенести рядом с подтверждённым доменом и выберите:
- •Откуда —
*.example.com, чтобы перенести подписки со всего домена вместе с поддоменами, или отдельный хост видаsub.example.com, чтобы перенести только его. - •Куда — новый хост. Он должен быть подтверждён в том же аккаунте, чтобы никто не мог направить ваших пользователей на домен, которым не владеет.
После этого каждый запрос подписки, пришедший на старый хост, получает заголовок new-domain, и приложение само перезаписывает адрес. У каждого пользователя сохраняются его путь и токен:
old.example.com/sub/abc123 → new.example.com/sub/abc123b.example.com уже есть свой переезд, сделать его получателем другого нельзя — пользователи получили бы адрес, который тут же переезжает снова.
Запасные домены — fallback-domains
Нажмите Запасные рядом с доменом и перечислите хосты для отката, по одному в строке. Каждый должен быть вашим подтверждённым доменом. Список отправляется как fallback-domains для запросов на этот домен, и приложение перебирает его по порядку, если основной хост перестал отвечать.
Переезд — когда вы действительно переехали; запасные домены — когда основной адрес может стать недоступным и вы хотите, чтобы приложение само нашло дорогу.
Два канала доставки
Оба правила доходят до приложения двумя независимыми путями:
- •Заголовки ответа подписки —
new-domain/fallback-domains, как описано выше. Требуется, чтобы запрос всё ещё доходил до одного из ваших доменов. - •Собственный сервисный канал приложения — приложение получает
new-domain/fallback-domains, настроенные вами для этого домена, и по своему сервисному соединению, без запроса подписки. Они применяются при следующем обновлении подписки:new-domainперенацеливает сохранённый URL навсегда, запасные хосты сохраняются и используются, когда основной хост перестаёт отвечать.
Второй канал важен, когда домен подписки уже недоступен: он идёт через собственные сервисные адреса приложения, поэтому существующие пользователи получат переезд или список запасных доменов, даже если саму подписку скачать не могут.
Требуется сборка приложения конца августа 2026 года или новее; более старые сборки работают только через заголовки.
↑ К оглавлениюИдентификатор подписки — subid
Какую проблему решает. Когда вы выдаёте пользователю новый URL подписки — переезд домена, перевыпуск токена, смена панели — приложение не может понять, что это та же самая подписка. Оно добавляет вторую запись, и у пользователя оказывается две копии одного и того же.
Передайте subid — и это прекратится: при совпадении subid приложение считает подписку той же самой, заменяет её URL на новый и обновляет серверы на месте.
subid: my-sub-42#subid: my-sub-42 в теле подписки…?subid=my-sub-42HTTP-заголовок побеждает комментарий в теле, а тот — значение из URL. Формат: буквы, цифры, -, _ и пробелы ([A-Za-z0-9 _-]+). Всё остальное игнорируется — значение просто не сохраняется.
subid необязателен. Без него всё работает ровно как раньше — дубликаты определяются только по URL. Передавать его стоит просто чтобы сохранять контроль над записями пользователей при смене адресов.
Выбирайте значение, которое никогда не меняется для подписки конкретного пользователя. Секретным оно быть не обязано — оно лишь сравнивается с тем, что уже есть у приложения, — но должно быть стабильным и уникальным для каждой подписки. UUID или ваш внутренний id подписки одинаково подойдут.
subid: 8f3a91c2-4b77-4c1e-9a02-5e6d1f0b7c33
Доступно на всех платформах: iOS, Android, macOS, Windows, Linux и Apple TV.
↑ К оглавлениюСообщения и уведомления
эксклюзив SMProxyПровайдер может отправлять пользователям внутренние сообщения. Они приходят внутри ответа проверки Provider ID и попадают во входящие приложения (иконка колокольчика + счётчик непрочитанного), при желании вызывая системное уведомление.
Каждое сообщение: id, title, body, опционально date, type (info/update/promo/warning), url, notify и targeting. Статус прочтения хранится локально на каждом устройстве.
Кому отправлять
Сообщения составляются в кабинете провайдера. По умолчанию сообщение уходит всем; каждый фильтр ниже сужает выборку, и они складываются.
Платформа и сборка приложения
Отметьте платформы, которые должны получить сообщение. Оставьте поле сборки пустым, чтобы охватить все версии этой платформы, или задайте условие (<, ≤, =, ≥, >), чтобы охватить только часть.
Номера сборок свои у каждой платформы — iOS 200 и Android 200 никак не связаны — поэтому условие всегда привязано к платформе. Не отмечено ничего — значит «все платформы»; как только отмечена одна, остальные не получают ничего. Так и добираются до пользователей на старой сборке iOS, не трогая Android:
< 200 · пользователи iOS ниже сборки 200< 200, Android < 300 · старые сборки на обеих, на остальных — ничегоДомен подписки
Выберите подтверждённый домен, чтобы охватить только тех пользователей, чья подписка раздаётся с него — *.example.com для домена и всех его поддоменов или отдельный хост вида sub.example.com только для него. В кабинете видно, сколько устройств сейчас на каждом хосте.
Требуется подтверждённый домен — см. Подтверждение домена (раздел 05a).
Одно устройство
Вставьте HWID, чтобы отправить сообщение ровно одному устройству — удобно, когда вы разбираете проблему с конкретным пользователем.
↑ К оглавлениюGeoIP / GeoSite
Geo-правила, которые использует туннель, живут внутри импортированного Xray-конфига и разрешаются по базам geoip.dat / geosite.dat. Приложение поставляется со встроенными базами и может загружать обновлённые из заголовков geoipurl / geositeurl (поддерживается на iOS, Android и настольных ОС); свежезагруженная база заменяет встроенную для движка.
Профили маршрутизации
Профиль маршрутизации — это полный набор правил: что идёт напрямую, что через туннель и что блокируется, плюс опциональный split-DNS. Это ответ на «у меня подписка — одна ссылка vless://, внутри неё нет маршрутизации»: профиль несёт маршрутизацию отдельно от серверов.
Профиль
{
"Name": "Bypass RU",
"GlobalProxy": true,
"DirectSites": ["geosite:category-ru", "domain:gosuslugi.ru"],
"DirectIp": ["geoip:ru", "192.168.0.0/16"],
"ProxySites": ["geosite:youtube"],
"BlockSites": ["geosite:category-ads-all"],
"RemoteDNSType": "DoH", "RemoteDNSDomain": "https://dnsforge.de/dns-query",
"DomesticDNSType": "DoU", "DomesticDNSIP": "77.88.8.8",
"DnsHosts": { "example.com": "1.2.3.4" },
"DomainStrategy": "IPIfNonMatch",
"UpdateUrl": "https://example.com/routing.json",
"UpdateInterval": 24,
"LastUpdated": 1756600000
}
NameGlobalProxyDirectSites / ProxySites / BlockSitesDirectIp / ProxyIp / BlockIpRemoteDNS* / DomesticDNS*DnsHostsDomainStrategyFakeDNSUpdateUrlUpdateIntervalLastUpdatedПравила применяются в порядке block → direct → proxy и ставятся перед правилами, пришедшими с конфигурацией сервера.
GlobalProxy и FakeDNS принимаются и как JSON-булево, и как строки "true" / "false", которые шлют Happ и INCY. Поля, которые другие клиенты добавляют для своего интерфейса — RouteOrder, UseChunkFiles — игнорируются: SMProxy всегда применяет правила в порядке block → direct → proxy.
Поля split-DNS
RemoteDNSTypeDoH, DoT, DoQ или DoU (обычный UDP).RemoteDNSDomainhttps://dnsforge.de/dns-query. Пусто для обычного UDP.RemoteDNSIPRemoteDNSDomain это bootstrap-адрес домена — та же роль, что у ;ip=… в заголовке s-resolve; без домена — обычный UDP-резолвер.DomesticDNSType / DomesticDNSDomain / DomesticDNSIPRemoteDns / DomesticDnsRemoteDNSIP / DomesticDNSIP. Читается только если новое поле отсутствует или пустое. В новых профилях не использовать.Как используются резолверы:
- •Кто за что отвечает. Remote — имена, идущие через туннель, Domestic — имена, идущие напрямую (
DirectSites). Удалённый резолвер опрашивается через туннель, локальный — через физическую сеть. - •
RemoteDNSDomain— ещё и собственный резолвер клиента для служебных запросов (обновление подписки, загрузка профиля), когда подписка не присылаетs-resolve. Профиль маршрутизации, таким образом, задаёт DNS для всего, а не только для трафика внутри туннеля. - •Bootstrap. Суффикс
;ip=…изs-resolveне работает внутриRemoteDNSDomain— там нет разбора, адрес уйдёт с мусором на конце. Bootstrap-адрес кладите вRemoteDNSIP. - •Цепочка запасных. Сначала резолверы профиля, затем DNS-серверы из самого конфига подключения (их разбиения
domains/skipFallbackсохраняются). Если все резолверы профиля недоступны, разрешение имён уходит на серверы конфига. - •Поддержка массивов клиентами: SMProxy начиная с Android 411 / iOS, macOS, tvOS 305 / Windows, Linux 193. Happ, INCY и старые сборки SMProxy читают только строку — присылайте строку, если не уверены, что пользователи обновились.
Строка или массив — расширение SMProxy. RemoteDNSDomain, RemoteDNSIP, DomesticDNSDomain и DomesticDNSIP принимают либо одну строку (классический формат, совместимый с Happ/INCY), либо массив строк:
"RemoteDNSDomain": ["https://dns1.example/dns-query", "https://dns2.example/dns-query"],
"RemoteDNSIP": ["1.2.3.4", "5.6.7.8"]Порядок = приоритет: ядро опрашивает резолверы сверху вниз, вторая запись — запасная для первой. *DNSIP[i] — bootstrap-адрес для *DNSDomain[i]; IP без парного домена работает как обычный резолвер.
Защита от отката — LastUpdated
Когда профиль с тем же Name приходит автоматически (заголовки подписки, обновление по UpdateUrl, ссылка), он заменяет сохранённый только если его LastUpdated больше. Если метки нет с одной из сторон, профиль заменяется безусловно. Увеличивайте значение при каждом изменении профиля. Ручной импорт из интерфейса приложения применяется всегда.
Как передать профиль пользователю
Ссылкой — самый естественный способ: из браузера, из сообщения или по QR-коду.
smproxy://routing/add/<base64|url>smproxy://routing/onadd/<base64|url>smproxy://autorouting/add/<url> · …/onadd/<url>smproxy://routing/offПолезную нагрузку можно передать и как ?data=<base64>. URL может вернуть JSON профиля, его base64 или другую ссылку smproxy:// — принимаются все три варианта.
Заголовком подписки — профиль приходит вместе с самой подпиской.
routingautoroutingrouting-update-urlrouting-update-intervalrouting-profileПрофиль, пришедший с подпиской, добавляется в список, но не включается — выбор остаётся за пользователем. Эти ключи работают и без Provider ID.
Заголовки принимают и deep-link-команды. Значением routing / autorouting может быть deep-link-команда — в тех же формах, что кликабельные ссылки, с любым словом схемы (smproxy://, happ://, yourapp://): внутри заголовка слово перед :// не важно.
*://routing/add/<base64|url>*://routing/onadd/<base64|url>*://autorouting/add/<url> · …/onadd/<url>*://routing/offПолезная нагрузка может быть зашифрована как crypt1/<base64> — как и любое другое значение заголовка.
Те же команды принимаются и отдельной строкой в теле подписки, прямо среди ссылок на серверы (совместимо с INCY):
vless://uuid@server1:443?security=tls#Server1
vmess://eyJhZGQiOiAic2VydmVyMi...
incy://routing/onadd/ewogICJOYW1lIjogIl...Настоящий HTTP-заголовок или явный заголовок в теле #routing: важнее строки без префикса.
Глобально и по подписке
Пользователь выбирает один активный профиль в настройках — это глобальный выбор. Подписка может его переопределить: если в ней указан профиль (в её настройках или заголовком routing-profile), при подключении к её серверам применяется он. И то, и другое можно выключить: глобально в настройках (или ссылкой routing/off), а для подписки — вариантом «Не применять».
Какой профиль победит
При обновлении подписки несколько заголовков выше могут прийти одновременно. Они разбираются в таком порядке:
routing / autorouting — профиль, присланный целиком, важнее скачанного по routing-update-url. Присылайте сам профиль, если хотите быть уверены, какая именно версия окажется у клиента.
routing-update-url — если профиль не пришёл целиком, клиент скачает его по этому адресу и импортирует. Заголовок работает сам по себе — routing рядом не нужен.
routing-profile (имя) — определяет, каким профилем подписка пользуется, и перебивает всё, что пришло в этом обновлении. Если указать Corporate и одновременно прислать профиль Default, подписка возьмёт Corporate, а Default всё равно попадёт в список.
Имя, которому ничего не соответствует, ничего не меняет. Если пришёл routing-profile: Corporate, а профиля с таким именем на устройстве нет, подписка сохранит прежние настройки маршрутизации. Клиент не подставит другой профиль и не сбросит настройку — опечатка в заголовке не может незаметно перенаправить трафик ваших пользователей.
Глобальный выбор не трогается никогда. Всё описанное выше задаёт профиль для этой подписки. Профиль, выбранный пользователем в настройках, остаётся как есть и продолжает действовать для всех остальных подписок. Чтобы сменить профиль подписки, используйте routing-profile; заголовка, меняющего глобальный выбор пользователя, нет.
Изменения применяются при следующем подключении. Профили читаются при сборке конфигурации туннеля, поэтому профиль, пришедший на активном соединении, начнёт действовать после переподключения — обновление подписки на ходу не перенаправляет живой трафик.
s-resolve → поле RemoteDNSDomain активного профиля маршрутизации → настройка пользователя → встроенный список (если пользователь его включил) → системный резолвер.s-resolve: off отключает предразрешение целиком — профиль в этом случае не подхватится.Обход блокировок
Системы DPI часто блокируют по SNI (домен назначения) из TLS ClientHello — первого пакета каждого TLS/Reality-хендшейка. Фрагментация дробит этот ClientHello на множество мелких TCP-сегментов с крошечными задержками, так что DPI не может собрать SNI обратно → не видит домен → не может резать по домену. Работает целиком на штатном ядре Xray (outbound freedom с настройками fragment) — без дополнительного сервера и инфраструктуры.
Четыре параметра ниже решают разные задачи и часто применяются вместе.
fragment-outbound в конфиг НЕ нужно: при включении приложение само вставляет его и перенаправляет через него весь прямой TLS/Reality-трафик на ЛЮБОМ конфиге, оставляя цепочки (multi-hop) нетронутыми — фрагментируется только тот хоп, который видит DPI.
08.1 · s-fragment — фрагментация TLS
Включение — заголовок s-fragment
отсутствует / offonpackets=tlshello;length=50-100;interval=10-20;maxsplit=100-200Передаётся как HTTP-заголовок ответа s-fragment: или строкой-комментарием в теле #s-fragment: packets=tlshello;length=50-100;interval=10-20.
s-fragment учитывается только пока ваш Provider ID активен. Неактивный или неизвестный провайдер не может включать фрагментацию на устройствах пользователей.
Параметры
packetsКакие пакеты фрагментировать. tlshello — только TLS ClientHello (несёт SNI), рекомендуется. 1-3 — первые 1–3 исходящих пакета.
lengthРазмер фрагмента, случайно в диапазоне. Меньше = труднее собрать, но больше накладных расходов.
intervalЗадержка между фрагментами, случайно в диапазоне. Джиттер мешает буферизации и пересборке.
maxsplitОпционально (только новые ядра). Ограничивает число фрагментов. Старые ядра игнорируют.
Значения по умолчанию подходят большинству сетей. Тюнинг под конкретный DPI: сильнее блокируют → меньше length и/или больше interval; падает скорость → больше length и меньше interval.
Имена параметров не зависят от регистра (maxsplit и maxSplit — один и тот же ключ), а ключ packets — во множественном числе: packets=, не packet=. packet= относится к s-noise, где означает полезную нагрузку.
⚙️Пользователь может включить сам
Пользователь также может включить фрагментацию и отредактировать те же параметры вручную — в приложении: Настройки → Обход блокировок → TLS-фрагментация, независимо от провайдера. При ручном включении его параметры имеют приоритет над заголовком.
08.2 · s-noise — шумовые пакеты
Мусорный трафик, отправляемый до соединения, чтобы DPI не распознал его начало. Работает в паре с фрагментацией — у них общий выход, и вместе они закрывают и начало соединения, и его содержимое.
Значения: on / 1 — параметры по умолчанию (rand, пакет 50-100, задержка 10-20); off / 0 — выключить. Полная форма — type=rand;packet=50-100;delay=10-20 или позиционно rand,50-100,10-20; type принимает rand, str или hex.
Принимаются оба написания заголовка — s-noise и s-noises.
08.3 · s-resolve — предразрешение адреса сервера
Разрешает адрес сервера через DoH до подъёма туннеля. Нужно там, где локальный DNS отдаёт подменённый ответ для домена вашего узла: без этого клиент получит неверный IP и просто не подключится.
Значения: on / 1 — резолвер по умолчанию (dnsforge.de); off / 0 — выключить; URL задаёт свой резолвер.
Если отравлен и домен самого резолвера, добавьте bootstrap-IP через ;ip=… — например https://dnsforge.de/dns-query;ip=49.12.67.122. Исходный домен остаётся в SNI, поэтому TLS/Reality проверяются как обычно. Если резолвер не ответил за полторы секунды, используется обычный поиск — параметр может только помочь, но не заблокировать подключение.
Несколько резолверов. Адреса можно перечислить через запятую, каждый со своим bootstrap-IP — они пробуются по порядку до первого ответившего. Одиночный адрес работает как раньше: это тот же формат без запятых.
s-resolve: https://a.example/dns-query;ip=1.2.3.4, https://b.example/dns-query;ip=5.6.7.8Список полезнее встроенного набора приложения: вы задаёте адреса, про которые знаете, что они работают в сетях ваших пользователей, — встроенный список об этом знать не может. К тому же включить его заголовком нельзя, он управляется только тумблером у пользователя.
08.4 · s-dns — DNS-over-HTTPS в туннеле
Шифрует обычные DNS-запросы внутри туннеля. Значения: on / 1 — встроенный резолвер по умолчанию (dnsforge.de); URL вида https://dnsforge.de/dns-query — свой резолвер; off / 0 — выключить. Разрешённый DNS идёт через туннель, а не через физическую сеть.
off. Если настраивает сам пользователь, порядок такой: фрагментация → шум → DoH.WireGuard/AmneziaWG
Серверы WireGuard и AmneziaWG работают как любые другие: стоят в одном списке рядом с VLESS/Trojan/Shadowsocks, пользователь выбирает их так же. Отдельного режима нет, дополнительной настройки нет. Работает на штатном ядре Xray (outbound wireguard) — со стороны провайдера ничего нового не требуется, кроме самого конфига.
Способ А — в JSON-подписке
Обычный конфиг Xray, где у outbound "protocol": "wireguard":
{
"remarks": "🇳🇱 Нидерланды — WG",
"outbounds": [{
"tag": "proxy",
"protocol": "wireguard",
"settings": {
"secretKey": "<приватный ключ клиента>",
"address": ["10.0.0.2/32"],
"mtu": 1420,
"peers": [{
"publicKey": "<публичный ключ сервера>",
"preSharedKey": "<необязательно>",
"endpoint": "example.com:51820",
"allowedIPs": ["0.0.0.0/0", "::/0"],
"keepAlive": 25
}]
}
}]
}Адрес сервера, который показывается в приложении, берётся из peers[0].endpoint. У WireGuard нет блоков vnext или servers — строка endpoint единственное место, где живёт хост.
Поля AmneziaWG. Тот же outbound принимает параметры обфускации — добавьте их рядом с обычными. Они нужны только для AmneziaWG; для обычного WireGuard их просто не указывают (нулевые значения игнорируются, соединение ведёт себя ровно как раньше).
{
"protocol": "wireguard",
"settings": {
"secretKey": "…",
"address": ["10.66.66.17/32"],
"mtu": 1420,
"jc": 4, "jmin": 40, "jmax": 70,
"s1": 15, "s2": 25, "s3": 0, "s4": 0,
"h1": 1111111, "h2": 2222222, "h3": 3333333, "h4": 4444444,
"peers": [
{ "publicKey": "…", "endpoint": "1.2.3.4:51820", "allowedIPs": ["0.0.0.0/0"] }
]
}
}jcjmin / jmaxs1 / s2s3 / s4h1–h4s1–s4 и h1–h4 обязаны совпадать на сервере и в конфиге клиента, иначе соединение молча не работает: туннель поднимается, а трафик не идёт. jc, jmin и jmax совпадать не обязаны — каждая сторона шлёт свой мусор.
Версия сервера — 3.1 и ниже. Приложение собрано на ветке AmneziaWG 3.1 и совместимо со всеми предыдущими, обновлять на своей стороне ничего не нужно. Присылайте только те параметры, которые сервер действительно использует: всё, что не указано, остаётся по умолчанию и игнорируется.
jc, jmin, jmax, s1, s2, h1–h4s3, s4i1–i5header_protection_key, content_padding_addition, rekey_after_time, rekey_timeout, reject_after_time, keepalive_timeout, max_handshake_attemptsrandom_trailers, disable_cookies, диапазоны a-b для h1–h4 и PersistentKeepaliveПараметр из 3.1, отправленный старому серверу, тот просто не поймёт — держите стороны в согласии: настраивайте клиент ровно тем, что работает на сервере.
Способ Б — ссылкой wireguard://
wireguard://<base64 стандартного .conf> — в base64 лежит обычный конфигурационный файл WireGuard, ровно тот текст, который выдают официальному клиенту. Необязательный якорь #Имя задаёт отображаемое название:
wireguard://W0ludGVyZmFjZV0K…#🇳🇱%20НидерландыРаскодированный payload — просто:
[Interface]
PrivateKey = <приватный ключ клиента>
Address = 10.0.0.2/32
DNS = 1.1.1.1
[Peer]
PublicKey = <публичный ключ сервера>
PresharedKey = <необязательно>
Endpoint = example.com:51820
AllowedIPs = 0.0.0.0/0, ::/0Эта форма работает везде, где и остальные share-ссылки: вставка в форму добавления, внутри зашифрованной crypt1-ссылки, отдельной строкой в теле подписки.
Вставьте .conf на служебной странице — она соберёт wireguard:// и QR прямо в браузере, без запросов наружу.
Ключи уходят в ядро как есть — приложение их не перекодирует.
Импорт на стороне клиента
Начиная с Android 379, iOS/macOS 2.0.3 (277+) и десктопа 169 экран добавления принимает конфиг WireGuard/AmneziaWG четырьмя способами — раздавать пользователям можно любым из них:
.conf — кнопка «Выбрать файл конфигурации» (Android, iOS, macOS, Windows, Linux; на Apple TV кнопки нет — там добавление «с телефона»).[Interface]…[Peer] вставляется прямо в поле ввода, на всех платформах..conf. Многие панели раздают конфиги именно так.wireguard:// / amneziawg:// / awg:// / wg:// с base64 конфига, как описано выше.Параметры маскировки AmneziaWG (Jc, Jmin, Jmax, S1, S2, H1–H4) подхватываются из [Interface] во всех четырёх способах. В более старых сборках работают только схема-ссылка и QR.
C. AmneziaWG — WireGuard с обфускацией
AmneziaWG — это тот же WireGuard плюс обфускация: мусорные пакеты и переписанные типы заголовков, из-за которых DPI не распознаёт хендшейк WireGuard.
Схемы ссылок. wireguard://, amneziawg://, awg:// и wg:// принимаются и разбираются одинаково — полезная нагрузка это base64 обычного .conf, с необязательным фрагментом #Name.
amneziawg://<base64url файла .conf>#GermanyПараметры обфускации живут в секции [Interface] этого .conf, рядом с обычными ключами:
[Interface]
PrivateKey = …
Address = 10.66.66.17/32
MTU = 1420
Jc = 4 ; сколько мусорных пакетов отправить до хендшейка
Jmin = 40 ; размер мусорного пакета, нижняя граница
Jmax = 70 ; размер мусорного пакета, верхняя граница
S1 = 15 ; размер префикса init-пакета
S2 = 25 ; размер префикса response-пакета
S3 = 0 ; префикс cookie-пакета — необязательно, если сервер не задаёт
S4 = 0 ; префикс транспортного пакета — то же
H1 = 1111111 ; переписанные типы заголовков — иначе узнаются по сигнатуре (серверы 3.1 могут задавать диапазон: H1 = 1000-2000)
H2 = 2222222
H3 = 3333333
H4 = 4444444
[Peer]
PublicKey = …
Endpoint = 194.61.120.25:57932
AllowedIPs = 0.0.0.0/0,::/0
Не указывайте их — получите обычный WireGuard: приложение и ядро ведут себя точно как раньше. То же поле за полем: присылайте только то, что работает на вашем сервере. Подходит любая версия AmneziaWG, 3.1 и старше — см. таблицу версий в разделе A.
Несколько локаций в одном файле. URL подписки может вернуть JSON-контейнер вместо ссылок:
{
"type": "amneziawg",
"version": 1,
"servers": [
{ "name": "Germany", "config": "<base64url файла .conf>" },
{ "name": "Netherlands", "config": "<base64url файла .conf>" }
]
}
type принимается как amneziawg, awg, wireguard или wg. Некорректная запись пропускается, не ломая остальной список.
Заметки для операторов
- IPv6-endpoint поддерживается, пишется стандартно:
[2606:4700:d0::a29f:c001]:2408. keepAlive(секунды) — persistent keepalive. Ставьте, если клиенты за NAT: без него трансляция истекает и туннель замолкает в одну сторону.- MTU в конфиге управляет тем, что шлёт клиент. Что шлёт сервер, задаётся MTU интерфейса
wg0на ноде — настраивайте оба, иначе путь, не несущий полноразмерные пакеты, пропустит хэндшейк и встанет. - Маршрутизация на ноде важна:
ip route get <ip клиента>должен резолвиться черезwg0. Если указывает на дефолтный шлюз — хэндшейк всё равно пройдёт (демон отвечает на него напрямую), но данные до клиента не дойдут никогда. Выглядит как блокировка, но это не она.
Форматы ссылок
Всё, что понимает клиент, — в одном месте. Регистр схемы не важен.
Ссылки на серверы
vless:// vmess:// trojan:// ss:// socks://wireguard:// · amneziawg:// · awg:// · wg://hysteria2:// · hy2://Base64 читается снисходительно — обычный и URL-safe алфавит, с выравниванием и без.
#fragment задаёт отображаемое имя (percent-encoded). Он же может нести описание сервера — см. раздел 04a.
Что показывает «Посмотреть конфиг»
Правило одно: если в ссылке base64 — показывается расшифрованное содержимое, иначе ссылка как есть. Поэтому wireguard://<base64> покажет читаемый .conf, а vless://uuid@host:443?… останется ссылкой — расшифровывать нечего. JSON выводится с отступами.
Подписки
По адресу подписки может вернуться:
{"type":"amneziawg","version":1,"servers":[
{"name":"Germany","config":"<base64 of .conf>"}]}type принимается как amneziawg, awg, wireguard или wg. Битая запись пропускается, а не рушит всю подписку.
Зашифрованные значения заголовков
Значения заголовков можно передавать в закрытом виде — чтобы ссылки и настройки не расходились в открытую. Любой заголовок подписки может нести значение в зашифрованном виде — с тем же префиксом crypt1/, что и deep-links:
routing-update-url: crypt1/<base64>
routing: crypt1/<base64>
autorouting: crypt1/<base64>
s-dns: crypt1/<base64>
s-fragment: crypt1/<base64>
s-resolve: crypt1/<base64>
s-noise: crypt1/<base64>
new-url: crypt1/<base64>
s-siteurl: crypt1/<base64>Клиент отрезает префикс, расшифровывает и дальше работает с результатом так же, как если бы он пришёл открытым текстом. Без префикса ничего не меняется — существующие подписки продолжают работать как есть. Шифрование необязательное и по-заголовочное: в одном ответе можно свободно смешивать зашифрованные и открытые значения.
Шифрование — ровно то же, что у ссылок smproxy://crypt1/…: AES-256-GCM, nonce || ciphertext || tag, base64, под тем же общим ключом. Панели, которая уже выдаёт такие ссылки, новый код не нужен: зашифруйте значение, добавьте префикс crypt1/ и положите в заголовок.
Чтобы получить зашифрованное значение вообще без кода, используйте тот же генератор, что делает ссылки — он вернёт smproxy://crypt1/<encrypted>; возьмите всё после smproxy://, это и есть crypt1/<base64>, что ждёт заголовок.
POST https://provider.smproxy.io/public/crypto-link
{ "url": "https://example.com/routing.json" }
→ { "link": "smproxy://crypt1/AbCd…" }
routing-update-url: crypt1/AbCd…
s-dns: crypt1/AbCd…Принимаются оба разделителя — crypt1/<base64> и crypt1:<base64> — но используйте слэш: так же, как в deep-links, и формат один на всё.
Deep-links
Принимаются две схемы: smproxy:// (текущая) и smartvpn:// (до переименования, оставлена рабочей для уже выданных ссылок). Это касается только кликабельных ссылок — систему открывает приложение, зарегистрированное на эту схему. Внутри заголовков routing / autorouting принимается любое слово схемы (раздел 07a).
smproxy://add?url=<encoded URL>smproxy://add/<https://…> · add/<base64 URL>smproxy://crypt1/<base64>smproxy://routing/add/<base64|url>smproxy://routing/onadd/<base64|url>smproxy://autorouting/add|onadd/<url>smproxy://routing/offПолезная нагрузка может передаваться и как ?data=<base64>. Для ссылок маршрутизации по адресу может лежать JSON профиля, его base64 или другая ссылка smproxy:// — разрешаются все три варианта.
Кабинет провайдера
Самообслуживание на provider.smproxy.io — регистрация, статистика, сообщения и генераторы ссылок.
provider.smproxy.io/provider/registerprovider.smproxy.io/provider/loginprovider.smproxy.io/provider/dashboardprovider.smproxy.io/provider/statsprovider.smproxy.io/provider/messagesprovider.smproxy.io/provider/hwid-linkprovider.smproxy.io/provider/crypto-linkРегистрация занимает минуту и даёт Provider ID, статистику и рассылку сообщений. Бесплатно.
providerid / s-provideridПриложения ваших пользователей начнут наполнять статистику, которую вы видите в кабинете.
Стоимость — сейчас всё бесплатно
🔒Поля под гейтом provider_active
Ключи с замком — это брендинг/поведение, управляемые провайдером (кнопки сайта/Telegram, UI продления, fallback-url, миграция и hide-settings). Они применяются, только когда в ответе есть providerid и у него provider_active == true.
Если провайдер не активен (нет providerid, неизвестен или provider_active == false) — эти поля принудительно сбрасываются на каждом обновлении (чтобы чужой/устаревший провайдер не мог подменить кнопки или fallback). Восстанавливаются, как только провайдер снова активен.
Без гейта (работают всегда): profile-title, s-title, profile-update-interval, subscription-userinfo, announce, support-url, profile-web-page-url, providerid, geoipurl/geositeurl.
Что требует активного Provider ID
Одно место вместо поиска значков 🔒. Активный — значит Provider ID, присланный с подпиской, принадлежит действующему аккаунту провайдера. Без этого ключи из первой таблицы просто игнорируются, сама подписка продолжает работать.
🔒Требует активного Provider ID
s-fragment s-noise s-noises s-resolve s-dns — и их аналоги из INCY/Happ fragmentation-* noises-* server-address-resolve-*new-url new-domain fallback-url fallback-domainss-siteurl s-sitename s-tgbot x-tgbot sort-order serverDescriptionbanner-text banner-button-text banner-button-url banner-bg-color banner-button-color announce-url support-emailsub-expire s-showexpire sub-expire-button-text sub-expire-button-link-site sub-expire-button-link-tg notification-subs-expirehide-settings✓Работает и без Provider ID
profile-title / s-titleprofile-update-intervalprofile-web-page-urlannounceannounce-url (кликабельность) требует активного провайдераsupport-urlsubscription-userinfosubidrouting autorouting routing-update-url routing-update-interval routing-profilegeoipurl / geositeurlГейт работает одинаково независимо от того, как пришло значение: HTTP-заголовок, строка #ключ: в теле или кабинет провайдера.