Метаданные подписки¶
Ответ эндпоинта подписки — это тело (список серверов) плюс метаданные (брендинг, срок действия, обновления). Метаданные можно передать двумя способами, и клиент читает оба.
AHTTP-заголовок ответа
Profile-Title: My VPN
BСтрока-комментарий в теле
#profile-title: My VPN
★
Приоритет — у HTTP-заголовка. Строка #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 для не-ASCII (например, кириллицы)
Текстовые поля можно закодировать, добавив префикс base64: — работает и в заголовке, и в теле. Применимо к profile-title, s-title, announce, sub-expire-button-text.
#profile-title: base64:0JzQvtC5IFZQTg== → «Мой VPN»
Ключи¶
Каждый ключ работает и как заголовок Ключ: значение, и как строка тела #ключ: значение. Все — бесплатно.
Брендинг и ссылки¶
| Ключ (заголовок / #тело) | Назначение |
|---|---|
profile-title / s-title🔒 |
Заголовок подписки (текст или base64:) |
s-sitename🔒 |
Название провайдера/сайта |
s-siteurl🔒 |
URL сайта провайдера |
s-tgbot / x-tgbot🔒 |
Ссылка на Telegram-бот/канал |
support-url🔒 |
Ссылка на поддержку |
announce🔒 |
Текст баннера-объявления (текст или base64:), до 5 строк — длиннее обрезается многоточием |
announce-url🔒 |
Делает объявление кликабельным — открывает этот URL |
support-email🔒 |
Email поддержки — добавляет на карточку подписки кнопку «Написать в поддержку» |
profile-web-page-url🔒 |
Веб-страница провайдера |
Статус подписки и продление¶
| Ключ (заголовок / #тело) | Назначение |
|---|---|
subscription-userinfo🔒 |
upload=…; download=…; total=…; expire=… (квота + epoch окончания) |
sub-expire / s-showexpire🔒 |
Показывать состояние срока действия |
sub-expire-button-text🔒 |
Подпись кнопки продления (текст или base64:) |
sub-expire-button-link-site🔒 |
Кнопка продления → сайт |
sub-expire-button-link-tg🔒 |
Кнопка продления → Telegram |
notification-subs-expire🔒 |
1 — слать уведомления «подписка истекает через N дней», начиная за 3 дня до окончания. Независим от sub-expire / s-showexpire. Отсутствует = без уведомлений. Также как #notification-subs-expire: 1 в теле. |
Обновление и данные¶
| Ключ (заголовок / #тело) | Назначение |
|---|---|
profile-update-interval🔒 |
Интервал авто-обновления подписки (часы) |
fallback-url🔒 |
Резервный URL подписки |
geoipurl / geositeurl🔒 |
Источники баз GeoIP / GeoSite (раздел 07) |
sort-order🔒 |
Порядок серверов в списке: ping (сначала быстрые, по замеренной задержке — без замера уходят в конец), name (по алфавиту) или none (как пришли, по умолчанию). Неизвестные значения считаются как none. |
Миграция и доступ¶
| Ключ (заголовок / #тело) | Назначение |
|---|---|
new-url🔒 |
Полностью заменить URL подписки (миграция) — см. ниже |
new-domain🔒 |
Заменить только хост URL: host или host:port (безопасно для персональных ссылок). Можно задать из кабинета провайдера, не трогая панель — см. раздел 05b |
fallback-domains🔒 |
Запасные хосты через запятую. Если хост подписки перестал отвечать, приложение пробует их по порядку, сохраняя путь и токен каждого пользователя. В отличие от new-domain ничего не меняется навсегда — это выход, когда основной адрес заблокирован, а не переезд. Задаётся из кабинета провайдера или отправляется вами (раздел 05b) |
hide-settings🔒 |
Скрывает от пользователя URL подписки и её конфиг — подробности в разделе 04b. 1 скрывает, 0 показывает; отсутствие заголовка ничего не меняет. |
Идентификация¶
| Ключ (заголовок / #тело) | Назначение |
|---|---|
providerid / s-providerid🔒 |
Provider ID (раздел 05). s- вариант предпочтителен; также читается из URL ?providerid= |
subid🔒 |
Стабильный идентификатор подписки — позволяет менять URL подписки без появления дубликатов у пользователей (раздел 05a) |
Обход блокировок¶
| Ключ (заголовок / #тело) | Назначение |
|---|---|
s-noise🔒 |
Шумовые пакеты перед хендшейком — мусорный трафик, отправляемый до соединения, чтобы DPI не распознал его начало. Работает вместе с s-fragment (общий выход). 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. → подробно в разделе 08 |
s-resolve🔒 |
Резолв адреса сервера через DoH до подъёма туннеля — для сетей, где локальный DNS подменяет ответ для домена вашей ноды. on / 1, off / 0 или URL резолвера с необязательным bootstrap-IP. → подробно в разделе 08 |
s-fragment🔒 |
Фрагментация TLS ClientHello против DPI по SNI (полный справочник — раздел 08). |
s-dns🔒 |
DNS-over-HTTPS внутри туннеля: on / 1 — встроенный резолвер по умолчанию (dnsforge.de); URL — этот резолвер; off / 0 — выключить. → подробно в разделе 08 |
🔒 Ключи с замком работают только при активном провайдере — полный список.
Баннер провайдера — banner-*¶
Баннер на карточке подписки, показывается только при активном provider id (совместимо с INCY). Цвета — только #RRGGBB; всё остальное игнорируется, и берётся цвет темы приложения. Цвет надписи на кнопке подбирается автоматически по яркости кнопки, поэтому остаётся читаемым и на светлом, и на тёмном фоне.
| Заголовок | Значение и назначение |
|---|---|
banner-text🔒 |
текст или base64: — текст баннера, до 5 строк |
banner-button-text🔒 |
текст или base64:, до 25 символов — надпись на кнопке |
banner-button-url🔒 |
URL или deep-link — куда ведёт кнопка |
banner-bg-color🔒 |
#RRGGBB — фон баннера |
banner-button-color🔒 |
#RRGGBB — фон кнопки |
Параметры обхода — сводка¶
Сводка по четырём заголовкам обхода; подробный разбор каждого — в разделе 08.
| Заголовок | Значения |
|---|---|
s-fragment |
on | off | packets=<tlshello\|1-3\|all>;length=<min-max>;interval=<min-max>[;maxsplit=<n>] · по умолчанию, если прислано только on: packets=tlshello;length=50-100;interval=10-20 |
s-noise (s-noises) |
on | off | type=<rand\|str\|hex>;packet=<value>;delay=<min-max> · по умолчанию, если прислано только on: type=rand;packet=50-100;delay=10-20 |
s-resolve |
on | off | <doh-url>[;ip=<bootstrap>][, …] · по умолчанию, если прислано только on: встроенный резолвер |
s-dns |
on | off | <doh-url> · по умолчанию, если прислано только on: встроенный резолвер (dnsforge.de) |
Совместимость с именами заголовков INCY / Happ¶
Если вы уже настраиваете другой клиент, приложение понимает и его отдельные ключи и сворачивает их в эквивалентную настройку. Наш заголовок s-* всегда важнее — ключи ниже читаются только когда соответствующего s-* нет. *-enable: 0 — явное выключение.
| Их ключи | Соответствует |
|---|---|
fragmentation-enable · fragmentation-packets · fragmentation-length · fragmentation-interval · fragmentation-maxsplit |
s-fragment |
noises-enable · noises-type / noises-packet-type · noises-packet · noises-delay · noises-rand |
s-noise |
server-address-resolve-enable · server-address-resolve-dns-domain · server-address-resolve-dns-ip |
s-resolve |
noises-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-name |
profile-title — запасное имя INCY |
content-disposition: attachment; filename="x.txt" |
profile-title — имя файла без .txt / .yaml / .yml; самый низкий приоритет |
homepage |
profile-web-page-url — INCY |
hide-url |
hide-settings — 1/true скрывает, 0/false открывает |
sub-info-text |
banner-text — Happ «расширенные объявления»; 0 = баннера нет |
sub-info-button-text / sub-info-button-link |
banner-button-text / banner-button-url |
sub-info-color (red · blue · green) |
banner-bg-color — переводится в hex-цвет |
sub-expire-button-link |
sub-expire-button-link-tg для t.me / tg://, иначе sub-expire-button-link-site — одиночная форма Happ |
routing-enable: 0 |
routing: routing/off — Happ «выключить маршрутизацию» |
subscription-userinfo: 0 |
заголовка нет — INCY «скрыть блок трафика» |
expire=<миллисекунды> в subscription-userinfo |
секунды — значения больше 32 000 000 000 считаются миллисекундами |
При наличии обоих заголовков побеждает заголовок SMProxy.