Перейти к основному содержимому

Развёртывание 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
s3нетдаобъектное хранилище: вложения, аватары и записи встреч. Объект здесь это обычный файл, поэтому резервная копия делается средствами файловой системы. Принимает только хосты messaging и recorder, каждый как /32 на порту 9000. Роль необязательная: без неё вложения лежат на диске messaging — один хост, одна резервная копия и никакой второй реплики. Вместо роли можно подключить хранилище организации
redisнетдашина координации. Нужна со второго узла sfu и обязательна для телефонии. Единственная граница — правило фаервола, поэтому на хосте шины обязателен ufw или firewalld
sfuдадамедиасервер: медиа и сигналинг звонков. Пересылает потоки, не микширует
turnдарелей для клиентов за строгим NAT
gatewayда, 443/tcpDMZ для корпоративного выходаVPN-узлы (VLESS+Reality), по одному на GEO
recorderнетдазапись конференций (опционально)
mediationдадателефония SIP/PSTN (опционально)
supportнетDMZ рядом с координаторомдемон бота поддержки (опционально)

2. Что нужно заранее

Хосты и размеры на старт

Одна таблица на весь контур: что ставим, сколько ресурсов, в какой сети и чем ограничено. Числа — на старт для организации до ~150 человек (размер S в профиле нагрузки); для организаций побольше смотрите «Сколько узлов под звонки», там масштабируется только медиа.

РольvCPU / RAM / дискСетьГде стоитЧем ограничена
координатор2 / 4 / 20 ГБ100 Мбит/с, публичный IPv4публичнаяничем; держит SQLite и сертификаты в томе
messaging2 / 4 / 100 ГБ SSD100 Мбит/с, публичный IPv4публичнаядиском, пока вложения лежат на нём: с ролью s3 или внешним хранилищем хватает 20 ГБ
s32 / 4 / диск по медиа1 Гбит/с внутри контураприватнаядиском — см. ниже; роль опциональная, не нужна при внешнем хранилище
sfu, каждый4 / 8 / 20 ГБ1 Гбит/с, публичный IPv4публичная + нога в приватную (redis)каналом — см. ниже
turn2 / 2 / 20 ГБ1 Гбит/с, публичный IPv4публичнаяканалом: через него идут ~15% участников, в обе стороны
gateway, каждый1 / 1 / 20 ГБ1 Гбит/с, публичный IPv4публичнаяканалом
calendar2 / 4 / 20 ГБ100 Мбит/с, публичный IPv4публичнаяопросом, а не людьми: подписанный Outlook и CalDAV-клиент приходят по своему расписанию
postgres2 / 4 / 40 ГБ SSD1 Гбит/с внутри контураприватнаядиском; не нужен, если подключён внешний кластер
redis1 / 1 / 10 ГБ1 Гбит/с внутри контураприватнаяничем; держит маршрутизацию комнат, не данные. Не нужен, если подключён внешний
support2 / 4 / 20 ГБ100 Мбит/с внутри контураприватная (DMZ)памятью — см. ниже; роль опциональная

Сколько диска под объектное хранилище

Считается по медиа, а не по людям. На человека в год, по профилю нагрузки и текущим умолчаниям хранения:

ДопущениеНа человека в год
вложения8 файлов в рабочий день × 250 дней, в среднем 400 КБ≈ 0,8 ГБ
миниатюрыодна на картинку, ~40 КБ, картинок половина≈ 0,04 ГБ
аватарыодин на человека, меняется несколько раз в годпренебрежимо
записи встречне входят: час записи комнаты в 720p — около 0,9 ГБ, и это решает политика организации

То есть ≈ 1 ТБ на 1000 человек в год файлов переписки, вдвое больше при регулярной записи встреч. Роль ограничена диском: ни процессор, ни сеть на этом размере не предел. Хранилище — второй хост с состоянием после базы, и его нужно включить в резервное копирование.

Живой пример для сверки: диск на 200 ГБ даёт под объекты 193 ГиБ (ZFS забирает остальное под метаданные и служебный резерв) — это около 230 человеко-лет переписки, то есть организация в 200 человек упрётся в него на втором году. Считать стоит на срок хранения, а не на «сейчас»: диск в пуле расширяется заменой на больший (zpool replace), но это операция с переливом данных, а не правка настройки.

