Установка использует готовые GitHub Releases. Rust, Git, Node.js и Docker на сервере клиента не нужны. Установщик настраивает PostgreSQL, панель, сервис подписок при совместном размещении, фоновые задачи, Telegram-бот (если указан токен) и Caddy с автоматическим HTTPS.
Подготовьте сервер
Debian 12 / 13 или Ubuntu 22.04 / 24.04 / 26.04 LTS; systemd; архитектура amd64 или arm64.
Рекомендуются 2 vCPU, 2 ГБ RAM и 10 ГБ свободного диска. Установщик остановится при памяти меньше 1 ГБ или свободном месте меньше 3 ГБ.
Доступ root по SSH. Существующая установка и её база не перезаписываются.
Два разных домена: для панели и подписок. A/AAAA направляются на сервер, где размещается соответствующий сервис. Для отдельной подписки её DNS можно настроить после установки панели.
В firewall провайдера откройте TCP 80 и 443. SSH оставьте доступным. Порты PostgreSQL 5432 и служб 8080/8081 остаются локальными. Активный UFW получит только правила для 80/443; остальные правила сохраняются.
Клиентский кабинет и Mini App устанавливаются из админки после запуска панели. До установки кабинета Mini App показывает страницу с объяснением, а не работает через панель напрямую. Ноды устанавливаются отдельно из раздела «Ноды».
Установка через GitHub
На чистом Debian/Ubuntu войдите по SSH как root и выполните:
Откроется мастер: укажите домены панели и подписки, название сервиса, валюту и данные владельца. Установщик сам скачает готовый релиз для архитектуры сервера, проверит SHA256 и установит PostgreSQL, системные службы и HTTPS. Компилировать Rust не требуется.
Репозиторий загрузится в /root/stealthnet-installer, а рабочая панель установится в /opt/stealthnet-software. Обновлять установленную панель затем нужно командой make update из её рабочего каталога.
Размещение подписки и поля мастера
В начале выберите 1 — на этом сервере или 2 — на отдельном сервере.
На этом сервере: оба домена направляются на IP панели. Мастер устанавливает sn-sub, настраивает HTTPS и проверяет подписку.
На отдельном сервере: на IP панели направляется только её домен. Домен подписки сохранится для клиентских ссылок; его DNS можно настроить позже на IP второй машины. Мастер не устанавливает локальный sn-sub, не создаёт для него сайт Caddy и не ждёт готовности удалённой подписки.
Поле
Пример и пояснение
Домен панели
panel.example.com — вход администратора; DNS A/AAAA на IP сервера панели
Домен подписки
sub.example.com — адрес подключения клиентов; отдельный домен на IP выбранного сервера подписки, без /ID
Название сервиса
My VPN — название, которое увидят клиенты
Валюта проекта
USD, EUR, RUB, UAH — код из трёх латинских букв для цен и баланса; не сумма и не символ $. Stars настраиваются отдельно
Можно вставить адрес вида https://panel.example.com/: мастер выделит домен. Путь, порт, параметры или логин в адресе не принимаются. При ошибке домена или валюты поле запрашивается повторно; уже введённые ответы сохраняются.
После установки панели для отдельного сервера откройте Настройки → Сервис подписки → Установка → На отдельном сервере, выпустите служебный ключ и выполните команду на второй машине. Затем настройте там DNS/HTTPS и проверьте /ready и реальную ссылку клиента. До этого подписка ещё не готова. Полная инструкция.
Выбор сохраняется в installation.json: обновление и stealthnet doctor проверяют только размещённые на панели службы. Обновление отдельной подписки выполняется на её сервере. В установках прежних версий отсутствие выбора означает прежнее размещение вместе с панелью.
Мастер попросит домены, название сервиса, валюту проекта, логин и пароль владельца. Пустой пароль означает генерацию случайного пароля. Токен Telegram можно пропустить и добавить позже. Пароли и токены не выводятся при вводе и не передаются в аргументах процессов.
Загрузчик определяет архитектуру и тег последнего стабильного релиза, скачивает архив и его SHA256 по HTTPS, проверяет архив и каждый файл из манифеста. Изменённый архив, чужая архитектура, неполный релиз или отсутствие контрольной суммы останавливают установку.
После подготовки базы применяются все миграции по порядку. Демо-клиенты, тарифы и платёжные реквизиты не создаются. Валюта и название берутся из вашего ввода. Службы работают от отдельного пользователя stealthnet; база и ключи доступны только root через файл окружения systemd.
Успешное завершение означает, что API ответил с рабочей базой, службы панели запущены и её HTTPS-домен проверен с проверкой сертификата. При совместном размещении также проверяются /ready и HTTPS подписки; отдельный сервис проверяется после его установки на второй машине. Если сертификат не выпущен, установщик сообщает ошибку, а не готовность.
Данные владельца находятся в /root/stealthnet-access.txt, права 600. Сохраните их в менеджере паролей и удалите этот файл. Он не публикуется через веб-сервер.
После установки
stealthnet doctor # релиз, службы, API, база, подписки и HTTPS
stealthnet status # состояние служб (бот без токена будет отключён)
stealthnet logs api # журнал API, также sub / worker / bot
stealthnet bot-token # добавить/заменить токен бота скрытым вводом
stealthnet admin-password # сменить пароль существующего администратора
В админке создайте профиль, ноду, хост и сквад, затем настройте тарифы и платежи. В разделе клиентского кабинета задайте брендинг и выполните установку. Пакеты устройств и трафика задаются отдельно в каждом тарифе.
Быстрое обновление
На сервере панели от root:
cd /opt/stealthnet-software
make update
То же из любой папки:
stealthnet update
Конкретный опубликованный релиз:
make update VERSION=v0.2.6
# или
stealthnet update --version v0.2.6
Для конкретной версии используйте тег опубликованного релиза.
Обновление проверяет файлы, создаёт PostgreSQL dump и копию конфигурации, применяет миграции, атомарно переключает current, перезапускает службы панели и проверяет их. Ноды и их Xray не перезапускаются. Их обновление выполняется отдельно из раздела нод. Кабинет и отдельный сервис подписок обновляются своими командами.
Верхняя кнопка версии в админке открывает сведения о сборке и проверку GitHub. Проверка выполняется на сервере панели, результат сохраняется на 15 минут; ошибка — на одну минуту. Публикуемые стабильные релизы должны содержать готовые архивы обеих архитектур с SHA256. Страница различает новую версию, актуальную сборку, сборку новее GitHub, отсутствие релизов и ошибку связи. Описание релиза показывается текстом без исполнения HTML.
Резервные копии: /opt/stealthnet-software/backups/<дата-UTC>/. При ошибке запуска новой версии возвращаются прежние бинарники. Уже применённые миграции автоматически не отменяются. Релизы должны использовать обратно совместимые миграции. Восстановление БД из dump — отдельная операция в окно обслуживания: оно отменяет изменения данных после момента копии.
Если установка оборвалась
Панель открылась без оформления
В релизах до 0.1.7 правило Caddy /app* могло возвращать заглушку Mini App вместо /app.css. Браузер сообщал MIME type ('text/html') is not a supported stylesheet. Обновите установленную панель от root:
cd /opt/stealthnet-software
make update VERSION=v0.2.6
Обновление создаёт резервную копию и исправляет старое правило в конфигурации, созданной установщиком, сохраняя остальные настройки. После обновления перезагрузите страницу с очисткой кэша (Ctrl+F5 / Cmd+Shift+R). Для своего reverse proxy используйте пути /app и /app/*, без перехвата /app.css. Новые установки и обновления проверяют тип и содержимое основного CSS и JavaScript перед сообщением об успехе. Страница входа показывает версию API без надписи «стенд».
Диагностика незавершённой установки
Журнал: /var/log/stealthnet/install-<дата>.log. Он доступен только root и скрывает введённые секреты. Журналы служб: journalctl -u sn-api -n 100, journalctl -u sn-sub -n 100, journalctl -u caddy -n 100.
Исправьте причину и повторите ту же команду. Незавершённая установка использует сохранённые параметры и ключи, повторно проверяет миграции и запуск. Не удаляйте .env или .install-pending.json, чтобы «начать заново»: они связывают настройку с уже созданной базой. Повторный запуск на готовой панели предлагает обновление, а не создаёт владельца заново.
Частые причины:
Ошибка
Что проверить
Нет релиза / HTTP 404
Опубликован ли стабильный GitHub Release, правильный ли тег. Черновики недоступны клиентам.
SHA256 не совпадает
Повторить загрузку; если повторяется — проверить файлы релиза. Не отключать проверку.
Нет DNS-записи
A/AAAA домена панели; при совместном размещении — также домена подписки. Дождитесь распространения DNS.
HTTPS не проходит
IP в DNS, неверная AAAA, TCP 80/443 в firewall провайдера, журнал Caddy, лимиты ACME.
Порт занят
Другой сервис на 80/443 или 8080/8081; мастер не выключает его автоматически.
База/роль уже есть
Возможно, это существующая установка. Её пароль не будет автоматически заменён.
apt заблокирован
Дождаться unattended-upgrades и повторить команду; apt ожидает блокировку до 180 секунд.
Последний шаг остановился на HTTPS / URLError
Если ошибка появилась после строки «Проверяем HTTPS и сертификаты», локальные API, база и сервис подписок уже прошли проверку. Старые версии мастера показывают только URLError: это общий тип ошибки соединения, а не доказательство проблемы с сертификатом.
Сверьте DNS домена панели с её публичным IP. При совместном размещении туда же должен вести домен подписки; для отдельной машины её домен проверяется на том сервере. Запись AAAA нужна только при работающем IPv6. Проверьте TCP 80/443 как в firewall сервера, так и в сетевых правилах провайдера; порты приложений 8080/8081 открывать наружу не нужно.
Connection refused / «соединение отклонено»: на выбранном IP и порту нет доступного слушателя либо соединение отклоняет firewall. Проверьте адрес, статус Caddy и список портов.
Timeout / «время ожидания»: проверьте адрес, маршрутизацию и блокировку трафика.
Ошибка сертификата: проверьте журнал Caddy, DNS, доступность портов для ACME и время сервера. Не отключайте проверку TLS.
HTTP 502: веб-сервер доступен, но не получает корректный ответ от приложения; проверьте локальный API и маршрут reverse proxy.
После исправления повторите команду установки той же версии. Установка, остановившаяся на шаге 7, ещё не считается завершённой: make update её не завершает. Сохраните .env, .install-pending.json и созданную базу — повторный запуск использует их.
Свой reverse proxy / автоматическая установка
Для уже настроенного nginx/Caddy или автоматизации создайте root-owned JSON с правами 600. Это режим для администратора инфраструктуры, обычному клиенту достаточно мастера.
Обязательные поля: panel_domain, sub_domain, brand, currency, admin_user, admin_password. Необязательные: bot_token (пустая строка отключает бот), proxy (caddy, по умолчанию, или external), subscription_placement (local, по умолчанию, или remote). Домен подписки остаётся обязательным в обоих вариантах: для отдельного сервера можно указать будущий домен без готового DNS. proxy выбирает управление HTTPS, а subscription_placement — сервер подписки; это разные настройки. Пароль: 12–128 символов. Конфигурацию передают файлом, не аргументами командной строки.
В режиме external установщик не меняет веб-сервер и его firewall. Он проверяет только локальные службы, оставляет пример в /opt/stealthnet-software/Caddyfile.example и явно сообщает, что внешний HTTPS нужно настроить самостоятельно. Проксируйте панель со статикой из current/web, /api/* на 127.0.0.1:8080, подписки на 127.0.0.1:8081. Пути /app и /app/* должны отдавать miniapp-unavailable.html. Caddy-пример содержит эти правила и заголовки.
При закрытом доступе к GitHub можно перенести опубликованный архив и .sha256 по доверенному каналу, проверить sha256sum, безопасно распаковать и выполнить python3 <релиз>/deploy/installer.py install --release-dir <релиз> --config /root/install.json. При таком способе администратор отвечает за проверку внешней SHA256 до запуска; внутренний манифест проверяется установщиком.
Файлы на сервере
Путь
Содержимое
/opt/stealthnet-software/.env
База, ключ шифрования кодов, токены; root, 600
/opt/stealthnet-software/releases/<версия>
Неизменяемые бинарники и статика
/opt/stealthnet-software/current
Активный релиз
/opt/stealthnet-software/installation.json
Версия и параметры установки без пароля
/var/lib/stealthnet
Рабочий каталог служб
/etc/systemd/system/sn-*.service
Службы api, sub, bot, worker
/etc/caddy/stealthnet/panel.caddy
Домены панели и подписок; другие сайты Caddy сохраняются
/var/log/stealthnet
Закрытые журналы установщика
Сохранение .env, особенно CABINET_CODE_KEY, обязательно для восстановления клиентских кодов. Вместе с дампом базы храните копию этого файла вне сервера.
Старые установки из исходников продолжают использовать deploy/update-source.sh через корневой update.sh. Этот режим пересобирает уже загруженные исходники и не переводит существующий стенд на релизную структуру автоматически.
Что сохраняется при обновлении
make update меняет готовый код и применяет новые миграции один раз. Пользователи, подписки, платежи, тарифы, профили, брендинг и тексты находятся в PostgreSQL; обновление не запускает db/seed.sql и не создаёт владельца заново. .env и ключ CABINET_CODE_KEY сохраняются без изменения. Текущая конфигурация reverse proxy и дополнительные настройки systemd при обновлении не переписываются.
Свои изображения размещайте в /opt/stealthnet-software/shared/public/, например logo.svg. При стандартной установке Caddy файл доступен как https://panel.example.com/custom/logo.svg; этот адрес можно указать в брендинге админки. Содержимое shared/ не заменяется релизом и входит в резервную копию обновления. Это публичный каталог: ключи и конфигурационные файлы туда не кладут. Для внешнего прокси настройте аналогичный маршрут /custom/.
Каталоги releases/ и current/web содержат код конкретной версии: свои файлы и ручные правки туда не помещайте. Правки исходников и CSS внутри релиза не являются настройками брендинга. Старый релиз остаётся на диске; при ошибке готовности установщик возвращает прежние бинарники. Возврат бинарников не отменяет применённые миграции; для отката данных используется сохранённый dump.
В старом мастере терминал SSH ошибочно открывался как файл с возможностью перемотки. В версии 0.1.6 это исправлено. Если установка остановилась сразу после проверки SHA256 с сообщением «Нет терминала», повторно запустите загрузчик без закрепления старой версии. Файл install.json для обычного интерактивного запуска не нужен; на этом этапе база и учётная запись владельца ещё не создавались.
При запуске через удалённую команду SSH без терминала используйте интерактивный сеанс ssh -t root@SERVER_IP или настройку через --config, описанную выше.