Документация · для владельцев VPN-сервисов

Подключите свой сервис
к клиенту MosaicVPN

MosaicVPN — клиент с открытым исходным кодом на движке sing-box. Если вы держите собственный VPN-сервис, вы можете отдавать своим пользователям этот клиент вместо того, чтобы писать свой: смарт-группы, автовыбор узла, брендирование и биллинг настраиваются одним JSON-манифестом на вашей стороне. Кода писать не нужно.

Содержание

  1. Быстрый старт за 5 минут
  2. Манифест подписки
  3. Смарт-группы: стратегии выбора узла
  4. Профиль провайдера: брендирование и биллинг
  5. Тарифные уровни
  6. Полный справочник полей
  7. Частые вопросы
Раздел I

Быстрый старт за 5 минут

Клиент понимает обычные форматы подписок «из коробки» — sing-box JSON, Clash YAML, v2ray base64 и SIP008. Если у вас уже есть подписка в любом из них, клиент заработает без изменений на вашей стороне.

Всё, что описано ниже, — это дополнительный слой. Он включается, когда ваша подписка отдаёт манифест, и даёт то, чего нет в обычных подписках: группы с автовыбором, ваш бренд и ваш биллинг внутри клиента.

Шаг 1. Отдайте манифест по ссылке подписки

На тот же URL, что пользователь вставляет в клиент, отвечайте JSON-манифестом с заголовком Content-Type: application/json. Минимальный рабочий вариант:

{
  "provider_name": "Ваш Сервис",
  "user_tier": "pro",
  "groups": [
    {
      "id": "auto",
      "title": "Автовыбор",
      "type": "urltest",
      "badge": "Рекомендуется",
      "nodes": [
        { "id": "de-01" },
        { "id": "nl-01" },
        { "id": "fi-01" }
      ]
    }
  ]
}

Шаг 2. Убедитесь, что ID узлов совпадают

Поле nodes[].id должно совпадать с идентификаторами серверов, которые вы отдаёте в конфигурации подписки. Если узел с таким ID не найден, он молча выпадет из группы — это самая частая ошибка при интеграции.

Шаг 3. Проверьте

Добавьте подписку в клиент. На вкладке «Группы» появится ваша группа «Автовыбор» с бейджем. Нажатие на неё замерит задержку до каждого узла и подключит к самому быстрому.

Обратная совместимость гарантирована

Манифест — необязательное расширение. Клиенты старых версий и другие приложения (Hiddify, NekoBox) продолжат читать вашу подписку как обычно, игнорируя неизвестные им поля.

Раздел II

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

Манифест — корневой объект, которым вы управляете поведением клиента у своих пользователей. Он состоит из четырёх независимых частей, каждая необязательна.

ПолеТипНазначение
provider_namestringНазвание сервиса в интерфейсе клиента
user_tierstringУровень пользователя: free, pro, vip
telemetry_urlstringКуда клиент шлёт статистику узлов (необязательно)
groupsarrayСмарт-группы — см. раздел III
routing_rulesarrayПравила маршрутизации по домену/IP/приложению
profileobjectБрендирование и биллинг — см. раздел IV

Как клиент получает манифест

Клиент запрашивает манифест по URL подписки и кэширует его локально. Если ваш сервер недоступен, пользователь продолжит работать на последней сохранённой версии — подключение не сломается из-за недоступности вашего API.

Раздел III

Смарт-группы

Группа — это набор узлов плюс правило, по которому клиент выбирает из них один. Вместо длинного списка серверов пользователь видит несколько понятных вариантов: «Автовыбор», «Германия», «Для стриминга».

Четыре стратегии выбора

urltest

По наименьшей задержке

Клиент замеряет пинг до каждого узла и берёт самый быстрый. Универсальный вариант по умолчанию.

weighted_round_robin

Распределение нагрузки

Учитывает вес узла: чем больше вес, тем чаще узел выбирается. Разгружает популярные серверы.

fallback

По порядку

Берётся первый живой узел из списка. Порядок задаёте вы полем priority.

direct_node

Фиксированный узел