Хранилище на FreeBSD с ZFS

Рекомендуемая форма для боевого контура, и она же та, ради которой выбран движок: versitygw это шлюз S3 перед файловой системой, объект лежит файлом, метаданные в расширенных атрибутах. Все свойства ZFS работают на уровне объекта: снимок это согласованная копия всех вложений, zfs send это копия на второй площадке, скраб ловит битовое гниение, а одно вложение достаётся из .zfs/snapshot вообще без нашего софта.

Хост на FreeBSD присоединяется к платформе так же, как любой другой: агент собирается и под FreeBSD, координатор отдаёт ему нужный бинарь, а служба ставится через rc.d и daemon(8). Диск под объекты платформа теперь размечает сама — руками до присоединения делать ничего не нужно.

1. Машина. Два диска: загрузочный и второй, пустой, под объекты. Размер второго считается по таблице выше. Пустой — это не формальность: агент возьмёт диск только если тот не смонтирован, не размечен и не состоит в пуле (см. ниже).

2. Присоединение. В админке: Серверы и развёртывание → Добавить хост, роль s3, приватный адрес хоста и диск под данные — имя устройства так, как его называет сам хост (vtbd1, da1, nvd0). Приватный адрес обязателен: хранилище слушает именно его, а имя хоста слушать нельзя — служба просто не поднимется. Команду из карточки выполнить на хосте под root. Она определит систему сама (uname -s), возьмёт агент для FreeBSD и поставит службу simpletwo_agent. Если координатор работает с самоподписанным сертификатом, на хосте нужен curl (pkg install -y curl): базовый fetch не умеет закреплять ключ, и вместо тихой незащищённой загрузки команда честно об этом скажет.

Диск можно указать и позже — Серверы → Настроить у нужного хоста. Там же под полем видно, что хост сообщает о своих дисках: имя, размер и занят он или свободен, так что угадывать имя устройства не нужно.

3. Что дальше делает платформа. Создаёт пул simpletwo на указанном диске и датасет simpletwo/s3 с xattr=sa, recordsize=1M, atime=off, compression=lz4, монтирует его в /var/db/simpletwo-s3 и складывает туда data, iam и versions. xattr=sa обязателен: versitygw держит метаданные объекта в расширенных атрибутах, и без sa каждый атрибут становится отдельным скрытым файлом. Дальше ставит versitygw, пишет /usr/local/etc/simpletwo-s3.env (ключи только там, в аргументах командной строки их нет), rc.d-скрипт с daemon(8) и правило pf: порт 9000 открыт только хостам messaging и recorder, каждому как /32. На хосте без pfctl развёртывание падает, а не оставляет хранилище открытым всей приватной сети.

Если поле диска оставить пустым, объекты лягут на загрузочный диск. Платформа так и сделает и напишет об этом в журнал агента — но ни снимка как резервной копии, ни zfs send, ни восстановления одного вложения из .zfs/snapshot у такого хранилища нет.

4. Перенос того, что уже накопилось. Если вложения до этого лежали на диске хоста messaging, они там и останутся: включение хранилища ничего не переносит. Перенос — одна команда на хосте messaging, с окружением самой службы:

set -a; . /etc/simpletwo/messaging.env; set +a
/usr/local/bin/simpletwo-messaging import-media -n # что будет скопировано
/usr/local/bin/simpletwo-messaging import-media # собственно перенос

Запускать можно сколько угодно раз и в любой момент — в том числе после того, как хранилище уже включилось. Объект, который уже лежит в хранилище и той же длины, пропускается, поэтому второй прогон, скопировавший ноль, и есть признак, что перенос закончен (флага «мигрировано» нет намеренно: флаг может врать, второй прогон — нет). Ничего не удаляется: диск остаётся источником, пока вы сами его не почистите. Если хранилище включилось раньше переноса, старые вложения отдают 404 — они никуда не делись, лежат на messaging, и импорт кладёт их туда, куда служба уже смотрит.

