On-Premise сервер
CloudPub On-Premise — это корпоративное решение для развертывания платформы туннелирования на собственной инфраструктуре. Данная версия позволяет организациям получить полный контроль над процессом публикации локальных сервисов, обеспечивая максимальную безопасность, соответствие требованиям информационной безопасности и независимость от внешних облачных провайдеров.
Серверная часть поставляется в виде универсального Docker-образа. Образ не содержит привязки к домену, секретов или брендинга - вся конфигурация задается переменными окружения при запуске контейнера. Один и тот же образ обслуживает любое развертывание, а установка занимает несколько минут.
Здесь описан серверный образ. Образ Docker для агента описан на отдельной странице.
Системные требования
Раздел содержит минимальные и рекомендуемые системные требования для развертывания и стабильной работы системы. Требования разделены на базовые (необходимые для функционирования основных компонентов) и дополнительные (зависящие от планируемой нагрузки и количества подключаемых агентов).
При планировании инфраструктуры следует учитывать как текущие потребности, так и возможности масштабирования системы в будущем. Представленные расчеты основаны на средних показателях производительности и могут варьироваться в зависимости от специфики использования и характера обрабатываемого трафика.
Базовые требования
- Операционная система: Debian 12 или Ubuntu 22.04 (рекомендуется использовать минимальную установку без графического интерфейса)
- RAM: 4 GB
- CPU: 4 ядра (для базовой работы системы и сервиса туннелей)
- Дисковое пространство: 50 GB для системы и базовых нужд
Дополнительные требования
- RAM: Дополнительно 25 МБ на каждого подключенного агента
- CPU: 1 дополнительное ядро на каждых 250 агентов
- Если требуется запись трафика: примерно 1 GB на агента в день
Пример: Сервер на 1000 агентов
- RAM: 4 GB + (1000 * 25 MB) = 29 GB
- CPU: 4 ядра + (1000 / 250) = 8 ядер
- Дисковое пространство: 50 GB + (1000 * 1 GB) = 1050 GB (около 1 TB, глубина записи 1 день)
Подготовка инфраструктуры
Для корректной работы системы требуется подготовка инфраструктуры. Процесс развертывания включает настройку сервера, конфигурацию доменных имен, SSL-сертификатов и интеграцию с внешними сервисами.
Все компоненты должны быть подготовлены заранее, так как некоторые из них могут потребовать времени на получение или настройку (например, SSL-сертификаты или настройка DNS).
Настоятельно рекомендуется настроить бекапы виртуальной машины средствами гипервизора или использовать специализированные инструменты резервного копирования для Linux. Настройка резервного копирования является ответственностью пользователя.
Необходимые компоненты и информация
- Зарегистрированый домен 1 или 2 уровня (example.com или tunnel.example.com)
- WildCard TLS сертификат в формате PEM (сертификат и приватный ключ), покрывающий и сам домен, и маску поддоменов: example.com + *.example.com (или tunnel.example.com + *.tunnel.example.com)
- Возможность добавить в DNS A-записи домена и wildcard-маски
- Сервер (виртуальный или физический), соответсвующий системным требованиям
- Логин/пароль root или пользователь с правами sudo
- SSH доступ к серверу (публичный ключ будет предоставлен)
- SMTP сервер для отправки транзакционной почты (host, логин, пароль, port, TLS/SSL)
- E-Mail адрес для системных уведомлений и поддержки пользователей
- Название сайта (например, "MyCompany Tunnel")
- Опционально: API token и Chat ID для бота telegram c системными уведомлениями
- Опционально: логин/пароль акканута на DockerHub (если нужен репозиторий Docker образов)
Домен, DNS и TLS-сертификат
Каждая публикация получает собственный поддомен внутри домена сервера, например
resolutely-tough-petrel.example.com. Поэтому для полноценной работы нужны две вещи:
wildcard-запись A в DNS и wildcard TLS-сертификат. Без них панель управления
откроется, но опубликованные ресурсы будут недоступны или отдадут ошибку сертификата.
Записи DNS. На IP-адрес сервера должны указывать A-записи и самого домена, и wildcard-маски. Домен может быть как второго уровня, так и поддоменом:
; вариант 1: домен второго уровня, IP сервера 203.0.113.10
example.com. IN A 203.0.113.10
*.example.com. IN A 203.0.113.10
; вариант 2: выделенный поддомен
tunnel.example.com. IN A 203.0.113.10
*.tunnel.example.com. IN A 203.0.113.10
Первая запись обслуживает панель управления, вторая - поддомены публикаций. Проверить можно так (обе команды должны вернуть IP сервера, вторая - для любого случайного имени):
dig +short example.com
dig +short random-name.example.com
Тот же публичный IP укажите в CLOUDPUB_IP и CLOUDPUB_EDGES.
Сертификат. Он должен покрывать оба имени: сам домен и маску поддоменов. Wildcard сам по себе апекс не покрывает, поэтому в SAN должны быть обе записи:
X509v3 Subject Alternative Name:
DNS:example.com, DNS:*.example.com
Проверить готовый сертификат:
openssl x509 -in certificate.crt -noout -checkhost example.com
openssl x509 -in certificate.crt -noout -checkhost demo.example.com
Маска покрывает ровно один уровень. Сертификат на *.example.com подходит для
demo.example.com, но не подходит ни для example.com, ни для a.b.example.com.
При развертывании на поддомене (tunnel.example.com) нужны SAN tunnel.example.com
и *.tunnel.example.com.
Wildcard-сертификат от Let's Encrypt выпускается только через проверку DNS-01, HTTP-01 для масок не работает:
certbot certonly --manual --preferred-challenges dns \
-d example.com -d '*.example.com'
Полученные файлы кладутся в том данных, см. TLS-сертификаты. Если сертификат не предоставлен, контейнер выпускает самоподписанный сразу с обоими именами - этого достаточно для первого запуска и тестов, но браузер будет предупреждать о недоверенном сертификате.
Быстрый старт
Для работы нужны три сервиса: PostgreSQL, Redis и сам сервер. Минимальный
docker-compose.yml:
services:
db:
image: postgres:latest
environment:
POSTGRES_USER: cloudpub
POSTGRES_PASSWORD: <пароль-БД>
POSTGRES_DB: cloudpub
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
- pgdata:/var/lib/postgresql/data/pgdata
restart: unless-stopped
redis:
image: redis:7-alpine
restart: unless-stopped
node:
image: docker.ermak.dev/cloudpub/server:latest
ports:
- "443:443"
- "80:80"
environment:
CLOUDPUB_DOMAIN: cloud.example.com # единственная обязательная переменная
POSTGRES_HOST: db
POSTGRES_PASSWORD: <пароль-БД>
REDIS_HOST: redis
volumes:
- cloudpub-data:/var/lib/cloudpub
restart: unless-stopped
depends_on:
- db
- redis
volumes:
pgdata:
cloudpub-data:
docker compose up -d
При первом запуске контейнер автоматически: формирует конфигурацию сервера под указанный
домен, дожидается базы данных, применяет миграции, создает расширение pg_trgm,
генерирует самоподписанный TLS-сертификат (если не предоставлен настоящий) и запускает
все сервисы.
Первый администратор создается интерактивно:
docker compose exec node clo createsuperuser
После этого панель управления доступна по адресу https://cloud.example.com.
Дистрибутивы агента образ раздает сам, по адресу https://cloud.example.com/download/stable/.
Ссылки на панели управления и автообновление подключенных агентов ведут туда же, поэтому
установка и обновление агентов не требуют доступа в интернет.
Порты 443 и 80 должны быть доступны снаружи (порт 80 обслуживает перенаправление на HTTPS и ACME-проверки). A-записи домена и wildcard-маски, а также требования к сертификату описаны в разделе Домен, DNS и TLS-сертификат.
Переменные окружения
Обязательная переменная одна - CLOUDPUB_DOMAIN. Остальные опциональны и сгруппированы
по назначению.
Идентификация сервера
| Переменная | Назначение | По умолчанию |
|---|---|---|
CLOUDPUB_DOMAIN | Публичный домен сервера | - (обязательна) |
CLOUDPUB_PORT | Публичный HTTPS-порт | 443 |
CLOUDPUB_IP | Публичный IP-адрес, показываемый пользователям для A-записей при подключении своего домена | пусто |
CLOUDPUB_EDGES | Список публичных IP-адресов сервера через запятую (используется бэкендом) | 127.0.0.1 |
Для развертывания на одном сервере задайте CLOUDPUB_IP и CLOUDPUB_EDGES в один и тот же
публичный IP-адрес.
Брендинг и интерфейс
| Переменная | Назначение | По умолчанию |
|---|---|---|
CLOUDPUB_SITE_NAME | Название сайта в интерфейсе | CloudPub |
CLOUDPUB_ENTITY, CLOUDPUB_INN | Юридическое лицо и ИНН в подвале | пусто |
CLOUDPUB_EMAIL, CLOUDPUB_PHONE, CLOUDPUB_TELEGRAM | Контакты поддержки в интерфейсе | пусто |
CLOUDPUB_TRAFFIC_LIMIT | Лимит трафика бесплатного тарифа, байт (0 - без лимита) | 0 |
CLOUDPUB_LOG_LEVEL | Уровень логирования сервера | info |
CLOUDPUB_DEBUG | Режим отладки Django (true/false) - только для диагностики | false |
TLS
| Переменная | Назначение | По умолчанию |
|---|---|---|
CLOUDPUB_CERT_FILE, CLOUDPUB_KEY_FILE | Пути к сертификату и ключу основного домена | certs/certificate.{crt,key} в томе |
CLOUDPUB_CA_FILE | Путь к CA-бандлу для проверки клиентских сертификатов | не задан |
CLOUDPUB_ACME_EMAIL | E-Mail для регистрации ACME-аккаунта (сертификаты клиентских доменов) | не задан |
Почта (SMTP)
| Переменная | Назначение | По умолчанию |
|---|---|---|
CLOUDPUB_EMAIL_HOST | SMTP-сервер (без него почта пишется в файлы) | не задан |
CLOUDPUB_EMAIL_PORT | Порт SMTP | 465 |
CLOUDPUB_EMAIL_USER, CLOUDPUB_EMAIL_PASSWORD | Учетные данные SMTP | пусто |
CLOUDPUB_EMAIL_USE_SSL | Использовать SSL | true |
CLOUDPUB_EMAIL_USE_TLS | Использовать STARTTLS | false |
CLOUDPUB_SUPPORT_EMAIL | Адрес отправителя и адрес поддержки | support@<домен> |
Интеграции и уведомления
| Переменная | Назначение | По умолчанию |
|---|---|---|
CLOUDPUB_TELEGRAM_BOT_TOKEN, CLOUDPUB_TELEGRAM_CHAT_ID | Telegram-бот для системных уведомлений | не задан |
CLOUDPUB_SENTRY_DSN | DSN для отправки ошибок в Sentry | не задан |
CLOUDPUB_SMS_RU_API_KEY | Ключ API sms.ru для отправки SMS | не задан |
Учетные записи
| Переменная | Назначение | По умолчанию |
|---|---|---|
CLOUDPUB_ADMIN_EMAIL, CLOUDPUB_ADMIN_PASSWORD | Автосоздание администратора при старте (для развертывания из секрет-менеджера; иначе используйте clo createsuperuser) | не задан |
База данных и кеш
| Переменная | Назначение | По умолчанию |
|---|---|---|
POSTGRES_HOST, POSTGRES_PORT, POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD | Подключение к PostgreSQL | db:5432, cloudpub |
CLOUDPUB_DB_CONNECT | Полный URL подключения к PostgreSQL (заменяет POSTGRES_*) | строится из POSTGRES_* |
REDIS_HOST, REDIS_PORT | Подключение к Redis | redis:6379 |
CLOUDPUB_REDIS_URL | Полный URL подключения к Redis (заменяет REDIS_HOST/PORT) | строится из REDIS_HOST/PORT |
Без настроенного SMTP исходящая почта (ссылки регистрации, восстановление пароля) не
доставляется. Для боевого развертывания задайте CLOUDPUB_EMAIL_* или создавайте
пользователей через администратора.
CLOUDPUB_TELEGRAM - это контакт поддержки, отображаемый в интерфейсе. Токен и chat ID
бота для системных уведомлений задаются отдельными переменными
CLOUDPUB_TELEGRAM_BOT_TOKEN и CLOUDPUB_TELEGRAM_CHAT_ID.
TLS-сертификаты
Сертификат основного домена. Положите wildcard-сертификат в том данных:
certs/certificate.crt и certs/certificate.key (пути настраиваются через
CLOUDPUB_CERT_FILE/CLOUDPUB_KEY_FILE). Если сертификат не предоставлен, контейнер
генерирует самоподписанный - удобно для первого запуска и тестов. При смене домена
самоподписанный сертификат перевыпускается автоматически, предоставленный вручную -
никогда не затрагивается.
Сертификаты клиентских доменов. Когда пользователь подключает собственный домен,
сертификат выпускается автоматически через Let's Encrypt (задайте CLOUDPUB_ACME_EMAIL)
и продлевается встроенными заданиями. Сертификат, полученный вне CloudPub, достаточно
положить в том данных как letsencrypt/live/<домен>/fullchain.pem и privkey.pem -
сервер подхватывает содержимое каталога на лету, без перезапуска.
Хранение данных
Все постоянное состояние сервера живет в одном томе, смонтированном в
/var/lib/cloudpub:
/var/lib/cloudpub/
├── certs/ сертификат основного домена
├── instance_id уникальный идентификатор установки (создается при первом старте)
├── license файл лицензии (устанавливается при развертывании)
├── letsencrypt/ ACME-аккаунт и сертификаты клиентских доменов
├── media/ записи трафика и медиа-данные
└── sockets/ служебные сокеты публикаций
Резервная копия развертывания - это дамп PostgreSQL плюс архив этого тома:
docker compose exec db pg_dump -U cloudpub cloudpub > backup.sql
docker run --rm -v cloudpub_cloudpub-data:/data -v $PWD:/backup alpine \
tar czf /backup/cloudpub-data.tar.gz -C /data .
Redis используется только как кеш и шина сообщений - его данные не требуют сохранения.
Лицензирование
Сервер лицензируется по количеству агентов и одновременно активных публикаций. Без файла лицензии он работает в пробном режиме со встроенными ограничениями: до 5 агентов и до 10 одновременно активных публикаций. Лицензия снимает или расширяет эти лимиты.
Лицензия привязывается к идентификатору установки - случайному UUID, который генерируется при первом старте сервера и хранится в томе данных. Получить его можно командой:
docker compose exec node cat /var/lib/cloudpub/instance_id
Идентификатор также выводится в лог сервера при старте (строка Instance ID).
Порядок активации:
- Получите идентификатор установки и передайте его поставщику лицензии.
- Полученный файл лицензии поместите в том данных:
docker compose cp license node:/var/lib/cloudpub/license
- Лицензия применяется автоматически в течение нескольких секунд, перезапуск сервера не требуется. Сводка по лимитам выводится в лог при старте.
Идентификатор установки хранится в томе данных (instance_id). При удалении тома
он будет сгенерирован заново, и файл лицензии перестанет подходить - сохраняйте
резервную копию тома или как минимум файлов instance_id и license.
Пути файлов настраиваются переменными окружения:
| Переменная | Назначение | По умолчанию |
|---|---|---|
CLOUDPUB_LICENSE_PATH | Путь к файлу лицензии | /var/lib/cloudpub/license |
CLOUDPUB_INSTANCE_ID_PATH | Путь к идентификатору установки | /var/lib/cloudpub/instance_id |
Администрирование
Любые команды управления выполняются внутри контейнера через clo:
docker compose exec node clo createsuperuser # создать администратора
docker compose exec node clo changepassword # сменить пароль пользователя
docker compose exec node clo shell # консоль Django
Изменение конфигурации. Поменяйте переменные окружения в compose-файле и пересоздайте
контейнер: docker compose up -d --force-recreate node. Данные при этом сохраняются -
они живут в томе и базе данных.
Обновление. Получите новый образ и перезапустите: docker compose pull node && docker compose up -d node. Миграции базы данных применяются автоматически при старте.