Без автовыбора — всегда конкретный сервер. Для выделенных или премиальных узлов.

Пример: три группы под разные задачи

{
  "provider_name": "Ваш Сервис",
  "user_tier": "pro",
  "groups": [
    {
      "id": "auto",
      "title": "Автовыбор",
      "type": "urltest",
      "badge": "Рекомендуется",
      "category": "smart",
      "icon": "lightning",
      "description": "Самый быстрый узел прямо сейчас",
      "ping_interval": 30,
      "max_retries": 3,
      "failover_delay": 2,
      "nodes": [
        { "id": "de-01" },
        { "id": "nl-01" },
        { "id": "fi-01" }
      ]
    },
    {
      "id": "balanced",
      "title": "Распределённая нагрузка",
      "type": "weighted_round_robin",
      "description": "Мощные узлы принимают больше подключений",
      "nodes": [
        { "id": "de-01", "weight": 50 },
        { "id": "de-02", "weight": 30 },
        { "id": "nl-01", "weight": 20 }
      ]
    },
    {
      "id": "vip-de",
      "title": "Германия VIP",
      "type": "fallback",
      "user_tier": "vip",
      "badge": "VIP",
      "nodes": [
        { "id": "de-vip-01", "priority": 1 },
        { "id": "de-vip-02", "priority": 2 }
      ]
    }
  ]
}

Поля группы

ПолеТипПо умолчаниюОписание
idstringОбязательное. Уникальный идентификатор группы
titlestringОбязательное. Название для пользователя
typestringurltestСтратегия выбора узла
nodesarrayОбязательное. Узлы группы
user_tierstringМинимальный уровень для доступа к группе
badgestringКороткая метка на карточке
categorystringsmart, compatibility, raw
iconstringНапример shield, lightning, flag_de
descriptionstringПояснение под названием
ping_intervalint30Секунды между проверками живости
max_retriesint3Неудач подряд до пометки «мёртв»
failover_delayint2Секунды до переключения на следующий узел

Умные группы пула (Стратифицированный пул)

Начиная с версии 1.1, клиент поддерживает динамический многоуровневый выбор из публичного пула нод (Stratified Fair Allocation). Каждая группа ранжирует ноды по комбинированному скору (задержка + джиттер + потеря пакетов + аптайм) и применяет адаптивный failover:

Раздел IV

Профиль провайдера

Профиль превращает клиент в витрину вашего сервиса: ваш логотип, ваш акцентный цвет, ваш тариф и ваша кнопка оплаты. Пользователю не нужно уходить на сайт, чтобы пополнить баланс.

Брендирование

{
  "profile": {
    "branding": {
      "logo_url": "https://example.com/logo.svg",
      "accent_color": "#B85C38",
      "support_url": "https://t.me/mosaicvpnbot",
      "provider_description": "Защищённое сетевое соединение"
    }
  }
}

Биллинг через Telegram-бота

Клиент умеет показывать баланс, тариф и кнопку пополнения, связываясь с вашим ботом. Ключи и токены остаются на вашей стороне — клиент только открывает ссылки и читает статус по вашим эндпоинтам.

{
  "profile": {
    "billing": {
      "type": "telegram_bot",
      "bot_username": "mosaicvpnbot",
      "pricing_model": "daily",
      "price_per_day": { "RUB": 1.0, "USDT": 0.01 },
      "trial_days": 3,
      "payment_methods": ["card", "crypto"],
      "endpoints": {
        "profile": "https://api.example.com/v1/profile",
        "topup":   "https://api.example.com/v1/topup",
        "status":  "https://api.example.com/v1/status"
      }
    }
  }
}
Секреты не передаются в манифесте

В манифест попадают только публичные URL. API-ключи, токены бота и подписи вебхуков остаются у вас на сервере — клиент их не видит и не хранит.

Единый кабинет и привязка устройств (Web & App)

Личный кабинет доступен как через встроенный в клиент интерфейс, так и на сайте (/cabinet.html). Архитектура сессий построена на криптографическом обмене кодами (OAuth-style enrollment flow):

