Публичный шлюз подписки
Шлюз позволяет выдавать ссылку подключения на домене магазина вместо прямой ссылки
Remnawave Panel. Одна ссылка вида https://app.example.com/s/<token> открывает
инструкции в браузере и отдаёт профиль подписки VPN-приложению. Пользователь может
импортировать её в приложение и получать обновления через тот же адрес.
Minishop получает профиль из Remnawave Panel: формат ответа, лимиты HWID-устройств и правила выдачи Response Rules по-прежнему задаются в панели. Для работы импорта и обновлений должны быть доступны и магазин, и панель.
На этой странице
Заголовок раздела «На этой странице»- Как работает ссылка
- Настройка
- Включение на существующей установке
- Проверка перед переключением ссылок
- Ошибки и диагностика
- Перевыпуск и отзыв доступа
- Откат
- Технический контракт
Как работает ссылка
Заголовок раздела «Как работает ссылка»| Обращение | Ответ |
|---|---|
Открытие /s/<token> в браузере |
Страница инструкций подключения. |
| Предпросмотр ссылки в Telegram и других поддерживаемых сервисах | Та же страница инструкций. |
Импорт или обновление /s/<token> в VPN-приложении |
Профиль подписки без JSON-обёртки API. |
/s/<token>?view=page |
Явный выбор страницы инструкций. |
/s/<token>?view=page&platform=android&app=happ |
Инструкция для выбранной ОС и приложения. |
/s/<token>?view=subscription |
Явный выбор профиля подписки. |
/s/<token>/<format> |
Профиль в формате stash, singbox, mihomo, json, v2ray-json или clash. |
Без явного выбора шлюз определяет ответ по заголовкам запроса, включая User-Agent
и Accept. Запрос профиля требует непустой User-Agent; запросы HEAD не
поддерживаются. Суффикс формата нельзя сочетать с ?view=page.
Параметр platform выбирает ключ ОС из конфигурации инструкций, а необязательный
app — идентификатор id приложения внутри этой ОС. Можно передать только
platform. Например, /install?platform=android&app=happ открывает личную инструкцию,
а /s/<token>?view=page&platform=android&app=happ — публичную. Используйте ключи и
идентификаторы из своей конфигурации. Неизвестные значения не блокируют открытие:
экран использует обычный выбор ОС и доступного приложения. Параметры относятся к
отображению инструкции и не меняют права доступа или формат профиля подписки.
Настройка
Заголовок раздела «Настройка»В админке откройте Система → Настройки → Инструкции подключения. Сначала проверьте выдачу профиля, затем переключите ссылки, которые магазин выдаёт пользователям.
| Настройка | По умолчанию | Назначение |
|---|---|---|
SUBSCRIPTION_GATEWAY_ENABLED |
True |
Переключатель «Выдавать подписку по публичной ссылке» разрешает приложениям импортировать и обновлять профиль через /s/. Отключение сохраняет страницу инструкций, но прекращает выдачу профиля. |
SUBSCRIPTION_LINK_MODE |
panel |
Переключатель «Использовать встроенную в Minishop ссылку подписки» выбирает minishop вместо panel для ссылок в боте и инструкциях подключения. Требуется включённый шлюз. |
SUBSCRIPTION_MINI_APP_URL |
Не задан | Публичный базовый адрес вашего Web App для формирования /s/-ссылок. Шлюз не берёт его из присланного клиентом Host. |
SUBSCRIPTION_GATEWAY_REWRITE_PROFILE_PAGE_URL |
False |
Заменяет заголовок profile-web-page-url ответа панели ссылкой на инструкции Minishop с ?view=page. Без этой настройки сохраняется адрес, заданный в панели. |
Пример настроек .env после проверки шлюза:
После изменения .env пересоздайте контейнеры по
инструкции развёртывания. Сохранённые настройки
админки могут переопределять значения .env; проверьте фактические переключатели.
Режим minishop не заменяет автоматически адреса, уже импортированные в приложения.
Прямые ссылки панели продолжают работать; для перехода на домен магазина пользователь
должен заново импортировать выданную /s/-ссылку.
Включение на существующей установке
Заголовок раздела «Включение на существующей установке»При обновлении установки, которая выдавала публичные инструкции до появления шлюза:
-
Примените миграцию
0088_bind_install_share_to_panel_linkдо передачи запросов новой версии backend. Добавляемое поле допускает пустое значение и совместимо с предыдущей версией backend. -
Из доверенного окружения оператора с доступом к БД и панели выполните проверку:
Проверьте счётчики
verifiedиskipped. Для сохранения проверенных привязок выполните ту же команду с--apply. Она связывает существующие активные токены с текущей ссылкой панели. Пропущенные записи разбирайте вручную: публичный запрос не привязывает старый токен. Утилита не определяет, кому ранее могла стать известна ссылка; при сомнениях перевыпустите доступ. -
Обновите backend и конфигурацию Nginx во frontend с отдельным маршрутом
/s/. При раздельном размещении frontend передаётMINISHOP_EDGE_TOKEN; прямой доступ к защищённому маршруту backend должен быть закрыт. См. раздельное размещение frontend и backend. -
Убедитесь, что выдача подписки по публичной ссылке включена. Пока оставьте
SUBSCRIPTION_LINK_MODE=panelи выполните проверки ниже. Старое значение.envили сохранённая настройка админки могут отключать шлюз, несмотря наTrueпо умолчанию. -
После успешных проверок включите режим
minishopв админке или.env.
Для новой установки перенос старых токенов не нужен.
Проверка перед переключением ссылок
Заголовок раздела «Проверка перед переключением ссылок»Используйте действующую ссылку своей тестовой подписки и настоящий публичный адрес магазина, чтобы проверить всю цепочку прокси:
- Откройте ссылку в браузере и проверьте предпросмотр в Telegram: должны открываться инструкции подключения.
- Импортируйте ссылку в используемые VPN-приложения, затем обновите профиль повторно. Проверьте нужные форматы, учёт HWID-устройств и Response Rules панели.
- Сравните ответы прямой ссылки панели и шлюза с одинаковыми заголовками клиента: содержимое профиля и разрешённые заголовки должны соответствовать ответу панели.
- На тестовой подписке перевыпустите доступ: старая публичная ссылка должна перестать работать, новая — успешно импортироваться.
- Проверьте сбой связи с панелью через внешний адрес: клиент должен получить ошибку
5xx, а не HTML-страницу прокси со статусом200.
Для ручного запроса профиля используйте GET, а не curl -I:
Замените адрес и <token> своими значениями. Ссылка даёт доступ к подписке:
не публикуйте её в отчётах, скриншотах и сообщениях поддержки.
Ошибки и диагностика
Заголовок раздела «Ошибки и диагностика»| Статус | Что проверить |
|---|---|
400 |
Для профиля нужен User-Agent; view допускает одно значение page или subscription. Нельзя запрашивать страницу вместе с суффиксом формата. |
404 |
Токен отсутствует, отозван или больше не соответствует текущей активной подписке и ссылке панели. Получите новую ссылку из аккаунта. |
429 |
Превышена общая квота запросов публичных инструкций и подписки. Повторите запрос с учётом Retry-After. |
502 |
Ошибка связи с источником или недопустимый ответ панели: перенаправление, HTML, пустой успешный профиль, профиль больше 8 МиБ либо суммарные заголовки больше 64 КиБ. Проверьте PANEL_API_URL и доступность /api/sub/<shortUuid>. |
503 |
Шлюз отключён, проверка доступа временно недоступна, исчерпан лимит одновременных обращений или недоступен настроенный Redis для общих квот. |
504 |
Истекло время ожидания ответа панели. Проверьте её доступность из backend. |
Панель также может вернуть свой статус ошибки. Для диагностики используйте логи backend и прокси, справочник переменных и настройки инструкций.
Перевыпуск и отзыв доступа
Заголовок раздела «Перевыпуск и отзыв доступа»При перевыпуске пользователем или администратором Minishop отзывает все локальные
публичные разрешения этого пользователя панели и сохраняет отзыв до обращения
к панели. Даже если панель вернёт ошибку, прежние токены остаются отозванными.
Запрос из авторизованного аккаунта выдаёт новый токен, связанный с текущим shortUuid.
Изменение shortUuid непосредственно в панели также делает старый токен недействительным
при следующем обращении.
Публичный JSON API и выдача профиля проверяют разрешение в БД и актуальную запись пользователя панели при каждом запросе. Прежний публичный кеш на 300 секунд не используется.
Возврат SUBSCRIPTION_LINK_MODE=panel меняет только вновь выдаваемые ссылки.
Оставьте шлюз включённым, пока пользователи могут хранить /s/-адреса в приложениях.
Для экстренной остановки выключите SUBSCRIPTION_GATEWAY_ENABLED: запросы профиля
будут получать 503, а пользователям потребуется заново импортировать прямую ссылку
панели. Откат backend на версию без шлюза также нарушит обновления уже импортированных
/s/-профилей.
Технический контракт
Заголовок раздела «Технический контракт»Сервис доставки получает привязку ресурса, разрешённую сервером, и запрос клиента.
Адаптер Remnawave обращается к настроенному /api/sub/<shortUuid> и передаёт
содержимое, статус и безопасные заголовки ответа без стандартной JSON-обёртки
{"ok": …}. Он не отправляет административный Bearer-токен, не следует
перенаправлениям, не пересылает пользовательские cookies, не кеширует профили
и не принимает адрес источника из публичного запроса. Если оператор настроил
PANEL_API_COOKIE для защищённого прокси панели, используется именно этот cookie.
Имена заголовков обрабатываются без учёта регистра, включая user-agent.
Крупные настройки клиента в безопасных заголовках передаются без усечения:
предел всех заголовков ответа панели — 64 КиБ с именами и разделителями.
Превышение возвращает 502, а не профиль с потерянными настройками. Штатный Nginx
имеет буфер 128 КиБ с запасом под служебные заголовки магазина; внешний прокси
оператора также должен принимать такой ответ.
Увеличьте буфер заголовков на каждом внешнем Nginx перед frontend. Буферы
внутреннего frontend не меняют ограничения внешнего прокси. Оба штатных
примера Nginx и
конфигурации для собственного ingress
задают для location ^~ /s/:
Проверьте конфигурацию nginx -t и перечитайте её перед повторным импортом.
Ошибка upstream sent too big header с внешним 502 при успешном ответе
frontend означает недостаточный буфер внешнего прокси. Проверяйте успешный профиль
с длинным x-client-settings и повторное обновление через публичный HTTPS-вход;
маленький ответ 404 не проверяет этот предел. Сохраняйте access_log off для
/s/, поскольку адрес содержит секретный токен.
HWID и учёт использования
Заголовок раздела «HWID и учёт использования»Шлюз передаёт x-hwid, x-device-os, x-ver-os, x-device-model и User-Agent
в публичный endpoint подписки того же пользователя Panel. Адрес клиента передаётся
через x-remnawave-real-ip: входящее значение этого заголовка удаляется и заменяется
адресом, вычисленным по цепочке доверенных прокси. Для собственного reverse proxy
проверьте TRUSTED_PROXIES; непроверенным заголовкам клиентского IP шлюз не доверяет.
Для поддерживаемого внутреннего HTTP endpoint Panel адаптер сам задаёт
X-Forwarded-For с тем же доверенным адресом и X-Forwarded-Proto: https,
требуемые проверкой reverse proxy панели. Входящие значения этих заголовков
удаляются; административный Bearer-токен в запрос подписки не добавляется.
Ограничение устройств должно быть включено и настроено в Remnawave, а приложение
должно отправлять поддерживаемый HWID. Шлюз не создаёт HWID за клиента и сохраняет
статусы отказа и заголовки x-hwid-* панели. Подробности — в
документации Remnawave.
HWID регистрируется при импорте или обновлении подписки: он не идентифицирует
каждое VPN-подключение. Учёт трафика и подключений выполняют Panel и её ноды.
Защита публичной ссылки
Заголовок раздела «Защита публичной ссылки»Токен содержит 128 случайных бит и не зависит от ID пользователя. HTML, профиль
и публичный JSON API используют общие квоты: 240 запросов в минуту на IP и 60
на токен. Redis обеспечивает общие счётчики для процессов и реплик; без него
квоты действуют отдельно в каждом процессе. Отказ настроенного Redis возвращает
503. Эти ограничения не заменяют защиту внешнего прокси от массовой нагрузки.
Ссылка является секретом доступа. Квоты и случайный токен защищают от подбора, но не от использования уже раскрытой ссылки. При утечке перевыпустите доступ.
Маршрут выдачи профиля не входит в JSON-контракт OpenAPI: его ответ зависит
от клиента и панели. JSON-маршрут /api/subscription-guides/public/<token>
остаётся в OpenAPI, сохраняет поле config и возвращает guide_document
с schemaVersion: 1. Документ строится из проверенного конфига Remnawave v1,
содержит упорядоченные идентификаторы платформ и типизированные цели кнопок.
Разрешение конкретной подписки выполняется отдельно; сервис доставки профиля
не читает документ инструкций.
Ответы шлюза запрещают кеширование и индексацию. В стандартной конфигурации
frontend исключает из журнала доступа /s/, публичный JSON API инструкций и
запросы с такой ссылкой в Referer. Backend маскирует токены в URL, заголовках
журнала доступа и атрибутах пути отчётов об ошибках, сохраняя статусы для диагностики.
Для двух публичных маршрутов штатный Nginx также отключает журнал ошибок,
который не умеет маскировать URL: диагностируйте их по безопасному журналу backend.
При настройке собственного внешнего прокси исключите секретные ссылки из его
журналов и отчётов. Обновление не удаляет токены из ранее записанных логов:
ограничьте доступ к ним и перевыпустите ссылки, если они могли стать известны другим.