Развёртывание 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/tcp | DMZ для корпоративного выхода | VPN-узлы (VLESS+Reality), по одному на GEO |
recorder | нет | да | запись конференций (опционально) |
mediation | да | да | телефония SIP/PSTN (опционально) |
support | нет | DMZ рядом с координатором | демон бота поддержки (опционально) |
2. Что нужно заранее
Хосты и размеры на старт
Одна таблица на весь контур: что ставим, сколько ресурсов, в какой сети и чем ограничено. Числа — на старт для организации до ~150 человек (размер S в профиле нагрузки); для организаций побольше смотрите «Сколько узлов под звонки», там масштабируется только медиа.
| Роль | vCPU / RAM / диск | Сеть | Где стоит | Чем ограничена |
|---|---|---|---|---|
| координатор | 2 / 4 / 20 ГБ | 100 Мбит/с, публичный IPv4 | публичная | ничем; держит SQLite и сертификаты в томе |
messaging | 2 / 4 / 100 ГБ SSD | 100 Мбит/с, публичный IPv4 | публичная | диском, пока вложения лежат на нём: с ролью s3 или внешним хранилищем хватает 20 ГБ |
s3 | 2 / 4 / диск по медиа | 1 Гбит/с внутри контура | приватная | диском — см. ниже; роль опциональная, не нужна при внешнем хранилище |
sfu, каждый | 4 / 8 / 20 ГБ | 1 Гбит/с, публичный IPv4 | публичная + нога в приватную (redis) | каналом — см. ниже |
turn | 2 / 2 / 20 ГБ | 1 Гбит/с, публи чный IPv4 | публичная | каналом: через него идут ~15% участников, в обе стороны |
gateway, каждый | 1 / 1 / 20 ГБ | 1 Гбит/с, публичный IPv4 | публичная | каналом |
calendar | 2 / 4 / 20 ГБ | 100 Мбит/с, публичный IPv4 | публичная | опросом, а не людьми: подписанный Outlook и CalDAV-клиент приходят по своему расписанию |
postgres | 2 / 4 / 40 ГБ SSD | 1 Гбит/с внутри контура | приватная | диском; не нужен, если подключён внешний кластер |
redis | 1 / 1 / 10 ГБ | 1 Гбит/с внутри контура | приватная | ничем; держит маршрутизацию комнат, не данные. Не нужен, если подключён внешний |
support | 2 / 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.
-
Создайте
A-записьs2.<д омен>на публичный адрес хоста координатора и дождитесь, пока она разойдётся:dig +short s2.<домен>должен вернуть этот адрес. -
Назовите имя — одним из двух способов, они равнозначны.
Переменной окружения (так проще для установки, которую собирают из 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. -
Если у установки несколько имён (white-label), добавьте их в Tenant domains в той же карточке. Сертификат на каждое выпускается при первом обращении — но только после шага 2: сам по себе этот список ничего не выпускает, он лишь разрешает имена.
-
Проверьте снаружи, а не с самого хоста:
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) 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, без порта 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 в той же строке; принесённый координатор не перевыпускает.
Свой nginx или балансировщик перед sfu по-прежнему допустим. Тогда имя в Client URL
принадлежит фронту, а не хосту роли, и сертификат ведёт он — координатор в этом сл учае имя
хоста роли не знает и ничего не заказывает.
Проверка после каждой роли
curl -fsS https://chat.s2.<домен>/healthz # messaging
curl -fsS https://s2.<домен>/healthz # координатор видит состояние ролей
В админке у каждой установленной роли есть строка состояния: координатор сам опрашивает
/healthz ролей. Роль в статусе active, но с красным состоянием — это установленный
сервис, который не работает; смотрите Host logs.
6. Шаг 4. Каталог и вход
- Settings → Single sign-on (OIDC) — подключите корпоративный провайдер (OIDC/SAML/ADFS).
- Groups / roles → profile — сопоставьте группы каталога с ролями и атрибутами профиля.
- Roles — проверьте, кто администратор, кто может вести встречи, кто видит телефонию.
Отдельная статья про ADFS понадобится в двух случаях: если пользователи входят по адресу, отличному от UPN, и если руководитель в AD задан как DN, а не как почта.
7. Шаг 5. Клиенты и приёмка контура
Клиент называется SimpleTwo Connect и один на все платформы: iOS, Android, macOS, Windows и веб. Пользователь вводит рабочую почту — приложение само находит контур по домену.
Приёмка — не «сервисы запущены», а сценарий целиком:
- Вход сотрудника по корпоративной учётной записи.
- Сообщение в чате доходит до второго устройства и до второго сотрудника.
- Звонок один на один: слышно в обе стороны.
- Встреча: внешний участник заходит по ссылке из браузера, ждёт в лобби, его впускают.
- Туннель: клиент подключается к VPN-узлу и открывает внутренний ресурс.
- Все
/healthzотвечают.
Зелёная джоба выката и запущенный контейнер — не признак работающего сервиса. Выкат не
закончен, пока каждый сервис не ответил на /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 на нужном хосте. Новый бинарник роли уже внутри нового образа координатора, поэтому порядок такой: сначала обновить координатор, потом переустановить роли.
Бэкап — три вещи, и первая важнее остальных:
- том
coordinator-data(секреты, база плоскости управления, сертификаты); - базы
postgres(чат и календарь) — обычнымpg_dumpпо расписанию; - вложения на хосте
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 # на переустановленном хосте
Совпало — нажмите Принять новый ключ хоста в меню ⋯ этого хоста, и следующее
подключение запомнит новый ключ. Не совпало — не принимайте: по этому адресу отвечает не ваш
хост.