Реестр образов registry.omniflow.ru
| версия | дата | состояние | что в ней |
|---|---|---|---|
0.76.0 | 2026-10-25 | текущая | Valkey — обязательная часть платформы: при его недоступности ядро больше не ведёт звонки по копии в памяти, а… подробнее |
Предыдущие версии, на которые можно откатиться, и полные заметки по каждой — в истории версий.
Обновляясь, прочитайте в истории разделы «Важно при обновлении» у всех версий новее вашей: ручной шаг перешагнутой версии не отменяется тем, что вы её не ставили. Разделы своей и более старых версий не нужны.
Нужен сервер с Linux, публичным статическим IP и установленным Docker
(Engine 24+, плагин compose v2.20+; верхней границы нет —
свежие Engine 29 / compose v5 подходят). Ставьте Docker из официального
репозитория docker.com (пошагово — docs.docker.com/engine/install): в дистрибутивных пакетах часто нет
плагина compose, без которого установка не пройдёт.
| минимум | рекомендуется | |
|---|---|---|
| CPU | 2 ядра | 8 ядер |
| RAM | 4 ГБ без сценариев, 6 ГБ со сценариями | 16 ГБ |
| Диск | 30 ГБ SSD | 200 ГБ SSD — записи разговоров растут |
Минимум — для небольшой организации. Первый запуск скачивает образы — меньше 2 ГБ по сети. Место под записи считайте так: минута разговора двух участников — около 2 МБ (по дорожке WAV на участника), то есть тысяча минут в месяц — около 2 ГБ.
corenode требуют
уровня инструкций x86-64-v2 (SSE4.2, POPCNT и соседи) — это нужно для
миниатюр вложений в чате, но не для работы платформы.
Любой серверный процессор с 2009 года его имеет, но
гипервизоры по умолчанию отдают гостю урезанную модель
(kvm64, qemu64, Common KVM processor), где эти
флаги замаскированы.
./omniflow-ctl logs core-node) видно
Unsupported CPU: Prebuilt binaries for Linux x64 require v2 microarchitecture.
lscpu | grep -o -E 'sse4_2|popcnt' | sort -u
Пусто — смените модель CPU виртуальной машины на host (проброс реального
процессора) и перезапустите её. В proxmox это Processors → Type → host, в
libvirt/virt-manager — Copy host CPU configuration. Менять тип на работающей
машине нельзя — нужен полный останов и старт, не reboot.
Таблица — не жёсткий вентиль: установщик по RAM/CPU не откажет, а doctor из ресурсов проверяет место на диске и сумму потолков памяти против памяти машины. Но ниже 4 ГБ RAM набор узлов (~15 контейнеров) упирается в OOM при запуске — установщик подгоняет потолки памяти под сервер и скажет прямо, если набор не помещается; на 4 ГБ помещается только набор без сценариев. На диске меньше 30 ГБ места под записи разговоров почти не остаётся. Проверка ресурсов сервера:
nproc # ядра
free -g # RAM, столбец available
df -h / # свободное место
docker version # Engine 24+
docker compose version # v2.20+
# Разрешаем своему пользователю работать с Docker без sudo.
# Все команды — и установщик, и docker compose — обращаются к сокету
# /var/run/docker.sock, а он принадлежит группе docker. Не состоя в ней,
# вы получите "permission denied" на первой же команде.
sudo usermod -aG docker $USER
# Теперь выйдите из системы и зайдите заново (для ssh — переподключитесь).
# Состав групп берётся в момент входа, текущая сессия о новой группе не знает:
# без повторного входа команды продолжат падать, хотя настроено уже верно.
id # в списке групп должна появиться docker
sudo, но не вперемешку. У root свой домашний каталог,
поэтому логин в реестр, сделанный под вашим пользователем, для
sudo docker просто не существует — оттуда берётся
no basic auth credentials. Вдобавок файлы инсталляции окажутся
с разными владельцами, и обычные команды перестанут в них писать.
Рекомендуемый вариант — обычный пользователь в группе docker.
Порты, которые должны быть свободны на сервере и открыты извне:
5060/udp,tcp | SIP — телефоны и софтфоны |
5080/udp,tcp | SIP — транки провайдеров |
5061/tcp | SIP через TLS |
8443/tcp | SIP через WebSocket (звонки из браузера) |
30000-30500/udp | голосовой трафик |
80/tcp, 443/tcp | веб-интерфейс |
# Ничего не должно слушать эти порты до запуска платформы:
ss -lntup | grep -E ':(5060|5080|5061|8443|80|443) '
«Открыты извне» обеспечивает firewall провайдера: у облачных VM это security group в консоли облака, а не локальный ufw (на облачных образах он обычно выключен). Команда выше проверяет лишь локальную занятость портов; внешнюю доступность — проверкой снаружи.
Реестр закрытый: логин и пароль выдаются вместе с поставкой. Без них не скачается ни установщик, ни сама платформа. Шаг делается один раз — Docker запоминает учётные данные в домашнем каталоге пользователя.
docker login registry.omniflow.ru
# успех выглядит как: Login Succeeded
# без терминала (ssh host '…', CI): echo "$PASS" | docker login registry.omniflow.ru -u "$USER" --password-stdin
# Проверяем, что доступ рабочий (маленьким образом (~8 МБ)):
docker pull registry.omniflow.ru/omniflow/alpine:3.20
Если проверка не прошла:
unauthorized — неверный пароль или логин;
no basic auth credentials — команда идёт под другим пользователем,
чем docker login (обычно из-за sudo);
denied — учётная запись есть, но прав на этот образ у неё нет;
no such host или таймаут — сервер не резолвит имя реестра либо
закрыт исходящий доступ на 443.
# Каталог инсталляции: сюда лягут конфиги, база, записи разговоров.
# Он и есть вся система — бэкап делается с него.
# В корне файловой системы папку создаёт только root, поэтому mkdir под sudo,
# а сразу за ним chown: каталог должен принадлежать ВАМ ещё до установщика.
# Он определяет владельца по каталогу и передаёт ему всё, что создал; каталог
# root'а означает .env и конфиги, которые вы не сможете править без sudo.
sudo mkdir -p /app/omniflow
sudo chown "$USER":"$USER" /app/omniflow
cd /app/omniflow
# CTL_HOST_DIR — чтобы установщик показывал ваши пути, а не свои внутренние:
# внутрь контейнера этот каталог виден как /install.
# ════════════════════ команда установки ════════════════════
docker run --rm -it --pull always -v "$PWD:/install" -e CTL_HOST_DIR="$PWD" \
registry.omniflow.ru/omniflow/ctl:0.76.0 install
# ═══════════════════════════════════════════════════════════
# Установщик раскладывает установку папками-юнитами (infra/ core/ sbc-1/ cu-1/
# rtpe-1/ web/ …) и кладёт рядом скрипт ./omniflow-ctl — дальше все команды через него.
# В конце вывода он печатает пароль администратора панели — сохраните его.
# Он же лежит в .env строкой ADMIN_PASSWORD.
# Три строки, которые нужно проверить руками. По EXTERNAL_IP телефоны находят
# сервер, по PUBLIC_DOMAIN — браузер, SIP_DOMAIN — SIP-домен (тот же). Остальное установщик заполнил сам.
nano .env
# EXTERNAL_IP=203.0.113.10 # публичный IP сервера
# PUBLIC_DOMAIN=pbx.example.com # домен панели; нет домена — пишите тот же IP
# SIP_DOMAIN=pbx.example.com # SIP-домен; тот же, что PUBLIC_DOMAIN (нет домена — тот же IP)
# За 1:1 NAT (облачная VM: внутренний адрес 10.x, публичный — снаружи) в EXTERNAL_IP
# пишите ПУБЛИЧНЫЙ адрес — этого достаточно: rtpengine анонсирует его в SDP, Kamailio —
# в Via/Contact, внутренний адрес платформе указывать не нужно. Публичный IP с сервера:
# curl -s https://api.ipify.org
# Запуск. Юниты поднимаются по порядку с ожиданием готовности каждого.
# Первый раз скачиваются образы и создаётся схема базы — несколько минут.
# Оборвался на скачивании (502, timeout) — повторите ту же команду:
# докачает недостающее, уже скачанное не тронет.
./omniflow-ctl up
В терминале установщик задаёт четыре вопроса. Первый — состав
компонентов: меню с номерами, где цифра переключает пункт, а
Enter идёт дальше (буквы вроде y он не
понимает — переспросит). Второй — показывает будущую структуру каталогов и
спрашивает «Создать эту структуру? [Y/n]»: Enter означает
«да», и только после этого на диске что-то появляется. Третий — внешний
IP сервера: он его определяет сам и предлагает в скобках, Enter
соглашается. Четвёртый — домен панели, и там же по умолчанию
предложен этот самый адрес: домен нужен не всякой установке, по
IP одинаково работают и панель, и телефония, и запись. Домен обязателен только
для настоящего сертификата (letsencrypt/custom) и для
чатов через внешних провайдеров — им нужен достижимый адрес вебхука.
Повторный запуск ничего не затирает, а недостающее дополняет.
Если сессия оборвалась на вопросе, контейнер установщика остаётся ждать
ввода: docker ps покажет его с образом omniflow/ctl,
снимите его docker stop <имя> и запустите команду заново.
Без терминала (скрипт, ssh host 'команда',
CI) — добавьте флаг --yes после install и уберите
-t из docker run, иначе Docker откажет с
the input device is not a TTY. Вопросов установщик задавать не
будет: из компонентов поставит панель, внешний IP определит сам и его же
подставит в PUBLIC_DOMAIN — установка без домена получается сразу
рабочей. Домен, если он есть, вписывается в .env потом.
Сценарии обработки обращений (стратегии) установщик не ставит:
они включаются на организацию, отдельной командой и позже —
./omniflow-ctl unit add strategies --tenant <тенант>, затем
./omniflow-ctl up strategies-<тенант>.
Сертификат по умолчанию самоподписанный (TLS_MODE=self-signed
в .env): браузер предупредит о нём при любом значении
PUBLIC_DOMAIN — и с доменом, и с IP. Настоящий сертификат —
режимы letsencrypt / custom, для них нужен домен;
описаны в INSTALL.md.
Установка — набор папок-юнитов, каждая свой compose-проект. Управляет всеми
сразу ./omniflow-ctl, а не docker compose в корне:
корневого compose-файла нет, и docker compose up -d в корне ответит,
что его не нашёл. С одним юнитом можно работать и обычным docker compose
из его папки: cd cu-1 && docker compose ps.
./omniflow-ctl up # поднять всё по порядку, дождаться готовности
./omniflow-ctl up cu-1 # поднять один юнит (или несколько через пробел)
./omniflow-ctl ps # одна таблица по всем юнитам: состояние, health, аптайм
./omniflow-ctl logs core-node # логи сервиса
./omniflow-ctl logs infra migrator # логи сервиса юнита — например, накат миграций
./omniflow-ctl restart sbc-1 # перезапустить юнит
./omniflow-ctl down # остановить всё (спросит подтверждение; в скрипте — --yes)
# Одна команда проверяет всё и печатает OK/FAIL по каждому пункту:
# контейнеры, образы из реестра, схема базы, конфиг SIP-фронта, панель,
# вход администратора, здоровье сервисов.
./omniflow-ctl verify
После первого ./omniflow-ctl up дайте платформе 2–3 минуты подняться,
прежде чем запускать verify — узлы стартуют не мгновенно. Пункт
«здоровье сервисов» может показать 503 в первые минуты
после первого старта: платформа сама восстанавливает браузерный путь шины, и пункт
зеленеет. Ускорить — разовым
docker compose -f infra/docker-compose.yml restart nats, затем повторить
verify.
Ручные команды — если нужно разобраться, что именно не сошлось:
# Все сервисы Up (где есть healthcheck — healthy). Одноразовые migrator
# и shared-tls завершаются сами: для них норма — Exited (0).
./omniflow-ctl ps
# Подробная проверка: порты, место на диске, память, контейнеры, схема базы,
# блокировки источников (и не ваш ли адрес среди них).
./omniflow-ctl doctor
# Панель отвечает (-k из-за самоподписанного сертификата): ожидаем 200.
curl -k -o /dev/null -w '%{http_code}\n' https://<PUBLIC_DOMAIN>/
# Вход администратора без браузера: ожидаем 200 и {"token":"..."};
# 401 — пароль не тот (берите из вывода установщика или ADMIN_PASSWORD в .env).
curl -k -s -w '\n%{http_code}\n' -H 'content-type: application/json' \
-d '{"username":"admin","password":"<пароль>"}' \
https://<PUBLIC_DOMAIN>/api/v1/auth/login
Если всё это сошлось, платформа установлена: дальше — вход в панель
браузером под тем же admin и телефония по следующему разделу.
Работающий стек ещё никому не звонит: в системе нет ни одного телефона.
В панели заведите SIP-точки — по одной на каждый аппарат или софтфон,
подключите их к внешнему IP сервера (порт 5060) и позвоните с
одной точки на другую: это разом проверяет весь тракт — SIP-фронт,
медиа-движок, оркестрацию и запись. Пошагово —
от установки до первого звонка; всё остальное —
в INSTALL.md, он лежит рядом с инсталляцией.
Без браузера — то же самое из консоли. Сначала организация (тенант), её код
потом станет SIP-доменом телефонов:
./omniflow-ctl tenant create romashka --name "Ромашка". Затем точки:
./omniflow-ctl sipuser add 101 --tenant romashka и
./omniflow-ctl sipuser add 102 --tenant romashka — команда печатает всё,
что нужно вбить в софтфон; входящий номер на точку —
./omniflow-ctl route add --did <номер> --to sipuser:101; транк
провайдера — ./omniflow-ctl trunk add …. Полный список команд и
флагов — ./omniflow-ctl help, машинный каталог для скриптов —
./omniflow-ctl help --json.
Версия платформы — одна строка в .env. Какие версии опубликованы —
таблица на этой странице или ./omniflow-ctl versions.
# 0. дамп базы — миграции необратимы, откат версии образа схему не откатит
docker compose -f infra/docker-compose.yml exec -T postgres pg_dump -U postgres omniflow > backup-$(date +%F).sql
# 1. сменить версию в .env. Без номера команда покажет опубликованные версии
# и предложит самую свежую; в скрипте без терминала нужен --yes, иначе
# она откажет, ничего не изменив
./omniflow-ctl upgrade 0.76.0
# 2. обновить файлы установки до новой версии и проверить инсталляцию.
# Установщик запустится уже новым образом и принесёт compose юнитов по
# шаблонам версии, INSTALL.md, .env.example и самого себя
./omniflow-ctl doctor
# 3. применить: юниты пересоздаются по порядку, образы новой версии скачиваются сами
./omniflow-ctl up
# 4. проверка — в том числе что все образы пришли из реестра
./omniflow-ctl verify
upgrade в 0.67.0 устарела. Команда
советует docker compose pull и docker compose up -d — это
шаги прежней раскладки. В раскладке юнитов выполняйте шаги 2–3 из блока выше:
./omniflow-ctl doctor, затем ./omniflow-ctl up.
upgrade платформы его не меняет, а up пересоздаёт наборы
на тех же версиях. Есть ли новее — ./omniflow-ctl strategies list --updates,
обновить одну — ./omniflow-ctl strategies upgrade <стратегия> [версия].*.dist —
сравните diff и перенесите нужное..env пересобирается по эталону новой версии: значения
сохраняются, ваши комментарии — нет. Копию прежнего файла установщик кладёт рядом
(.env.bak-<время>).OMNIFLOW_VERSION=latest — тег не меняется, и образы сами не
скачаются: перед шагом 3 выполните
for f in */docker-compose.yml; do docker compose -f "$f" pull; done..env есть
SBC_UNIT_IDS или транки и SIP-точки хранил сам SIP-фронт) — сначала
Приложение Б в INSTALL.md: там разовый ./omniflow-ctl sbc bootstrap --all.Первые секунд десять после up в логах нормальны строки уровня
error — узлы находят друг друга не мгновенно: медиа-узел сообщает о разрыве
с медиа-движком, SBC-узел — о пустом наборе медиа-прокси. Они снимаются сами за
несколько секунд и остаются в логе как след. Тревогу поднимать стоит, если такая строка
повторяется спустя минуту после подъёма.
Если в корне установки лежит docker-compose.yml, а папки
infra/ нет, — это прежняя раскладка (установки до 0.67.0). Она продолжает
работать, ./omniflow-ctl понимает обе. Обновление в ней — прежними шагами:
дамп docker compose exec -T postgres pg_dump …, ./omniflow-ctl upgrade,
./omniflow-ctl doctor, docker compose pull && docker compose up -d;
остальные команды — Приложение Г в INSTALL.md. Перевести её в папки-юниты —
две команды, переезд останавливает всё, поэтому дождитесь нуля разговоров:
./omniflow-ctl layout plan # только показ: что куда уедет, размер, конфликты
./omniflow-ctl layout migrate # исполнение: с подтверждением, журналом и откатом (--rollback)
registry.omniflow.ru с закреплённым digest. Если у вас
прежняя раскладка с compose старых версий (дефолты на Docker Hub, который из России
отдаёт образы нестабильно), добавьте в .env те же копии из реестра:
IMAGE_ACME=registry.omniflow.ru/omniflow/acme.sh:3.1.3
IMAGE_ALPINE=registry.omniflow.ru/omniflow/alpine:3.20
IMAGE_NATS=registry.omniflow.ru/omniflow/nats:2.11-alpine
IMAGE_NGINX=registry.omniflow.ru/omniflow/nginx:1.27-alpine
IMAGE_POSTGRES=registry.omniflow.ru/omniflow/postgres:18-alpine
IMAGE_S3STORE=registry.omniflow.ru/omniflow/seaweedfs:4.47
IMAGE_VALKEY=registry.omniflow.ru/omniflow/valkey:8-alpine
Бэкап установки — это .env, дамп базы и папки юнитов, кроме
infra/data/postgres (его заменяет дамп) и */var/ (пересоздаётся само).
Без .env бэкап бесполезен: пароли базы и ключи подписи записаны только в нём.
# дамп базы и отдельно её роли — без ролей дамп не восстановится на чистом сервере
docker compose -f infra/docker-compose.yml exec -T postgres pg_dump -U postgres omniflow > backup-$(date +%F).sql
docker compose -f infra/docker-compose.yml exec -T postgres pg_dumpall -U postgres --roles-only > roles-$(date +%F).sql
# файлы — на остановленной установке (записи разговоров, конфиги, стратегии)
./omniflow-ctl down --yes
sudo tar -czf omniflow-files-$(date +%F).tar.gz \
--exclude='infra/data/postgres' --exclude='*/var' .env */
./omniflow-ctl up
Храните копию не на этом сервере. Восстановление идёт в строгом порядке — пустая база,
роли, дамп, затем ./omniflow-ctl up; порядок и что будет, если его нарушить, —
раздел «Резервное копирование и восстановление» в INSTALL.md.
./omniflow-ctl verify # коротко: установлено или нет
./omniflow-ctl doctor # подробно, с причинами и командами исправления
./omniflow-ctl logs <сервис> --tail 100
./omniflow-ctl ban list # не заблокирован ли ваш адрес защитой от подбора паролей
Частые проблемы и как их решать — отдельная страница.
acme.sh, alpine, asterisk, corenode, ctl, fail2ban, kamailio, nats, nginx, postgres, rtpe-agent, rtpengine, seaweedfs, skopeo, strategy-ai-reception, strategy-chat-queue, strategy-dial-by-code, strategy-echo, strategy-mibs-main, strategy-not-work, strategy-operator-status, strategy-pay-select, strategy-queue-operator, strategy-reminder-dialer, strategy-simple-main, strategy-speech-demo, strategy-tcardio-main, strategy-transcribe-batch, strategy-vq, syft, ui, valkey