Внешний сервер

SUBPAGE — страница подписки

Отдельный веб-сервер для страницы подписки пользователей. Рекомендуется размещать на независимом сервере с собственным доменом.

Ubuntu 24.04 Python 3.12 nginx + SSL systemd
⚠️
Рекомендация по домену. Настоятельно рекомендуется использовать отдельный домен для SUBPAGE, не связанный с доменом бота. Например, если бот на bot.example.com, для SUBPAGE возьмите другой домен. Это повышает безопасность и позволяет независимо управлять подписками.
🚨
Переезд SUBPAGE с домена бота на внешний сервер.
Если ранее SUBPAGE работал на том же домене, что и бот, и вы решаете вынести его на отдельный сервер — необходимо сменить домен бота на новый, а прежний домен привязать к внешнему SUBPAGE-серверу.

В противном случае клиенты продолжат получать подписку через бота, а не через внешний SUBPAGE. В итоге у вас окажутся два активных домена для одной аудитории, и часть клиентов с устаревшими ссылками будет обслуживаться старым адресом.
1

Подготовка сервера

  • 1Сервер с Ubuntu 24.04, доступ root по SSH
  • 2Отдельный домен с A-записью, указывающей на IP этого сервера
    Пример: sub.example.com
  • 3Порты 80 и 443 открыты в файрволе
2

Установка SUBPAGE

Выполните команду на сервере SUBPAGE (не на сервере бота):