Когда платформа откажется брать диск

zpool create — единственная операция платформы, которая уничтожает данные, поэтому агент отказывается при любом сомнении и никогда не передаёт -f. Он не тронет диск, который смонтирован, размечен (gpart) или уже состоит в пуле, и не примет имя, не похожее на устройство. Не смонтирует датасет поверх каталога, в котором уже лежат объекты: они бы не пропали, а спрятались — это хуже, потому что никто об этом не сообщит. И откажется, если пул simpletwo на хосте уже есть, но собран из другого диска: значит, поле поменяли, а перенос данных — это zfs send, а не правка настройки.

Каждый отказ виден в админке в строке хоста, с указанием причины и того, что делать.

Роли и системы

На FreeBSD платформа держит только роль s3. Остальные роли это systemd-службы, пакеты apt и Linux-бинарники: приглашение на такую роль для хоста FreeBSD отклоняется при присоединении, с указанием причины. Хранилище, которое у вас уже есть, по-прежнему подключается как внешнее — Настройки → Внешние хранилища.

3. Шаг 1. Координатор

Из реестра — так выглядит установка целиком, копировать можно построчно:

mkdir -p /opt/simpletwo && cd /opt/simpletwo
curl -fsSL https://docs.simpletwo.ru/deploy/docker-compose.coordinator.yml -o docker-compose.yml

REGISTRY=gitlab.itglobal.com:5050
IMAGE=$REGISTRY/simpletwo/platform/coordinator
echo "COORDINATOR_IMAGE=$IMAGE:v0.9.216" > .env # актуальную версию см. ниже

docker login $REGISTRY # логин GitLab, пароль — токен с read_registry
docker compose pull && docker compose up -d

Какая версия сейчас последняя — спросить, а не угадывать. Спрашивать надо у тегов репозитория, а не у реестра: в реестре рядом с версиями лежат образы веток, помеченные хешами коммитов, их сотни, и они идут первыми — запрос к реестру на первой странице отдаёт одни хеши и ни одной версии (проверено 11.09.2026; ровно на этом можно решить, что версий там нет вовсе). Теги репозитория короткие и отсортированы:

curl -fsS -H "PRIVATE-TOKEN: <токен>" \
"https://gitlab.itglobal.com/api/v4/projects/2081/repository/tags?search=^v0.9&per_page=3" |
grep -o '"name":"[^"]*"'

Каждому такому тегу соответствует образ с тем же именем: сборка образа запускается именно на теге v*.

Тег latest тоже есть, но в .env лучше писать версию: тогда видно, что развёрнуто, и docker compose pull не подтянет новое ядро в неподходящий момент.

Из архива — если доступа к реестру нет:

mkdir -p /opt/simpletwo && cd /opt/simpletwo
docker load < coordinator-v0.9.214.tar # печатает имя загруженного образа
curl -fsSL https://docs.simpletwo.ru/deploy/docker-compose.coordinator.yml -o docker-compose.yml
echo "COORDINATOR_IMAGE=<имя из вывода docker load>" > .env
docker compose up -d # без pull: образ уже локальный

В 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. Имя и сертификат координатора

Координатор сам выпускает себе сертификат Let's Encrypt, но не начинает этого делать, пока ему не назвали имя. До этого он отвечает самоподписанным сертификатом — браузер ругается, а в консоли в строке Source стоит self-signed.

  1. Создайте A-запись s2.<домен> на публичный адрес хоста координатора и дождитесь, пока она разойдётся: dig +short s2.<домен> должен вернуть этот адрес.

  2. Назовите имя — одним из двух способов, они равнозначны.

    Переменной окружения (так проще для установки, которую собирают из compose-файла): в deploy/docker-compose.coordinator.yml задайте ST_TLS_DOMAIN=s2.<домен> и, если хотите получать письма об истечении, ST_TLS_EMAIL=<адрес>. Перезапустите координатор — выпуск начнётся при старте.

    В админке: Settings → TLS / Certificate → карточка Let's Encrypt (auto) → поле Domain = s2.<домен>, поле Contact email — при желании → кнопка Enable Let's Encrypt.

  3. Если у установки несколько имён (white-label), добавьте их в Tenant domains в той же карточке. Сертификат на каждое выпускается при первом обращении — но только после шага 2: сам по себе этот список ничего не выпускает, он лишь разрешает имена.

  4. Проверьте снаружи, а не с самого хоста:

