Перейти к содержанию

Метаданные подписки

Ответ эндпоинта подписки — это тело (список серверов) плюс метаданные (брендинг, срок действия, обновления). Метаданные можно передать двумя способами, и клиент читает оба.

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-settings1/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.