bash
bash <(curl -sSL https://update.3xstore.ru/subpage/install.sh)
Скрипт автоматически
  • 1Установит Python 3.12 и необходимые зависимости
  • 2Создаст виртуальное окружение и установит пакеты
  • 3Создаст systemd-сервис для автозапуска
  • 4Установит CLI-утилиту управления subpage
3

Настройка Nginx и SSL-сертификата

После установки запустите CLI-утилиту управления:

bash
sudo subpage
  • 1Запустите CLI: sudo subpage
  • 2В главном меню выберите Управление Nginx
  • 3Выберите Установить и настроить Nginx с SSL
  • 4Введите домен SUBPAGE: например sub.example.com
  • 5Укажите email для Let's Encrypt — получите уведомления об истечении сертификата
  • 6Скрипт получит сертификат через Certbot и настроит nginx как reverse proxy
💡
Certbot использует standalone-режим. Убедитесь, что порт 80 свободен. Для открытия портов в главном меню выберите Управление файрволом.
4

Настройка файрвола (UFW)

bash
sudo ufw allow 22/tcp  comment 'SSH'
sudo ufw allow 80/tcp  comment 'HTTP (Nginx)'
sudo ufw allow 443/tcp comment 'HTTPS (Nginx)'
sudo ufw enable
5

Настройка переменных окружения (.env)

Запустите CLI и выберите Редактировать .env файл:

bash
sudo subpage

В редакторе nano: Ctrl+O — сохранить, Enter — подтвердить, Ctrl+X — выйти.

Основные настройки

.env
# URL API сервера бота (откуда SUBPAGE получает данные подписки)
API_BASE_URL=https://bot.domain.com

# Название проекта — отображается в заголовках приложений и на странице
PROJECT_NAME=VPN Service

# Ссылка на Telegram-поддержку
SUPPORT_URL=https://t.me/support

# Ссылка на сайт
WEBSITE_URL=https://domain.ru

# Текст баннера в приложениях Happ и INCY (одна строка, \n — перенос)
ANNOUNCE_TEXT="?? Сайт/Telegram ??Продлить подписку.\n??Актуальный список серверов??\nПриятного пользования! ??"

# Показывать кнопки копирования ключей пользователю (true / false)
ENABLE_COPY_KEYS=false

# Интервал автообновления подписки в часах (рекомендуется: 1, 2, 3, 6, 12, 24)
UPDATE_INTERVAL_HOURS=1

# Тема страницы подписки: subscription | happcrypt | subscription_custom
SUBSCRIPTION_THEME=subscription

Ссылки на приложения

💡
Ссылки отображаются на странице подписки и в инструкциях по подключению. Убедитесь в их актуальности перед публикацией.
Happ
.env
LINK_IOS=https://apps.apple.com/ru/app/happ-proxy-utility-plus/id6746188973
LINK_IOS_GLOBAL=https://apps.apple.com/us/app/happ-proxy-utility/id6504287215
LINK_ANDROID=https://play.google.com/store/apps/details?id=com.happproxy
LINK_ANDROID_APK=https://github.com/Happ-proxy/happ-android/releases/latest/download/Happ.apk
LINK_WINDOWS=https://github.com/Happ-proxy/happ-desktop/releases/latest/download/setup-Happ.x64.exe
LINK_MAC=https://apps.apple.com/ru/app/happ-proxy-utility-plus/id6746188973
LINK_LINUX=https://github.com/Happ-proxy/happ-desktop/releases/
INCY
.env
LINK_INCY_IOS=https://apps.apple.com/us/app/incy/id6756943388
LINK_INCY_ANDROID=https://play.google.com/store/apps/details?id=llc.itdev.incy
LINK_INCY_ANDROID_APK=https://github.com/INCY-DEV/incy-platforms/releases/latest/download/Incy.apk
LINK_INCY_WINDOWS=https://github.com/INCY-DEV/incy-platforms/releases/latest/download/incy-windows-setup.exe
LINK_INCY_MAC=https://github.com/INCY-DEV/incy-platforms
LINK_INCY_LINUX=https://github.com/INCY-DEV/incy-platforms

Redis — кеширование

.env
USE_REDIS=true
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_DB=0
# Пароль Redis — оставьте пустым если не используется
REDIS_PASSWORD=
# Время жизни кэша (в секундах, по умолчанию 15)
REDIS_CACHE_TTL=15

Белый список приложений и жёсткое ограничение на HWID

ALLOWED_APP_USER_AGENTS — если переменная не задана, подписку получают все VPN-приложения (поведение по умолчанию). Если задана — только те, чей User-Agent содержит одну из указанных подстрок. Браузеры всегда видят веб-страницу подписки и данная настройка на них не влияет.

REQUIRE_HWID — если true, VPN-клиенты без заголовка X-HWID получают заглушку вместо ключей подписки. Браузеры и запросы на веб-страницу не затрагиваются.

.env
# Белый список приложений по User-Agent (подстроки через запятую)
# Не задан — подписку получают все; задан — только перечисленные
# ALLOWED_APP_USER_AGENTS=happ,incy

# Требовать заголовок X-HWID от VPN-клиентов
# Если true — клиенты без X-HWID получат заглушку вместо ключей
REQUIRE_HWID=false

Кастомные HTTP-заголовки ответа

💡
Любая переменная с префиксом RESP_HEADER_ автоматически добавляется как HTTP-заголовок в ответ VPN-клиенту. Подчёркивания в имени переменной после префикса автоматически преобразуются в дефисы.
Пример: RESP_HEADER_hide_settings > заголовок hide-settings
⚠️
Имена переменных в .env не могут содержать дефисы. Используйте подчёркивания — они автоматически заменятся на дефисы в HTTP-заголовке.
Неверно: RESP_HEADER_hide-settings=1
Верно: RESP_HEADER_hide_settings=1
Примеры для приложения Happ
.env
# Уникальный ID провайдера в Happ.
# Привязывает подписку к вашему аккаунту — пользователь не сможет
# сменить провайдера вручную.
# RESP_HEADER_providerid=ВАШ_PROVIDER_ID

# Скрыть конфигурации серверов от пользователя (1 — скрыть, 0 — показать)
# RESP_HEADER_hide_settings=1

# Маршрутизация через Happ Routing (base64-закодированный JSON)
# RESP_HEADER_routing=happ://routing/onadd/ВАША_BASE64_СТРОКА

Документация Happ: happ.su/main/ru/dev-docs/app-management

После сохранения .env перезапустите сервис:

bash
sudo systemctl restart subpage
7

Проверка работы

Статус сервиса
bash
sudo systemctl status subpage
Логи в реальном времени
bash
sudo journalctl -u subpage -n 50 -f
💡
Откройте в браузере: https://ваш-домен/sub/test-uuid — должна появиться страница подписки (ошибка UUID — это нормально).
8

Полезные команды управления

CLI-утилита
bash
sudo subpage
Команды systemctl
bash
sudo systemctl start   subpage   # Запустить
sudo systemctl stop    subpage   # Остановить
sudo systemctl restart subpage   # Перезапустить
sudo systemctl status  subpage   # Статус
sudo systemctl enable  subpage   # Включить автозапуск
sudo systemctl disable subpage   # Отключить автозапуск