Свои блоки в интерфейсе

Секции services и widgets позволяют добавить в клиент собственные элементы: выбор маршрута, показатель трафика, кнопку действия или ссылку на ваш ресурс.

{
  "profile": {
    "services": [
      {
        "id": "streaming",
        "type": "proxy_picker",
        "title": "Маршрут для видеосервисов",
        "description": "Отдельная группа маршрутов для медиасценариев",
        "icon": "play",
        "config": { "group_id": "streaming" }
      }
    ],
    "widgets": [
      {
        "id": "traffic",
        "type": "progress_bar",
        "title": "Трафик за месяц",
        "data_source": "billing.profile",
        "fields": ["used_gb", "limit_gb"]
      }
    ]
  }
}
Тип сервисаЧто показывает
proxy_pickerВыбор узла из указанной группы
value_displayЗначение из вашего API (баланс, срок)
actionКнопка, вызывающая ваш эндпоинт
web_viewВстроенная страница
linkВнешняя ссылка
Раздел V

Тарифные уровни

Уровень пользователя задаётся в корне манифеста полем user_tier, а требование группы — полем user_tier внутри группы. Группа с более высоким требованием пользователю недоступна.

УровеньПорядокТипичное применение
free1Общий пул, ограниченная скорость
pro2Основной платный тариф
vip3Выделенные узлы, приоритет

Проверка выполняется на стороне демона: попытка подключиться к группе выше своего уровня возвращает 403. Группы, недоступные по уровню, показываются в интерфейсе с пометкой — это работает как апселл, а не как скрытая ошибка.

Уровень — не замена авторизации

Тир управляет отображением и доступом к группам внутри клиента. Реальное ограничение доступа к узлам обеспечивается вашим сервером: не отдавайте в подписке те узлы, к которым пользователь не должен подключаться.

Раздел VI

Полный справочник

Поддерживаемые протоколы

ПротоколТранспорт
VLESSTLS · Reality · ws · grpc · xhttp
VMessTCP · ws · grpc
Hysteria2QUIC
ShadowsocksTCP · UDP
TrojanTLS
NaiveHTTP/2
AmneziaWGWireGuard

Форматы подписок

Формат определяется автоматически, указывать его не нужно: sing-box JSON, Clash YAML, v2ray base64, SIP008. Дубликаты узлов отсеиваются при импорте.

Локальное API демона

Демон mosaicd поднимает HTTP-API на петлевом интерфейсе. Оно полезно, если вы делаете свою обвязку поверх клиента.

Порт назначается динамически. Демон слушает 127.0.0.1:0, то есть ОС выдаёт свободный порт при старте. Адрес, PID и токен доступа записываются в lockfile, откуда их читает клиент:

{
  "host": "127.0.0.1",
  "port": 51734,
  "token": "<токен доступа>",
  "pid": 12480,
  "version": "0.2.0",
  "started": "2026-08-08T21:30:00Z"
}

Расположение lockfile: %LOCALAPPDATA%\Mosaic на Windows, $XDG_DATA_HOME/mosaic или ~/.local/share/mosaic на Linux, ~/Library/Application Support/Mosaic на macOS. Каталог можно переопределить переменной MOSAIC_DATA_DIR. Порт из предыдущего запуска не переиспользуется — читайте lockfile каждый раз, а не кэшируйте значение.

Метод и путьНазначение
GET /v1/manifestТекущий манифест провайдера
GET /v1/groups/{id}/selectВыбрать узел по стратегии группы
GET /v1/groups/{id}/healthСостояние узлов группы
GET /v1/serversСписок серверов
POST /v1/subscriptionsДобавить подписку
POST /v1/connectПодключиться к узлу
GET /v1/statusСтатус подключения
API привязано к localhost и защищено токеном

Демон слушает только петлевой интерфейс и не принимает внешние подключения. Запросы требуют токен из lockfile — это осознанное ограничение безопасности.

REST API & MCP (Model Context Protocol) для скриптов и агентов

