Подключение нового агента — CRM + Asterisk + Bitrix24

01 · Обзор

Эта инструкция описывает подключение нового Asterisk-сервера к уже работающему CRM-серверу. Все действия выполняются на стороне Asterisk и Bitrix24.

ℹ️
Установка и настройка CRM-сервера не входит в эту инструкцию — он уже поднят и обслуживается отдельным администратором. Всё, что от тебя требуется — подготовить Asterisk-агента и передать файл регистрации администратору CRM-сервера.

Схема взаимодействия

Bitrix24 webhook CRM Server HTTPS + enc CRM Agent AMI Asterisk

Кто что делает

КомпонентЗадачаКто отвечает
Asterisk Принимает звонки, пишет разговоры через MixMonitor, транслирует AMI-события Ты (настраиваешь)
CRM Agent Слушает AMI, формирует сегменты, шлёт на сервер по HTTPS Ты (устанавливаешь)
Bitrix24 Показывает карточки звонков, хранит записи Ты (настраиваешь webhook)
CRM Server Хранит сегменты, ведёт очередь Bitrix24, выдаёт UI Администратор CRM-сервера

Что должно быть готово заранее

  • Администратор CRM-сервера передал тебе agent.py и crm_url
  • Известны crm_url (HTTP endpoint), ADMIN_TOKEN (для тестов), схема ключей
  • Есть SSH-доступ к Asterisk и root/sudo на нём
  • Есть права администратора в Bitrix24

02 · Требования

КомпонентВерсия / примечание
Asterisk18+ (с включённым AEL)
ОСDebian 11/12, Ubuntu 20.04/22.04
Python3.9+
Пакетыsox, lame, python3-venv
Свободные порты8080 (HTTP API агента), 5038 (AMI, локально)

Установить зависимости

apt-get update
apt-get install -y python3 python3-pip python3-venv sox lame curl jq openssl

03 · Настройка AMI в Asterisk

Агент подключается к AMI локально (127.0.0.1:5038). Создаём отдельного пользователя с ограничением по IP.

1Сгенерировать пароль
openssl rand -base64 32 | tr -d '=+/'

Скопируй результат — он пойдёт и в manager.conf, и в agent.conf.

2Добавить пользователя в manager.conf

Открой /etc/asterisk/manager.conf и убедись, что есть блок:

[general]
enabled = yes
port = 5038
bindaddr = 127.0.0.1
displayconnects = no

[crm_agent]
secret = СЮДА_ВСТАВЬ_СГЕНЕРИРОВАННЫЙ_ПАРОЛЬ
deny = 0.0.0.0/0.0.0.0
permit = 127.0.0.1/255.255.255.255
read = all
write = all
3Применить и проверить
asterisk -rx "manager reload"
asterisk -rx "manager show user crm_agent"

Ожидаемый вывод:

Username: crm_agent
Secret: 
ACL: yes
Read Permissions: all
Write Permissions: all

04 · Настройка dialplan (AEL)

⚠️
Ключевой момент: агент берёт extension из события DialBegin.DestExten. Если в Dial() ты пишешь PJSIP/74855${EXTEN}@trunk, то DestExten останется коротким (${EXTEN}), а файл записи будет называться с полным номером — они не совпадут.

4.1 · Включить AEL

В /etc/asterisk/extensions.conf должна быть строка:

#include extensions.ael

4.2 · Добавить контекст record-call

В конец /etc/asterisk/extensions.ael добавь:

context record-call {
    s => {
        Set(source_uniqueid=${ARG3});
        Set(fname=${UNIQUEID}-${ARG1}-${ARG2});
        Set(DB(record/${source_uniqueid})=${fname});
        Set(linkedid=${CHANNEL(linkedid)});
        Set(CDR(userfield)=${fname});

        Set(rfile=${DIR_RECORDS}${fname}-r.wav);
        Set(tfile=${DIR_RECORDS}${fname}-t.wav);

        MixMonitor(,r(${rfile})t(${tfile}));

        Return();
    }
}
АргументЧто передавать
${ARG1}Номер звонящего (${CALLERID(num)})
${ARG2}Номер вызываемого (${EXTEN} после подстановки префикса)
${ARG3}${UNIQUEID} исходного канала

4.3 · Правило про ${EXTEN} перед Dial

