Развёртывание on-premise
Актуально для: SimpleTwo 0.9.x · Проверено: 25.08.2026
К концу этой статьи у вас работает контур, в котором сотрудник входит по корпоративной учётной записи, переписывается, звонит, проводит встречу с внешним участником по ссылке и ходит в корпоративную сеть через защищённый туннель. Порядок шагов не произвольный: каждый следующий сервис настраивается на предыдущий, и часть шагов отказывается выполняться, если предыдущий не готов.
Что в статье не разбирается: облачная поставка, изолированный контур без доступа в интернет, телефония и запись конферен ций — они опциональны и вынесены в отдельные статьи.
Руками ставится один сервис — координатор. Всё остальное (базу, чат, календарь, SFU, TURN, VPN-узлы) координатор ставит сам: вы даёте ему SSH-доступ к хосту и выбираете роль, он копирует туда бинарник, пишет конфиг и systemd-юнит и запускает сервис. Бинарники всех ролей и Xray уже лежат внутри образа координатора — отдельно ничего скачивать не нужно.
1. Что вы разворачиваете
Одна приватная сеть, и все правила до ступа в ней записаны явно. Хосты стоят в общей приватной сети, а между ними — только правила, которые пишет сама плоскость управления:
- база принимает только два хоста —
messagingиcalendar, каждый как/32вpg_hba; - шина принимает только тех, кто на неё ходит — узлы
sfu,mediationиrecorder, — правилом фаервола на своём хосте плюс пароль.
Оба правила применяются заново на каждом опросе состояния, поэтому ни одно из них не приходится помнить и поддерживать руками.
интернет
│
┌──────────────┬─────────────┼──────────────┬───────────────┐
│ │ │ │ │
координатор messaging sfu ×N turn VPN-узлы
(80/443) chat.s2.<домен> calls.s2.<домен> 3478 + (gateway)
│ │ │ 49152–65535 по IP, 443/tcp
└──────────────┴─────────────┴──────────────┴───────────────┘
одна приватная сеть 10.x.x.x
│
┌───────────────┼────────────────┐
postgres calendar redis
только /32 хостов своя база на только адреса
messaging и calendar том же postgres тех, кто ходит на шину
| Роль | Публично | В приватной сети | Зачем |
|---|---|---|---|
| координатор | да, 80 и 443 | да | плоскость управления: каталог и вход, политики, реестр узлов, админка, выпуск сертификатов, установка остальных ролей |
postgres | нет | да | база чата и календаря; снаружи не доступна, а внутри принимает только хосты messaging и calendar — каждый как /32 в pg_hba |
messaging | да | да | чат, треды, файлы, сигналинг звонков; продуктовый сервер |
calendar | да | да | календари, ICS-подписки, CalDAV. Публичен потому, что читатели — не наш клиент: Outlook обновляет подписку, CalDAV-клиент опрашивает. Держит свою базу на том же postgres |
redis | нет | да | шина координации. Нужна со второго узла sfu и обязательна для телефонии. Единственная граница — правило фаервола, поэтому на хосте шины обязателен ufw или firewalld |
sfu | да | да | медиасервер: медиа и сигналинг звонков. Пересылает потоки, не микширует |
turn | да | — | релей для клиентов за строгим NAT |
gateway | да, 443/tcp | DMZ для корпоративного выхода | VPN-узлы (VLESS+Reality), по одному на GEO |
recorder | нет | да | запись конференций (опционально) |
mediation | да | да | телефония SIP/PSTN (опционально) |
support | нет | DMZ рядом с координатором | демон бота поддержки (опционально) |
2. Что нужно заранее
Хосты и размеры на старт
| Хост | vCPU / RAM / диск | Чем ограничен |
|---|---|---|
| координатор | 2 / 4 / 20 ГБ | ничем; держит SQLite и сертификаты в томе |
postgres | 2 / 4 / 40 ГБ SSD | диском |
messaging | 2 / 4 ГБ | диском: вложения лежат на нём, пока не подключено S3 |
redis | 1 / 1 ГБ | ничем; держит маршрутизацию комнат, не данные |
sfu, каждый | 4 / 8 ГБ | каналом: SFU пересылает каждый поток каждому участнику, аплинк упирается раньше проц ессора |
turn | 2 / 2 ГБ | каналом, по той же причине |
calendar | 2 / 4 ГБ | опросом, а не людьми: подписанный Outlook и CalDAV-клиент приходят по своему расписанию |
gateway, каждый | 1 / 1 ГБ | каналом |
ОС на хостах ролей: Ubuntu 22.04 / 24.04, amd64 или arm64. На хосте координатора нужны Docker Engine и плагин Compose.
Имена DNS
Соглашение: база тенанта — s2.<домен-организации>, сервисы — поддомены от неё.
| Имя | На что | Обязательно |
|---|---|---|
s2.<домен> | координатор | да |
chat.s2.<домен> | хост messaging | да, для чата |
calls.s2.<домен> | хост sfu | да, для звонков |
turn.s2.<домен> | хост turn | рекомендуется |
Приложение находит ваш контур по домену почты: ivan@<домен> → s2.<домен>. Если поддомен
s2. занять нельзя, есть альтернатива — файл https://<домен>/.well-known/simpletwo.json
в корне основного домена.
VPN-узлам DNS не нужен: клиент ходит на IP:443, а SNI в их конфигурации — домен
камуфляжа, а не ваша запись.
Порты
| Где | Наружу | Зачем |
|---|---|---|
| координатор | 80/tcp, 443/tcp | админка и API; порт 80 нужен для выпуска сертификатов (HTTP-01), 443 — для TLS-ALPN-01 |
messaging | 443/tcp | REST и WebSocket клиентов, выпуск своего сертификата |
sfu | 443/tcp | wss://calls.s2.<домен> и медиа |
turn | 3478 + 49152–65535/udp | релей |
gateway | 443/tcp | VLESS+Reality |
| все хосты ролей | 22/tcp с адреса координатора | установка и обновление по SSH |
Доступы
- SSH к каждому хосту роли: пользователь
rootлибо пользователь с беспарольнымsudo, и приватный ключ, который вы дадите координатору. На хостах нуженcurl. - Доступ к образу координатора: GitLab Container Registry или переданный вам архив образа.
- Домен организации и возможность править его DNS-зону.
3. Шаг 1. Координатор
mkdir -p /opt/simpletwo && cd /opt/simpletwo
# положите рядом deploy/docker-compose.coordinator.yml как docker-compose.yml
cp <путь>/docker-compose.coordinator.yml ./docker-compose.yml
echo "COORDINATOR_IMAGE=<registry>/coordinator:<версия>" > .env
docker login <registry>
docker compose pull && docker compose up -d
В compose-файле нет ни одного секрета, и это сознательно: координатор генерирует свои секреты
сам (секрет подписи токенов, токен узлов, учётную запись администратора) при первом запуске и
хранит их в томе coordinator-data. Порты: 80:8080 и 443:8443 — TLS терминир уется внутри
координатора, внешний обратный прокси не нужен.
Проверка:
docker compose ps # healthy
curl -fsS http://127.0.0.1/healthz # 200
Заберите одноразовый bootstrap-токен — он печатается в лог при первом запуске и лежит в томе:
docker compose logs coordinator | grep -i bootstrap
docker compose exec coordinator cat /data/bootstrap-token
Откройте http://<адрес>/admin, вставьте токен, задайте пароль администратора и публичный
URL (https://s2.<домен>). Дальше вход только по паролю; токен больше не действует.
В coordinator-data лежат секреты, база плоскости управления и сертификаты. Потеря тома
означает переустановку контура и перерегистрацию всех узлов. Он — первый пункт в бэкапе (§9).
4. Шаг 2. Имя и сертификат координатора
- Создайте
A-записьs2.<домен>на публичный адрес хоста координатора. - В админке: Settings → TLS → Tenant domains → добавьте
s2.<домен>. Сертификат выпустится автоматически при первом обращении по этому имени. - Проверьте снаружи, а не с самого хоста:
curl -fsS https://s2.<домен>/healthz
curl -fsS https://s2.<домен>/.well-known/simpletwo.json
Выпуск сертификата требует, чтобы хост был доступен из интернета на 80 и 443 в момент выпуска. Если запись ещё не разошлась по DNS, выпуск не удастся — это не ошибка настройки, просто повторите позже.
5. Шаг 3. Роли, строго по порядку
Все роли ставятся из админки: Installed servers → Add a host. Для каждого хоста нужны
адрес, SSH-пользователь, приватный ключ, роль и приватный адрес — тот, по которому этот
хост видят остальные. Перед установкой нажмите Test SSH: он проверяет доступность до
того, как что-то начнёт устанавливаться. Ход установки виден в Provisioning log, статус
проходит pending → deploying → waiting → active.
redis защищён паролем и правилом, разрешающим 6379 только тем, кто на шину ходит —
узлам sfu, mediation и recorder. В одной приватной сети это правило и есть вся
граница шины, поэтом у на хосте без ufw и без firewalld установка откажется
выполняться, а не поднимет базу, доступную всей сети. Список адресов плоскость управления
ведёт сама: добавили узел SFU, телефонию или запись — правило дополнилось на следующем
опросе состояния.
Порядок:
1) postgres → 2) messaging → 3) calendar (опционально) → переустановить
postgres один раз → 4) redis → 5) sfu узел A → 6) sfu узел B →
7) turn
Почему postgres переустанавливается: правила доступа к базе сужаются до /32 адресов хостов
messaging и calendar, а записать их нельзя, пока этих хостов не существует. Одна
переустановка закрывает оба.
Приватный адрес нельзя отдавать клиентам. Приватный адрес хоста идёт в поле private address; адрес, по которому клиенты обращаются к SFU, — в node IP. Перепутаете — звонок установится, медиа не пойдёт, соединение отвалится по таймауту, и ни в одном журнале ничего не будет.
Ещё две вещи, которые продукт не даст сделать неправильно:
- Второй узел
sfuбезredisустановить нельзя — установка откажется. Два узла без шины ведут каждый свою таблицу комнат: двое «в одной встрече» на разных узлах не видят друг друга, и никто об этом не сообщает. calendarможно не ставить. Пока хоста календаря нет, клиенты прячут экраны календаря, а не показывают кнопки, которые не работают.
Чат: имя и сертификат
После установки messaging откройте карточку Messaging TLS: укажите hostname
chat.s2.<домен> → Save config → Redeploy → Issue. Сертификат выпустится по
TLS-ALPN-01 на :443, а адрес https://chat.s2.<домен> попадёт в дискавери автоматически. Для
проверки схемы есть флаг staging — тестовый сертификат Let's Encrypt, который не
расходует лимиты.
Звонки: адрес для клиентов
Для sfu нужен TLS-фронт с сертификатом на calls.s2.<домен> — этот сертификат
выпускается вручную, координатор его не выдаёт. Адрес wss://calls.s2.<домен>
указывается в Settings → Calls → Client URL.
Проверка после каждой роли
curl -fsS https://chat.s2.<домен>/healthz # messaging
curl -fsS https://s2.<домен>/healthz # координатор видит состояние ролей
В админке у каждой установленной роли есть строка состояния: координатор сам опрашивает
/healthz ролей. Роль в статусе active, но с красным состоянием — это установленный
сервис, который не работает; смотрите Host logs.