01 · Обзор
Эта инструкция описывает подключение нового Asterisk-сервера к уже работающему CRM-серверу. Все действия выполняются на стороне Asterisk и Bitrix24.
Схема взаимодействия
Кто что делает
| Компонент | Задача | Кто отвечает |
|---|---|---|
| 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 · Требования
| Компонент | Версия / примечание |
|---|---|
| Asterisk | 18+ (с включённым AEL) |
| ОС | Debian 11/12, Ubuntu 20.04/22.04 |
| Python | 3.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 openssl03 · Настройка AMI в Asterisk
Агент подключается к AMI локально (127.0.0.1:5038). Создаём отдельного пользователя с ограничением по IP.
openssl rand -base64 32 | tr -d '=+/'Скопируй результат — он пойдёт и в manager.conf, и в agent.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 = allasterisk -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.ael4.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 | Стало |
|---|---|---|
_XXXXXX | 74855${EXTEN} | Set(EXTEN=74855${EXTEN}) + Dial(PJSIP/${EXTEN}@...) |
_8XXXXXXXXXX | 7${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/ | head4.6 · Перезагрузить dialplan
asterisk -rx "dialplan reload"
asterisk -rx "dialplan show record-call"05 · Установка CRM Agent
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Положи файл 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.pypython3 -m venv /opt/crm-agent/venv
/opt/crm-agent/venv/bin/pip install --upgrade pip
/opt/crm-agent/venv/bin/pip install requests cryptography06 · 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.targetsystemctl daemon-reload
systemctl enable crm-agentagent.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_url | URL CRM-сервера (выдаёт администратор CRM) |
agent_name | FQDN Asterisk-сервера |
recording_url | Базовый URL для доступа к MP3 (должен открываться из Bitrix) |
outgoing_contexts | Контекст исходящих звонков (обычно phones) |
08 · Регистрация агента
Агент и CRM-сервер аутентифицируют друг друга через ключи Ed25519/X25519. При первом запуске агент сгенерирует ключи и создаст файл регистрации. Этот файл нужно отредактировать и передать администратору CRM-сервера.
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Открой файл:
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_ip | IP твоего Asterisk (откуда пойдут события). Пустой список = принимать с любого IP |
missed_call_mode | all — все звонки; success_only — только отвеченные |
default_extension | Заглушка, если внутреннего номера нет в Bitrix. Уточни у администратора CRM |
agent_api_url | URL HTTP API агента (этот же Asterisk, порт 8080). Сюда Bitrix будет стучать для click-to-call |
bitrix24.enabled | true для включения интеграции |
bitrix24.url | URL портала Bitrix24 |
bitrix24.webhook | Входящий webhook (см. раздел 09) |
ed25519 и x25519 не трогай — это твои публичные ключи, они сгенерированы автоматически.Файл лежит по пути:
/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 - Контактное лицо и телефон ответственного с вашей стороны
Администратор CRM-сервера:
- Положит файл в
/opt/crm-integration/config/на CRM-сервере - Выполнит команду перечитать конфиги у себя
В ответ ты должен получить подтверждение: «Агент aster.corp.example.ru зарегистрирован, agents: 1».
AGENT NOT REGISTERED ON CRM SERVER и агент завершится с кодом 0.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. После изменения:
- Отредактируй JSON заново
- Снова передай его администратору CRM-сервера
- Дождись подтверждения
- Перезапусти агент
Если менял только agent.conf (пароль AMI, recording_url и т.п.) — достаточно:
systemctl restart crm-agent09 · Настройка Bitrix24
9.1 · Создать входящий webhook
- Bitrix24 → Разработчикам → Другое → Входящий вебхук
- Права:
crm,telephony,user,crm.timeline - Скопируй URL вида:
https://portal.bitrix24.ru/rest/1/xxxxxxxxxxxxxxxx/ - Вставь его в
bitrix24.webhookв JSON-конфиге (шаг 08.2). Если JSON уже передан администратору — правь и передавай заново
9.2 · Настроить ONEXTERNALCALLSTART
- Настройки → Телефония → включить «Внешние звонки»
- Разработчикам → Другое → Исходящий вебхук
- URL: адрес CRM-сервера, выданный администратором. Например:
https://crm.example.com/webhook/bitrix24 - Событие:
ONEXTERNALCALLSTART
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=incoming10.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 | jq12 · Чек-лист
Отмечай по мере выполнения — прогресс сохраняется в браузере.
- В
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