Для каждого исходящего паттерна, где ты добавляешь префикс, вставь Set(EXTEN=...) до Dial():

_XXXXXX => {
    if ("${bxCallID}" = "") {
        Set(json=${CURL(${SURL}call&USER_PHONE_INNER=${CALLERID(num)}&PHONE_NUMBER=74855${EXTEN}&CALL_TYPE=1)});
        Set(bxCallID=${SHELL(echo '${json}' | jq -j '.CALL_ID')});
    };

    Set(num=${CALLERID(num)});
    Set(EXTEN=74855${EXTEN});       // <── ЭТА СТРОКА

    if (${LEN(${DNUM})}) {
        Dial(PJSIP/${EXTEN}@731778,,b(record-call,s,1(${CALLERID(num)},${EXTEN},${UNIQUEID}))TU(ddial^${DNUM}));
    } else {
        Dial(PJSIP/${EXTEN}@731778,,b(record-call,s,1(${CALLERID(num)},${EXTEN},${UNIQUEID}))T);
    };

    HangUp();
};

Шаблон для остальных паттернов:

ПаттернБыло в DialСтало
_XXXXXX74855${EXTEN}Set(EXTEN=74855${EXTEN}) + Dial(PJSIP/${EXTEN}@...)
_8XXXXXXXXXX7${EXTEN:1}Set(EXTEN=7${EXTEN:1}) + Dial(PJSIP/${EXTEN}@...)
_9XXXXXX${EXTEN:1}Set(EXTEN=${EXTEN:1}) + Dial(PJSIP/${EXTEN}@...)
_+7XXXXXXXXXX${EXTEN:1}Set(EXTEN=${EXTEN:1}) + Dial(PJSIP/${EXTEN}@...)

4.4 · Отключить старый h-handler

Если в контексте internal есть h => { ... CURL(${SURL}call_finish ...) } — закомментируй тело. Иначе Bitrix получит дубли hide_card и call_finish.

h => {
    // Старая интеграция отключена — всем управляет CRM Agent.
    // Set(fname=${DB(record/${UNIQUEID})});
    // Set(dummy=${DB_DELETE(record/${UNIQUEID})});
    // Set(json=${CURL(${SURL}hide_card&CALL_ID=${bxCallID}&USER_PHONE_INNER=${num})});
    // Set(json=${CURL(${SURL}call_finish&CALL_ID=${bxCallID}&USER_PHONE_INNER=${num}&DURATION=${ANSWEREDTIME}&RECORD_FILE=${fname}.mp3&STATUS_CODE=${DIALSTATUS})});
};

4.5 · Права на каталог записей

chown asterisk:asterisk /var/spool/asterisk/recording
chmod 755 /var/spool/asterisk/recording
ls -la /var/spool/asterisk/recording/ | head

4.6 · Перезагрузить dialplan

asterisk -rx "dialplan reload"
asterisk -rx "dialplan show record-call"

05 · Установка CRM Agent

1Создать пользователя и каталоги
useradd -r -s /usr/sbin/nologin -d /var/lib/crm-agent crm-agent 2>/dev/null || true

mkdir -p /opt/crm-agent
mkdir -p /var/lib/crm-agent/keys
mkdir -p /var/lib/crm-agent/registration
chown -R crm-agent:crm-agent /var/lib/crm-agent
chmod 700 /var/lib/crm-agent/keys
2Скопировать agent.py

Положи файл agent.py (полученный от администратора CRM-сервера) в /opt/crm-agent/agent.py:

cp agent.py /opt/crm-agent/agent.py
chmod 755 /opt/crm-agent/agent.py
chown crm-agent:crm-agent /opt/crm-agent/agent.py
3Создать venv и поставить зависимости
python3 -m venv /opt/crm-agent/venv
/opt/crm-agent/venv/bin/pip install --upgrade pip
/opt/crm-agent/venv/bin/pip install requests cryptography

06 · Systemd unit

Создай /etc/systemd/system/crm-agent.service:

[Unit]
Description=Asterisk CRM Agent
After=network.target asterisk.service
Wants=asterisk.service

[Service]
Type=simple
User=crm-agent
Group=crm-agent
WorkingDirectory=/opt/crm-agent
ExecStart=/opt/crm-agent/venv/bin/python3 /opt/crm-agent/agent.py
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=crm-agent