curl -fsS https://s2.<домен>/healthz
curl -fsS https://s2.<домен>/.well-known/simpletwo.json
Про почту

Адрес — необязательный. Let's Encrypt выпускает сертификат и без контакта; разница в том, что при неудачном продлении предупредить будет некого: письмо «сертификат истекает через 20 дней» уходит именно на него. Указывайте общий ящик команды эксплуатации, а не личный.

Когда выпуск не удаётся

Хост должен быть доступен из интернета на 80 и 443 в момент выпуска — так работают оба способа проверки владения именем. Если DNS-запись ещё не разошлась, выпуск не удастся; это не ошибка настройки, повторите позже кнопкой Renew (Let's Encrypt).

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) postgres2) messaging3) calendar (опционально)переустановить postgres один раз4) redis5) sfu узел A6) sfu узел B7) turn

Почему postgres переустанавливается: правила доступа к базе сужаются до /32 адресов хостов messaging и calendar, а записать их нельзя, пока этих хостов не существует. Одна переустановка закрывает оба.

Одно правило, которое молча ломает звонки

Приватный адрес нельзя отдавать клиентам. Приватный адрес хоста идёт в поле private address; адрес, по которому клиенты обращаются к SFU, — в node IP. Перепутаете — звонок установится, медиа не пойдёт, соединение отвалится по таймауту, и ни в одном журнале ничего не будет.

Ещё две вещи, которые продукт не даст сделать неправильно:

  • Второй узел sfu без redis установить нельзя — установка откажется. Два узла без шины ведут каждый свою таблицу комнат: двое «в одной встрече» на разных узлах не видят друг друга, и никто об этом не сообщает.
  • calendar можно не ставить. Пока хоста календаря нет, клиенты прячут экраны календаря, а не показывают кнопки, которые не работают.

Чат: имя и сертификат

После установки messaging откройте карточку Messaging TLS: укажите hostname chat.s2.<домен>Save configRedeployIssue. Здесь сертификат получает сама служба — по TLS-ALPN-01 на :443, без порта 80 и без участия координатора, — а адрес https://chat.s2.<домен> попадает в дискавери автоматически. Календарь устроен так же. Для проверки схемы есть флаг staging — тестовый сертификат Let's Encrypt, который не расходует лимиты.

Звонки: адрес для клиентов

Укажите wss://calls.s2.<домен> в Settings → Calls → Client URL — из этого адреса берётся имя сертификата. Сертификат для sfu заказывает координатор и присылает его на хост вместе с желаемым состоянием; то же самое для turn и для SIP-транка mediation (там TLS живёт на 5061).

Что для этого нужно на хосте роли:

  • имя из Client URL указывает на этот хост (A-запись);
  • порт 80 свободен и доступен из интернета: агент поднимает на нём ответ на проверку владения именем. Занят другим сервером — установка роли скажет об этом прямо;
  • ничего больше: контактный адрес для удостоверяющего центра берётся общий на установку (тот, что задан координатору), и он необязателен.

Состояние видно в таблице Installed servers: строка сертификата у каждого хоста говорит issuing (заказ идёт), ошибку проверки или срок действия. Готовый сертификат можно и принести свой — Import в той же строке; принесённый координатор не перевыпускает.

Если у роли уже есть TLS-фронт

Свой nginx или балансировщик перед sfu по-прежнему допустим. Тогда имя в Client URL принадлежит фронту, а не хосту роли, и сертификат ведёт он — координатор в этом случае имя хоста роли не знает и ничего не заказывает.

Проверка после каждой роли

curl -fsS https://chat.s2.<домен>/healthz     # messaging
curl -fsS https://s2.<домен>/healthz # координатор видит состояние ролей

В админке у каждой установленной роли есть строка состояния: координатор сам опрашивает /healthz ролей. Роль в статусе active, но с красным состоянием — это установленный сервис, который не работает; смотрите Host logs.