Для автоматизации из bash/python-скриптов и AI-агентов (Cursor, Claude Code, Windsurf) клиент предоставляет прямой REST API мост и полноценный MCP-сервер. Эндпоинты доступны по пути /mcp/v1/* и поддерживают как стандартный заголовок Authorization: Bearer <token>, так и заголовок X-MCP-Token или параметр ?token=. Для локальных GET-запросов на петлевом интерфейсе (127.0.0.1) действует безопасный read-only доступ без передачи токена.

Метод и путьПараметрыОписание
GET /mcp/v1/statusСтатус туннеля, активная нода/группа, трафик и аптайм
GET /mcp/v1/serversСписок всех доступных серверов подписок
GET /mcp/v1/groupsСписок Smart-групп (min-latency, stable, max-speed, страны)
POST /mcp/v1/connectserver_id, group_id, country_codeМгновенное подключение к серверу или смарт-группе
POST /mcp/v1/disconnectОстановка активного VPN туннеля
GET /mcp/v1/egressesСписок локальных прокси-слушателей (SOCKS5/HTTP)
POST /mcp/v1/egressesname, protocol, listenСоздание нового локального egress-порта с горячей перезагрузкой
DELETE /mcp/v1/egresses/{id}Удаление egress-слушателя с синхронизацией sing-box
POST /mcp/v1/egresses/{id}/toggleactive (optional)Включение / отключение egress-прокси без разрыва VPN

Пример: Управление egresses и туннелем из Python

import requests

BASE = "http://127.0.0.1:51734/mcp/v1"
HEADERS = {"X-MCP-Token": "ваш_токен_из_lockfile"}

# 1. Подключиться к маршруту с минимальным пингом
requests.post(f"{BASE}/connect", json={"group_id": "min-latency"}, headers=HEADERS)

# 2. Создать выделенный локальный SOCKS5 порт для парсера или Telegram-бота
res = requests.post(f"{BASE}/egresses", json={
    "name": "Scraper Egress",
    "protocol": "socks",
    "listen": "127.0.0.1:1082"
}, headers=HEADERS).json()

egress_id = res["data"]["egress"]["id"]
print(f"Egress поднят на 127.0.0.1:1082 (ID: {egress_id})")

# 3. Временно отключить egress при необходимости
requests.post(f"{BASE}/egresses/{egress_id}/toggle", json={"active": False}, headers=HEADERS)

Интеграция с Claude Code, Cursor и Windsurf (MCP JSON-RPC 2.0)

Для подключения к AI-ассистентам добавьте MCP-сервер Mosaic в конфигурационный файл mcpServers:

{
  "mcpServers": {
    "mosaic-vpn": {
      "url": "http://127.0.0.1:51734/mcp",
      "headers": {
        "Authorization": "Bearer ваш_токен_из_lockfile"
      }
    }
  }
}

Агентам становятся доступны нативные функции: mosaic_status, mosaic_connect (с поддержкой group_id), mosaic_disconnect, mosaic_list_egresses, mosaic_add_egress, mosaic_toggle_egress, mosaic_test_url.

Раздел VII

Частые вопросы

Нужно ли форкать клиент?

Нет. Брендирование, группы и биллинг задаются манифестом с вашего сервера. Форк нужен только если вы хотите менять саму логику приложения.

Что будет, если мой сервер недоступен?

Клиент использует последний сохранённый манифест. Пользователь продолжит подключаться к узлам, которые уже знает.

Можно ли использовать клиент в коммерческом сервисе?

Да. Клиент построен на sing-box под лицензией GPL-3.0, поэтому коммерческое использование разрешено, но при распространении собственной сборки вы обязаны раскрыть исходный код своей производной работы и сохранить лицензию. Использование оригинальных сборок с вашим манифестом никаких дополнительных обязательств не создаёт.

Где взять исходный код?

github.com/DangerousANEN/mosaicvpn — исходники клиента, демона и готовые сборки под Windows, Linux и Android.

Как протестировать манифест до выката?

Поднимите его на любом статическом хостинге, добавьте ссылку как подписку в клиент и проверьте вкладку «Группы». Ошибки разбора видны в разделе «Логи» внутри приложения.