# Доступ к записям Asterisk (если записывает asterisk:asterisk)
SupplementaryGroups=asterisk

[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable crm-agent
ℹ️
Пока не запускаем — сначала настроим agent.conf и пройдём регистрацию.

07 · Конфигурация agent.conf

mkdir -p /etc/crm-agent
cat > /etc/crm-agent/agent.conf <<'EOF'
[agent]
# ============================================================
# AMI подключение к Asterisk
# ============================================================
ami_host=127.0.0.1
ami_port=5038
ami_user=crm_agent
ami_secret=CHANGE_ME_STRONG_PASSWORD

# ============================================================
# CRM сервер
# ============================================================
crm_url=http://192.168.150.115:18080/api/v1/asterisk/events
agent_name=aster.corp.example.ru

# ============================================================
# Записи разговоров
# ============================================================
recording_dir=/var/spool/asterisk/recording
recording_url=https://aster.corp.example.ru:56300

sox_path=/usr/bin/sox
lame_path=/usr/bin/lame

# ============================================================
# HTTP API для Click-to-Call
# ============================================================
api_host=0.0.0.0
api_port=8080

# ============================================================
# Определение направления
# ============================================================
outgoing_contexts = phones
internal_extension_regex = ^\d{2,4}$

# ============================================================
# Очередь отправки (SQLite)
# ============================================================
queue_max_attempts=10
queue_retry_delay=30
queue_db=/var/lib/crm-agent/queue.db

# ============================================================
# Каталоги ключей и регистрации
# ============================================================
key_dir=/var/lib/crm-agent/keys
registration_dir=/var/lib/crm-agent/registration

# ============================================================
# Таймауты
# ============================================================
request_timeout=10
reconnect_delay=5

# ============================================================
# Click-to-Call
# ============================================================
internal_channel_type = Local
internal_context = internal

click_to_call_context = phones
click_to_call_timeout = 30
click_to_call_priority = 1
EOF

chmod 600 /etc/crm-agent/agent.conf

Что заменить

КлючЗначение
ami_secretПароль из шага 03
crm_urlURL CRM-сервера (выдаёт администратор CRM)
agent_nameFQDN Asterisk-сервера
recording_urlБазовый URL для доступа к MP3 (должен открываться из Bitrix)
outgoing_contextsКонтекст исходящих звонков (обычно phones)

08 · Регистрация агента

Агент и CRM-сервер аутентифицируют друг друга через ключи Ed25519/X25519. При первом запуске агент сгенерирует ключи и создаст файл регистрации. Этот файл нужно отредактировать и передать администратору CRM-сервера.

ℹ️
У тебя нет доступа к CRM-серверу. Файл регистрации ты передаёшь администратору CRM-сервера (email, тикет, мессенджер — как принято у вас). Дальше он размещает файл у себя и перечитывает конфиги. Ты только ждёшь подтверждения.
1Первый запуск агента — генерация ключей
systemctl start crm-agent
sleep 3
journalctl -u crm-agent -n 50 --no-pager

В логах должно быть:

Starting CRM Agent
Agent: aster.corp.example.ru
==============================================================
AGENT NOT REGISTERED ON CRM SERVER
Registration file created: /var/lib/crm-agent/registration/aster.corp.example.ru.json
Copy to crm-server/config/ and reload server.
==============================================================

Останови агент — пока не запускай повторно, пока не закончишь с регистрацией:

systemctl stop crm-agent
2Отредактировать файл регистрации у себя

Открой файл:

nano /var/lib/crm-agent/registration/aster.corp.example.ru.json

Изначально он выглядит так:

{
  "agent": "aster.corp.example.ru",
  "ed25519": "...",
  "x25519": "...",
  "allowed_ip": [],
  "missed_call_mode": "all",
  "default_extension": "",
  "agent_api_url": "http://:8080",
  "bitrix24": {"enabled": false, "url": "", "webhook": ""}
}

Заполни поля под свой сервер:

{
  "agent": "aster.corp.example.ru",
  "ed25519": "...",
  "x25519": "...",
  "allowed_ip": ["192.168.150.103"],
  "missed_call_mode": "all",
  "default_extension": "777",
  "agent_api_url": "http://192.168.150.103:8080",
  "bitrix24": {
    "enabled": true,
    "url": "https://your-portal.bitrix24.ru",
    "webhook": "https://your-portal.bitrix24.ru/rest/1/xxxxxxxxxxxxxxxx/"
  }
}
ПолеЧто писать
allowed_ipIP твоего Asterisk (откуда пойдут события). Пустой список = принимать с любого IP
missed_call_modeall — все звонки; success_only — только отвеченные
default_extensionЗаглушка, если внутреннего номера нет в Bitrix. Уточни у администратора CRM
agent_api_urlURL HTTP API агента (этот же Asterisk, порт 8080). Сюда Bitrix будет стучать для click-to-call
bitrix24.enabledtrue для включения интеграции
bitrix24.urlURL портала Bitrix24
bitrix24.webhookВходящий webhook (см. раздел 09)
⚠️
Поля ed25519 и x25519 не трогай — это твои публичные ключи, они сгенерированы автоматически.
3Передать файл администратору CRM-сервера

Файл лежит по пути:

/var/lib/crm-agent/registration/aster.corp.example.ru.json

Передай его администратору CRM-сервера любым принятым у вас способом:

  • Приложи к задаче / тикету
  • Отправь по email с темой «Регистрация Asterisk-агента aster.corp.example.ru»
  • Передай через защищённый канал / мессенджер

Вместе с файлом сообщи администратору:

  • FQDN агента: aster.corp.example.ru
  • IP Asterisk-сервера: 192.168.150.103
  • Контактное лицо и телефон ответственного с вашей стороны
4Дождаться подтверждения от администратора CRM

Администратор CRM-сервера:

  1. Положит файл в /opt/crm-integration/config/ на CRM-сервере
  2. Выполнит команду перечитать конфиги у себя

В ответ ты должен получить подтверждение: «Агент aster.corp.example.ru зарегистрирован, agents: 1».

ℹ️
Пока не получишь подтверждение — не запускай агент. Если запустишь раньше, в логах будет AGENT NOT REGISTERED ON CRM SERVER и агент завершится с кодом 0.
5Запустить агент и проверить логи
systemctl restart crm-agent
journalctl -u crm-agent -f

Успешные логи:

Starting CRM Agent
Agent: aster.corp.example.ru
Internal channel: LOCAL
Internal extension regex: ^\d{2,4}$
Agent registration confirmed
Connecting AMI 127.0.0.1:5038
HTTP API listening on 0.0.0.0:8080
AMI authenticated

Если видишь AMI authenticated — агент запущен и работает.

Если что-то поменялось после регистрации

Например, ты поменял agent_api_url, allowed_ip или параметры Bitrix24 в JSON. После изменения:

  1. Отредактируй JSON заново
  2. Снова передай его администратору CRM-сервера
  3. Дождись подтверждения
  4. Перезапусти агент

Если менял только agent.conf (пароль AMI, recording_url и т.п.) — достаточно:

systemctl restart crm-agent

09 · Настройка Bitrix24

9.1 · Создать входящий webhook

  1. Bitrix24 → РазработчикамДругоеВходящий вебхук
  2. Права: crm, telephony, user, crm.timeline
  3. Скопируй URL вида: https://portal.bitrix24.ru/rest/1/xxxxxxxxxxxxxxxx/
  4. Вставь его в bitrix24.webhook в JSON-конфиге (шаг 08.2). Если JSON уже передан администратору — правь и передавай заново

9.2 · Настроить ONEXTERNALCALLSTART

  1. Настройки → Телефония → включить «Внешние звонки»
  2. Разработчикам → Другое → Исходящий вебхук
  3. URL: адрес CRM-сервера, выданный администратором. Например: https://crm.example.com/webhook/bitrix24
  4. Событие: ONEXTERNALCALLSTART
ℹ️
URL исходящего вебхука уточни у администратора CRM-сервера — он знает публичный адрес вашего сервера.

9.3 · Прописать внутренние номера

У каждого пользователя Bitrix должно быть заполнено поле UF_PHONE_INNER = внутренний номер (например 772). Если у тебя тестовый портал и номеров нет — работает default_extension.

10 · Проверка работы

10.1 · Внутренний звонок

Набери с софтфона внутренний номер (например 772).

В логах агента:

DIAL BEGIN: dest=1789541722.6666 ext=772 phone=704 dir=outgoing ctc=-

У администратора CRM-сервера в логах должны быть строки call_segment_start, bitrix_register, externalCall.show. Проверить можно и в UI CRM-сервера:

https://crm.example.com/ui → раздел «Сегменты»

Убедись, что видишь свежий сегмент с uid, совпадающим с логом агента.

10.2 · Исходящий через транк

Набери короткий номер с префиксом-паттерном (например 211472). Проверь, что файл записи создан с полным номером:

ls -la /var/spool/asterisk/recording/ | grep 1789

Пример корректного имени:

1789542167.6681-710-74855211472-r.wav
1789542167.6681-710-74855211472-t.wav

В логах агента:

DIAL BEGIN: dest=1789542167.6681 ext=74855211472 phone=710 dir=outgoing
HANGUP: starting conversion for 1789542167.6681 (ANSWER, duration=15s)

10.3 · Входящий

DIAL BEGIN: dest=... ext=772 phone=79001234567 dir=incoming

10.4 · UI

Открой https://crm.example.com/ui (адрес и токен — у администратора CRM-сервера) и убедись, что все сегменты с твоего Asterisk отображаются.

11 · Диагностика

AMI auth failed

asterisk -rx "manager show user crm_agent"
grep -E "^(secret|permit)" /etc/asterisk/manager.conf
  • Проверь ami_user, ami_secret в agent.conf
  • permit=127.0.0.1/255.255.255.255 — агент должен ходить с 127.0.0.1

AGENT NOT REGISTERED ON CRM SERVER

Агент запущен, но администратор CRM ещё не разместил файл регистрации у себя.

  • Проверь, что ты передал JSON администратору
  • Проверь, что он подтвердил agents: 1
  • После подтверждения: systemctl restart crm-agent

WAVs not found after 60s for

Файл записи создан, но с другим именем:

ls -la /var/spool/asterisk/recording/ | grep 

Если имя вида ...-74855XXXXXX-r.wav — значит не сработало правило из раздела 04.3 (нет Set(EXTEN=...) перед Dial()).

Если файла вообще нет:

asterisk -rx "dialplan show record-call"
asterisk -rx "core show channels"

USER_PHONE_INNER not found, retry with 777

Это норма для тестового портала. Если шум мешает — уточни у администратора CRM, можно ли очистить default_extension, но тогда регистрация таких звонков упадёт.

Bitrix показывает пустую карточку

Проверь, что номера пользователей Bitrix совпадают с внутренними номерами Asterisk (UF_PHONE_INNER). Если номера нет — работает default_extension. Точную информацию о том, дошёл ли звонок до Bitrix, можно получить у администратора CRM-сервера.

Полный рестарт пайплайна

# Asterisk
asterisk -rx "dialplan reload"
asterisk -rx "manager reload"

# Агент
systemctl restart crm-agent
journalctl -u crm-agent -n 30 --no-pager

Проверить, что агент жив

systemctl status crm-agent
curl -s http://127.0.0.1:8080/queue | jq

12 · Чек-лист

Отмечай по мере выполнения — прогресс сохраняется в браузере.

  • В manager.conf создан crm_agent с permit=127.0.0.1
  • В extensions.ael добавлен контекст record-call
  • Во всех Dial() с префиксом стоит Set(EXTEN=...) перед вызовом
  • Старый h-handler закомментирован
  • Права на /var/spool/asterisk/recording выставлены
  • agent.py установлен в /opt/crm-agent/
  • venv создан и зависимости установлены
  • crm-agent.service создан, enable сделан
  • /etc/crm-agent/agent.conf заполнен
  • Агент сгенерировал registration JSON
  • JSON отредактирован (allowed_ip, default_extension, agent_api_url, bitrix24)
  • JSON передан администратору CRM-сервера
  • Получено подтверждение: «Агент зарегистрирован, agents: 1»
  • Агент запущен, в логах AMI authenticated
  • Bitrix webhook ONEXTERNALCALLSTART настроен
  • Тестовый внутренний звонок — карточка и запись есть
  • Тестовый исходящий через транк — запись с полным номером
  • UI открывается и отображает сегменты

Прогресс: 0 / 18