6. Шаг 4. Каталог и вход

  1. Settings → Single sign-on (OIDC) — подключите корпоративный провайдер (OIDC/SAML/ADFS).
  2. Groups / roles → profile — сопоставьте группы каталога с ролями и атрибутами профиля.
  3. Roles — проверьте, кто администратор, кто может вести встречи, кто видит телефонию.

Отдельная статья про ADFS понадобится в двух случаях: если пользователи входят по адресу, отличному от UPN, и если руководитель в AD задан как DN, а не как почта.

7. Шаг 5. Клиенты и приёмка контура

Клиент называется SimpleTwo Connect и один на все платформы: iOS, Android, macOS, Windows и веб. Пользователь вводит рабочую почту — приложение само находит контур по домену.

Приёмка — не «сервисы запущены», а сценарий целиком:

  1. Вход сотрудника по корпоративной учётной записи.
  2. Сообщение в чате доходит до второго устройства и до второго сотрудника.
  3. Звонок один на один: слышно в обе стороны.
  4. Встреча: внешний участник заходит по ссылке из браузера, ждёт в лобби, его впускают.
  5. Туннель: клиент подключается к VPN-узлу и открывает внутренний ресурс.
  6. Все /healthz отвечают.
warning

Зелёная джоба выката и запущенный контейнер — не признак работающего сервиса. Выкат не закончен, пока каждый сервис не ответил на /healthz, а сценарий выше не прошёл целиком.

8. Опциональные роли

РольКогда нужнаЧто важно знать
gatewayнужен доступ в корпоративную сеть или выход в нужном GEOсначала создайте GEO, затем установите узел. Ключи Reality генерируются на узле, наружу уходит только публичный. DNS не требуется
recorderнужна запись конференцийединственная роль, которая работает контейнером: она пишет комнату, управляя headless Chrome. Ограничена процессором: 4 vCPU / 4 ГБ на одну одновременную запись плюс диск. Наружу не слушает ничего — берёт задания из шины и пишет в объектное хранилище. Требует redis и настроенное хранилище
mediationнужна телефония и дозвонredis — жёсткая зависимость, причём тот же, что у пула SFU: без него сервис не стартует. Каждый звонок транскодируется, поэтому хост считается по одновременным звонкам (≈0,05 ядра на звонок), а не по участникам. Входящие вызовы не балансируются: второй хост — это решение про прокси, а не про масштаб, и установка второго будет отклонена
s3нужны вложения не на одном диске, несколько реплик messaging или записи встречобъектное хранилище (versitygw, S3-совместимое). Наружу не слушает: 9000 открыт только хостам messaging и recorder. Ключи и бакеты заводит координатор, руками вводить нечего. На хосте обязателен межсетевой экран — ufw или firewalld на Linux, pf на FreeBSD (агент сам пишет якорь и включает pf); без него развёртывание падает, а не оставляет хранилище открытым всей приватной сети. Альтернатива — внешнее хранилище в Settings → External stores
supportнужен бот поддержкиставится в DMZ рядом с координатором. Входящие — только подписанные вебхуки с хоста messaging на :8087; наружу и к клиентам не доступен. Держит свой ключ провайдера модели и свою базу знаний; токен GitLab нужен с правом read_api на проект продукта

9. Обновление и бэкап

Обновление координатора — это новый тег образа:

cd /opt/simpletwo
sed -i 's|:v[0-9.]*$|:v0.9.215|' .env # только тег; путь к образу остаётся тем же
docker compose pull && docker compose up -d
curl -fsS http://127.0.0.1/healthz

Откат — тот же файл с предыдущим тегом: прошлые образы остаются в реестре. Если на хосте координатора установлен GitLab Runner, эти же шаги выполняет джоба deploy на теге v*.

Обновление ролей — из админки: Redeploy на нужном хосте. Новый бинарник роли уже внутри нового образа координатора, поэтому порядок такой: сначала обновить координатор, потом переустановить роли.

Бэкап — три вещи, и первая важнее остальных:

  1. том coordinator-data (секреты, база плоскости управления, сертификаты);
  2. базы postgres (чат и календарь) — обычным pg_dump по расписанию;
  3. вложения на хосте messaging, пока они лежат на его диске.

