Установка сервиса
Страница подключения и выдача конфигураций работают в одном сервисе sn-sub. Браузер получает страницу с приложениями и инструкциями, VPN-приложение — конфигурацию по той же ссылке /ID. Покупки доступны через клиентский кабинет, витрину, бот и установленный Mini App; страница подключения содержит только подключение и инструкции. Клиентский кабинет устанавливается отдельно от сервиса подписки.
Название, светлый и тёмный логотипы, favicon и цвета страницы подключения берутся из Кабинет и Mini App. Кнопка Настроить бренд в разделе подписки открывает общие настройки; приложения, инструкции и заголовок профиля в VPN-приложении задаются отдельно. Оба режима sn-sub получают только публичные поля оформления, без закрытых настроек кабинета и служебных ключей. Roboto поставляется с сервисом; выбор светлой, тёмной или автоматической темы сохраняется для текущего домена и не синхронизируется между отдельными доменами. Подробности — в дизайн-системе страницы подключения.
Язык и короткие ссылки
Ссылка клиента имеет вид https://sub.example.com/ID. Старые адреса /s/ID продолжают работать без перенаправления и повторного добавления подписки. QR-коды, бот, кабинет и Mini App используют короткий адрес.
Страница подключения доступна на русском и английском. Кнопка RU / EN вверху меняет язык и запоминает выбор на этом домене. При первом открытии учитывается язык браузера; язык конкретной ссылки можно задать через ?lang=en или ?lang=ru. Язык страницы не изменяет конфигурацию, импортируемую в VPN-приложение. Названия тарифов, локаций и собственные тексты администратора сохраняются в заданном им виде.
При обновлении раздельной установки сначала обновите sn-sub на сервере подписки до v0.1.9 или новее, затем панель: она начнёт выдавать короткие ссылки. Старые адреса работают и после обновления. Инструкция обновления вынесенной службы приведена ниже.
Выберите размещение
| Один сервер с панелью | Отдельный сервер | |
|---|---|---|
| Источник данных | Локальная PostgreSQL, SUB_MODE=db |
API панели, SUB_MODE=api |
| Установка | В мастере выберите «На этом сервере»; также входит в Compose | Команда в Настройки → Сервис подписки |
| Служебный ключ | Не требуется | Требуется |
| Домен, пример | sub.example.com → IP панели |
sub.example.com → IP отдельного сервера |
| Соединение с панелью | Через локальную базу | Исходящий HTTPS к panel.example.com |
Панели и подписке нужны разные домены. Например: панель — panel.example.com, подключение — sub.example.com, клиентский кабинет — example.com. Ниже замените примеры своими доменами.
1. Настройки в панели
Откройте Настройки → Сервис подписки. Укажите внешний адрес панели и адрес подписки целиком, например https://panel.example.com и https://sub.example.com. Адреса задаются без /ID, других путей, параметров и логина/пароля. Сохраните их. Ссылки новых и существующих клиентов будут использовать указанный домен подписки.
Кнопка Установка открывает инструкции для обоих вариантов. Не меняйте рабочий ключ только ради просмотра инструкции: ключ показывается целиком один раз, а его перевыпуск немедленно отзывает предыдущий.
2А. На одном сервере с панелью
Если в мастере install.sh выбрано «На этом сервере», sn-sub уже установлен и читает ту же базу. Сервис использует общий .env из каталога проекта, заданный в EnvironmentFile его systemd-юнита. Не заменяйте этот юнит инструкциями для отдельной машины.
Выполните на сервере панели:
systemctl status sn-sub --no-pager
curl -fsS http://127.0.0.1:8081/ready
Ожидаемый ответ: {"status":"ready"}. Если служба выключена:
systemctl enable --now sn-sub
journalctl -u sn-sub -n 50 --no-pager
Проверьте в .env проекта SUB_MODE=db, правильный DATABASE_URL, SUB_BIND=127.0.0.1:8081 и SUB_PUBLIC_URL=https://sub.example.com. После изменения .env перезапустите только sn-sub.
Для новой установки всей панели запустите sudo bash install.sh из каталога исходников проекта. Выберите «На этом сервере»: скрипт спросит два домена, установит оба сервиса и создаст конфигурацию Caddy. Для отдельной машины выберите «На отдельном сервере»: на панели останутся только её службы и HTTPS-домен, а подписку нужно установить отдельно по шагам ниже. Не запускайте install-sub.sh поверх существующей установки панели.
Если панель работает в Docker Compose: в каталоге проекта выполните docker compose up -d sub и docker compose exec sub curl -fsS http://127.0.0.1:8081/ready. Сервис собирается из исходников проекта, слушает 0.0.0.0:8081 внутри контейнера; Caddy обращается к sub:8081. Внешняя база или служебный ключ не нужны. Не подставляйте 127.0.0.1:8081 как upstream в контейнер Caddy — это адрес самого контейнера Caddy.
2Б. На отдельном сервере
При новой установке панели выберите «На отдельном сервере». Укажите будущий домен подписки: его DNS направляется на вторую машину и не проверяется установщиком панели.
Нужен чистый Debian/Ubuntu с systemd и архитектурой amd64 или arm64. Работающий сервер должен иметь исходящий доступ к панели по HTTPS. PostgreSQL и открытый доступ к базе панели не нужны.
- В панели сохраните домены. Выпустите служебный ключ, сохраните его, откройте вариант На отдельном сервере → Установка.
- Подключитесь к новому серверу по SSH от root. Скопируйте установочную команду целиком из панели и выполните её там.
- Установщик проверит ключ, ответ API, архитектуру и запуск скачанного бинарника. Он создаст
/etc/sn-sub/envс правами 600 и systemd-службу. - Дождитесь сообщения, что сервис получает данные панели. Это проверка локальной службы; публичный HTTPS настраивается следующим шагом.
Если бинарник нужной архитектуры ещё не опубликован, установка остановится. Нужно собрать sn-sub для Linux этой архитектуры и разместить sn-sub-linux-amd64 или sn-sub-linux-arm64 в каталоге сайта панели. Готовые релизы панели включают бинарники amd64 и arm64. Также можно задать SUB_BINARY_URL с адресом своей сборки. Скрипт не принимает HTML вместо бинарника.
Служебный ключ находится только в /etc/sn-sub/env, а не в публично читаемом юните. Для смены ключа обновите SUB_SERVICE_TOKEN в этом файле и выполните systemctl restart sn-sub. Все отдельные экземпляры подписки используют один активный ключ проекта: после перевыпуска обновите каждый экземпляр.
Docker на отдельном сервере: готовый Compose появляется, только когда владелец панели указал доступный SUB_IMAGE. Образ должен содержать команду sn-sub; его можно собрать из Dockerfile проекта и опубликовать в своём registry. Compose задаёт SUB_MODE=api, SUB_BIND=0.0.0.0:8081 и публикует порт только на 127.0.0.1 хоста. При обычной установке через скрипт Docker не требуется.
3. DNS и HTTPS — для обоих вариантов
Создайте DNS A для домена подписки на IP выбранного сервера. AAAA добавляйте только при работающем IPv6 на том же сервере; неверная AAAA часто мешает выпуску сертификата. Откройте входящие TCP 80 и 443 в firewall ОС и у хостера. Порт 8081 оставьте закрытым снаружи.
Если Caddy уже работает рядом с панелью, используйте его. Если на новом сервере веб-сервера нет, установите Caddy по официальной инструкции для Debian/Ubuntu. Если 80/443 уже занимает Nginx, настройте reverse proxy в нём и действующий TLS-сертификат либо осознанно перенесите сайты в Caddy; два веб-сервера не смогут слушать одинаковые порты.
Добавьте блок в существующий /etc/caddy/Caddyfile, сохранив другие сайты:
https://sub.example.com {
encode zstd gzip
reverse_proxy 127.0.0.1:8081
header -Server
}
Этот блок предназначен для Caddy на хосте. Для Caddy внутри общей сети Compose используйте reverse_proxy sub:8081, как в deploy/Caddyfile проекта. Если блок домена уже существует, измените его вместо добавления дубликата.
Проверьте и примените:
caddy validate --config /etc/caddy/Caddyfile
systemctl reload caddy
curl -fsS https://sub.example.com/ready
Caddy автоматически получает и продлевает сертификат при доступных DNS и портах. Подробнее: Automatic HTTPS. Для отдельного сервера запрос к панели проходит по проверяемому HTTPS; не отключайте проверку сертификата.
4. Проверка клиентом
Откройте в панели действующего тестового клиента, у которого есть сквад с хостами, и скопируйте его реальную ссылку. Откройте её в браузере: должны загрузиться статус, приложения и кнопка подключения. Проверьте QR-код. Импортируйте ту же ссылку в VPN-приложение и обновите подписку: должны появиться доступные этому клиенту локации. Затем проверьте VPN-подключение.
/health означает только, что процесс отвечает. /ready проверяет доступ к базе или API. Ни один из этих адресов сам по себе не проверяет доступ клиента к VPN-ноде. Запрос /UNKNOWN_ID должен вернуть 404; это не проверка действующей подписки.
5. Обновление
На каждом сервере используется одинаковый каталог и команды. Сначала обновите панель, затем выполните обновление на отдельных серверах кабинета и подписки: они получают сборки со своей панели. Команда управляет только компонентами на сервере, где запущена.
cd /opt/stealthnet-software
| Команда | Действие |
|---|---|
make update |
Обновить установленные компоненты |
make start |
Запустить службы |
make stop |
Остановить службы |
make restart |
Перезапустить службы |
make status |
Показать состояние |
Caddy, PostgreSQL и настройки автозапуска не меняются. На сервере панели команды управляют панелью, её локальной подпиской, настроенным ботом и установленным кабинетом. На отдельном сервере — кабинетом, подпиской или обоими установленными сервисами. Бот без токена не запускается.
Новые установщики создают команды автоматически. Если отдельный сервис установлен до v0.2.6 и каталога с Makefile ещё нет, один раз добавьте команды от root (ключи и настройки сохранятся):
apt-get update && apt-get install -y curl ca-certificates python3 make
curl --proto '=https' --tlsv1.2 -fsSL https://raw.githubusercontent.com/STEALTHNET-APP/STEALTHNET-SOFTWARE/v0.2.6/web/service-manager.py -o /root/stealthnet-service-manager.py
python3 /root/stealthnet-service-manager.py install-entrypoints
После этого используйте cd /opt/stealthnet-software && make update. Старые команды обновления продолжают работать. Для существующей установки через Docker используйте её Compose-файл.
Обновлятор сохраняет /etc/sn-sub/env, заменяет бинарник атомарно и проверяет готовность. Если новая служба не готова, возвращает предыдущий бинарник. Ключ и адреса не меняются. Повторный запуск свежего установщика вместо обновлятора остановится, чтобы не затереть рабочую службу.
Если что-то не работает
| Симптом | Что проверить |
|---|---|
| Панель отвергла ключ | Правильный PANEL_URL, актуальный SUB_SERVICE_TOKEN, доступ к /api/sub/settings; новый ключ отзывает старый |
| Вместо бинарника HTML | В каталоге сайта панели отсутствует сборка нужной архитектуры; обновите панель или опубликуйте сборку |
| Служба не стартует | journalctl -u sn-sub -n 50 --no-pager, параметры /etc/sn-sub/env, порт 8081, запуск бинарника нужной архитектуры |
/ready возвращает 503 |
Источник данных недоступен: в режиме API проверьте сеть/ключ панели; в режиме DB — PostgreSQL и DATABASE_URL |
| HTTPS не открывается | A/AAAA, TCP 80/443, сертификат, journalctl -u caddy -n 50, отсутствие конфликта веб-серверов |
| Страница открылась, локаций нет | Активность клиента, тариф, внутренний сквад, включённые хосты и инбаунды нод |
| Ссылки ведут на старый домен | Адрес подписки в Настройки → Сервис подписки; обновление кэша настроек занимает до 30 секунд |
Отдельное размещение не делает подписку независимой от панели: при недоступности API новые запросы конфигураций не смогут получить данные. Уже установленный VPN-туннель обслуживает нода и имеет отдельный жизненный цикл.