10. Если что-то не работает

Где смотреть: в админке — Coordinator logs, Host logs, Provisioning log, Audit log; на хосте координатора — docker compose logs coordinator; на хостах ролей — journalctl -u <юнит роли> -f.

СимптомВероятная причина
Установка роли останавливается сразуSSH: не тот пользователь, ключ без доступа, нет curl на хосте. Проверьте Test SSH
Роль active, состояние красноесервис установлен, но не поднялся: смотрите Host logs и journalctl на хосте
В браузере самоподписанный сертификат, хотя имя добавленоимя внесено только в Tenant domains, а Let's Encrypt не включён: в карточке TLS Source = self-signed. Шаг 2 выше — назвать имя в ST_TLS_DOMAIN или кнопкой Enable Let's Encrypt
У sfu, turn или mediation сертификат в состоянии issuing и не меняетсяна хосте роли занят или закрыт снаружи порт 80 — агент не может ответить на проверку владения именем
В строке сертификата ошибка и «next automatic attempt at …»после неудачи следующий автоматический заказ ждёт паузу (5 → 15 → 30 → 60 минут): так удостоверяющий центр не заблокирует имя за пять неудачных проверок в час. Исправили причину — нажмите Issue, ручной заказ паузу не ждёт
Сертификат не выпускается, в логе invalidContactуказан адрес, домен которого удостоверяющий центр не принимает (например, ops@example.test). Почта необязательна: сотрите её и повторите, либо укажите адрес в настоящем домене
Сертификат не выпускаетсяхост недоступен из интернета на 80/443 или DNS-запись ещё не разошлась
Клиент не находит контур по почтенет s2.<домен> или нет файла /.well-known/simpletwo.json
Чат работает, звонки — нетне задан Client URL в Settings → Calls, либо у SFU нет своего TLS-фронта
Звонок соединяется, звука нетв node IP попал приватный адрес (см. §5) или заблокированы порты turn
Двое в одной встрече не видят друг другадва узла sfu без redis
Клиент не подключается к VPN-узлуне совпали shortId, публичный ключ или SNI; либо узел не отправляет heartbeat и признан устаревшим
Экраны календаря отсутствуют в клиентероль calendar не установлена — это ожидаемое поведение, а не ошибка
«база по адресу … недоступна с этого хоста»роль calendar или messaging отказалась разворачиваться, пока не видит Postgres: разверните роль postgres и дайте хосту маршрут до неё
«не тот SSH-ключ хоста», хост переустановленвы пересоздали хост под тем же именем: Серверы и развертывание → меню у хоста → Принять новый ключ хоста

Роль отказывается разворачиваться из-за базы

calendar и messaging перед настройкой набирают адрес базы из своего DSN. Если ответа нет, роль отказывается с сообщением, где названы адрес и причина, — и это сделано намеренно.

Оба сервиса завершаются, когда не могут открыть хранилище, поэтому раньше такой хост получал установленный юнит, вечный цикл перезапусков systemd — и зелёный статус success в консоли. Развёртывание сообщало об успехе ровно там, где ничего не работало.

Что делать: развернуть роль postgres раньше зависимых ролей (порядок в §5 — не рекомендация), проверить, что хост роли имеет маршрут до неё, и повторить. Если база живёт вне контура, адрес в параметрах роли должен быть доступен именно с хоста роли, а не с координатора.

Хост переустановлен, а координатор его не пускает

Координатор запоминает SSH-ключ каждого хоста при первом подключении и потом сверяет его — это то, что отличает ваш хост от чужого, отвечающего по тому же адресу. Если вы пересоздали хост, ключ у него новый, и подключение будет отклонено с сообщением, где названы оба отпечатка: доверенный и предъявленный.

Сверьте предъявленный с тем, что говорит сам хост:

ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub   # на переустановленном хосте

Совпало — нажмите Принять новый ключ хоста в меню этого хоста, и следующее подключение запомнит новый ключ. Не совпало — не принимайте: по этому адресу отвечает не ваш хост.