История одного проекта или как я 7 лет создавал атс на базе asterisk и php

Введение

Я приведу простой пример, подразумевая, что вы выполнили настройку asterisk по моей статье или схожим образом. Классическая конфигурация для среднестатистического офиса. Представим, что у вас 2 таких офиса в разных городах. Пусть этими городами будут Москва (условное имя сервера moscow) и Санкт-Петербург (условное имя сервера piter) Вы хотите звонить на внутренние номера этих офисов напрямую, как-будто они обслуживаются вашим сервером. Допустим, на сервере moscow у вас номера начинаются на 100 и 200, а в piter на 300 и 400. Я считаю, что между серверами у вас настроен vpn канал и они видят друг друга без проблем.

Если у вас номера пересекаются, например, и там и там начинаются на 100, то задача немного усложняется, но не сильно. Просто придется добавить какую-нибудь еще цифру к набору, а в диалплане ее отсекать. Но я не буду рассматривать этот вариант. Если вы одна организация, то логично сделать такую нумерацию, чтобы она не пересекалась. Если это не так, то лучше ее переделать, чем городить костыли.

Наша задача будет разбита на 2 этапа:

  1. Готовим пиры и регистрации для связи двух серверов между собой.
  2. Настраиваем dialplan, чтобы распределять звонки по серверам.

Может возникнуть вопрос: «А зачем вообще соединять 2 сервера, если можно сделать один сервер asterisk и подключить к нему абонентов обоих офисов?». Причины могут быть разными. Мне видятся несколько, например:

  • В каком-то филиале нестабильный интернет. Офис не хочет терять возможность внутренних звонков при проблемах с интернетом. А если сервер с астериском будет находиться не у них, то даже между собой не смогут созвониться.
  • Разные люди администрируют сервера. В рамках одного сервера сложнее настроить разделение доступа. Более того, я даже не знаю, как это реализовать. А в случае с разными серверами никаких проблем. Главное не трогать часть диалплана, которая отвечает за звонки друг к другу, а дальше можно конфигурировать как душе угодно.
  • Нужна раздельная статистика и запись звонков. Конечно, можно все это реализовать в рамках одного сервера, но нужно будет либо покупать какое-то коммерческое решение, либо переделывать бесплатное. Я не знаю простого, бесплатного и удобного средства, которое позволит это реализовать в рамках одного сервера. А так ставишь любой cdr viewer и ограничиваешь доступ к web панели любым удобным способом.

Третья версия

Идеей для решения проблемы стало не генерить Asterisk диалплан из php, а использовать FastAGI и все правила обработки писать уже на самом php. FastAGI позволяет Asterisk, для обработки звонка, подключиться к сокету. Получать оттуда команды и отправлять результаты. Таким образом логика диалплана находится уже за границами Asterisk и может быть написана на любом языке, в моём случае на php.

Тут было много проб и ошибок. Главной проблемой являлось, что у меня уже было много классов/файлов. На создание объектов, инициализацию и взаимную регистрацию между ними уходило около 1,5 секунд, и эта задержка на каждый звонок не то, что можно игнорировать.

Инициализация должна была быть только 1 раз и поэтому поиски решения начались с написания сервиса на php с использованием Pthreads. Спустя неделю экспериментов этот вариант был отложен из-за тонкостей работы этого расширения. От асинхронного программирования на php после месяца тестов тоже пришлось отказаться, нужно было что-то простое, знакомое любому новичку php, да и многие расширения для php синхронные.

Решением стал свой многопоточный сервис на ‘си’, который компилировался с PHPLIB. Он подгружает все php файлы АТС, ждёт, когда все модули инициализируются, добавят коллбэк друг к другу и когда всё готово – кэширует. При запросе по FastAGI создаётся поток, в нём воспроизводится копия из кэша всех классов и данных и запрос передается в php функцию.

При таком решении время от отправки звонка в наш сервис до первой команды Asterisk сократилось с 1,5с до 0,05с и это время слабо зависит от размера проекта.

В итоге, время на разработку диалплана сократилось существенно, и я могу это оценить поскольку мне пришлось переписать веcь диалплан всех модулей на php. Во-первых, в php уже должны быть написаны методы для получения объекта из базы, они были нужны для отображения в веб-интерфейсе, а во-вторых, и это главное – наконец-то появилась возможность удобной работы со строками с числами с массивами с базой данных плюс множество расширений php.

Для обработки диалплана в классе модуля нужно реализовать функцию dialplanDynamicCall и аргумент pbxCallRequest будет содержать объект для взаимодействия с Asterisk.

В дополнении появилась возможность отлаживать диалплан (в php есть xdebug и для нашего сервиса оно работает), можно двигаться по шагам просматривая значения переменных.

Запуск asterisk

По-умолчанию, asterisk установлен от root и будет запускаться от него же. Я предлагаю для этого создать отдельного пользователя и запускать астериск от него. Для этого создаем пользователя и добавляем его в некоторые группы.

# adduser --system --group --home /var/lib/asterisk --no-create-home --gecos "Asterisk" asterisk
# usermod -a -G dialout,audio asterisk

Настраиваем Asterisk на запуск под этим пользователем. Для этого добавляем в конфиг /etc/default/asterisk параметры:

AST_USER="asterisk"
AST_GROUP="asterisk"

Назначаем новому пользователю права на директории астериска.

# chown -R asterisk: /var/{lib,log,run,spool}/asterisk /usr/lib/asterisk /etc/asterisk

Пробуем запустить asterisk:

# systemctl start asterisk

Если нет сообщений об ошибке, скорее всего все в порядке. Проверяем статус службы.

# systemctl status asterisk

Asterisk запустился, но у меня ошибка:

radcli: rc_read_config: rc_read_config: can't open /etc/radiusclient-ng/radiusclient.conf: No such file or directory

Не может найти необходимый конфиг. Я проверил глазами, директории /etc/radiusclient-ng действительно нет, но есть /etc/radcli, где находится указанный в ошибке конфиг radiusclient.conf. Подозреваю, что это он и есть. Посмотрел, где в конфигах астериска используется этот путь. Оказалось, что в /etc/asterisk/cdr.conf и /etc/asterisk/cel.conf. Я там раскомментировал параметры, где указан ошибочный путь и указал правильный.

В /etc/asterisk/cdr.conf раскомментировал и отредактировал строки:

radiuscfg => /etc/radcli/radiusclient.conf

То же самое в /etc/asterisk/cel.conf:

radiuscfg => /etc/radcli/radiusclient.conf

После этого перезапустил астериск и проверил, все было в порядке.

# systemctl restart asterisk
# systemctl status asterisk

Добавим астериск в автозагрузку:

# systemctl enable asterisk

Запускаем консоль астериск и убеждаемся, что он работает:

# rasterisk

Все в порядке, сервер телефонии asterisk установлен и готов к работе. Можно заниматься настройкой.

Идея и ключевые требования

А началось всё банально с любви к Asterisk (framework для построения коммуникационный приложений), автоматизации телефонии и установок FreePBX (веб интерфейс для Asterisk). Если потребности компании были без особенностей и укладывались в возможности FreePBX – всё супер. Вся установка проходила за сутки, компания получала настроенную АТС, удобный интерфейс и краткое обучение плюс сопровождение по желанию.

Но самые интересные задачи были нестандартными и тогда было не так сказочно. Asterisk может многое, но чтобы сохранить в рабочем виде веб-интерфейс, приходилось потратить в разы больше времени. Так небольшая мелочь могла занять времени гораздо больше, чем установка всей остальной АТС. И дело не в том, что писать веб интерфейс долго, а скорее дело в особенностях архитектуры FreePBX. Подходы и методы архитектуры FreePBX закладывалась во времена php4, а в тот момент уже был php5.6 на котором всё можно было сделать проще и удобнее.

Последней каплей стали графические диалпланы в виде схемы. Когда попытался подобное построить для FreePBX, понял, что придётся существенно его переписать и проще уже построить что-нибудь новое.

Ключевыми требованиями стали:

простая настройка, интуитивно доступная даже начинающему администратору. Тем самым компаниям не требуется обслуживание АТС на нашей стороне,
легкая доработка, чтобы задачи решались за адекватное время,
удобство интеграции с АТС. У FreePBX не было API для изменения настроек, т.е

нельзя, например, создавать группы или голосовые меню из стороннего приложения, только API самого Asterisk,
opensource – для программистов это крайне важно для доработок под клиента.

Идея более быстрой разработки была в том, чтобы весь функционал состоял из модулей в виде объектов. Все объекты должны были иметь общий родительский класс, а значит названия всех основных функций уже известны и значит уже есть реализации по умолчанию. Объекты позволят резко сократить количество аргументов в виде ассоциативных массивов со строковыми ключами, узнать которые в FreePBX можно было, исследовав всю функцию и вложенные функции. В случае объектов банальное автодополнение покажет все свойства, да и целом во много раз упростит жизнь. Плюс наследование и переопределение уже закрывает множество проблем с доработками.

Следующее, что замедляло время доработки и чего стоило избежать — это дублирование. Если есть модуль ответственный за дозвон до сотрудника, то все остальные модули, которым нужно отправить звонок сотруднику, должны использовать именно его, а не создавать свои собственные копии. Так, если нужно что-нибудь поменять, то менять придется только в одном месте и поиск «как это работает» проводить одного места, а не осуществлять поиск по всему проекту.

Настройка dialplan для работы с 2-мя серверами

Теперь нам нужно в диалплане на каждом из серверов указать, куда звонить по разным номерам. На сервере moscow укажем, что звонить по маскам 300 и 400 нужно в питер. Добавляем в extentions.conf правило перед основным правилом звонка на внутренние номера с маской _XXX.

exten => _XX,1,Dial(SIP/piter/${EXTEN},15,Tt)

И добавим контекст для приема входящих звонков с сервера piter

exten => _XXX,1,Dial(SIP/${EXTEN},15,Tt)

Делаем то же самое на сервере piter.

exten => _XX,1,Dial(SIP/moscow/${EXTEN},15,Tt)

Не забываем поменять маску. И добавляем контекст приема звонков с moscow.

exten => _XXX,1,Dial(SIP/${EXTEN},15,Tt)

Вот и все. Мы связали между собой 2 астериск сервера. Можно звонить друг другу, используя внутренние номера. Не забудьте перезагрузить план набора.

> dialplan reload

Можно проверять звонки. Не обязательно делать в точности, как я показал. У вас может быть по-другому организован диалплан. Можно в контекст для входящих заинклюдить ваш существующий контекст для внутренних звонков, например так.

include => office

Если у вас настроена запись звонков так же, как я рассказал в своей статье про настройку астериска, которую привел в начале, то не забудьте добавить запись по обоим направлениям. Примерно так для сервера moscow на исходящие.

exten => _XX,1,Macro(recording,${CALLERID(num)},${EXTEN})
exten => _XX,n,Dial(SIP/piter/${EXTEN},15,Tt)

И вот так на входящие:

exten => _XXX,1,Macro(recording,${CALLERID(num)},${EXTEN})
exten => _XXX,n,Dial(SIP/${EXTEN},15,Tt)

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

Если есть необходимость, то можно расширить эту конфигурацию и настроить звонки в Питер из Москвы через сервер piter, если там более выгодный тариф для локальных звонков. Для этого нужно добавить маски питерских номеров в dialplan на сервере moscow, а на сервере piter в контекст входящих звонков с moscow настроить набор через свой питерский транк.

Другие материалы по asterisk:

Онлайн курс Основы сетевых технологий

Теоретический курс с самыми базовыми знаниями по сетям. Курс подходит и начинающим, и людям с опытом. Практикующим системным администраторам курс поможет упорядочить знания и восполнить пробелы. А те, кто только входит в профессию, получат на курсе базовые знания и навыки, без воды и избыточной теории. После обучения вы сможете ответить на вопросы:

  • На каком уровне модели OSI могут работать коммутаторы;
  • Как лучше организовать работу сети организации с множеством отделов;
  • Для чего и как использовать технологию VLAN;
  • Для чего сервера стоит выносить в DMZ;
  • Как организовать объединение филиалов и удаленный доступ сотрудников по vpn;
  • и многое другое.

Уже знаете ответы на вопросы выше? Или сомневаетесь? Попробуйте пройти тест по основам сетевых технологий. Всего 53 вопроса, в один цикл теста входит 10 вопросов в случайном порядке. Поэтому тест можно проходить несколько раз без потери интереса. Бесплатно и без регистрации. Все подробности на странице .

  • Установка и настройка астериск с нуля
  • Мониторинг asterisk в zabbix
  • Соединение двух серверов астериск
  • Анализ SIP трафика
  • Замена +7 на 8 и наоборот
  • Ограничение на звонки для группы номеров

Details:

AstLinux provides a communication and networking platform including:

  • Asterisk 13 or 16:
    SIP, DAHDI —
    Voice PBX
  • Asterisk Operator Panel:
    FOP2 —
    optional Add-On Package
  • Prosody 0.10:
    XMPP —
    Presence and Messaging
  • Linux: Kernel 3.16, Busybox base with iproute2, e2fsprogs and util-linux
  • VPN Support:
    WireGuard
    OpenVPN
    IPSec VPN
  • Scripting Languages: bash, php, lua and perl
  • Web Server: Linux-Lighttpd-SQLite3-PHP
  • Monitoring:
    Zabbix
    SNMP
    UPS Equipment
  • IPv4 / IPv6 Router and
    Stateful Filtering Firewall
  • DHCP, DNS, TFTP
    DNS-TLS Proxy
    NTP and FTP servers
  • SMTP email forwarding for notifications
  • Fossil —
    software configuration management system for local configuration files
  • LDAP —
    server for distributing directory information
  • ODBC —
    database abstraction layer support for SQLite3
  • RUNNIX bootloader supporting firmware version management and low level diagnostics
  • Web interface for administration

Supported 64-bit, x86_64 boards and appliances include:

  • Qotom
    Intel Celeron J1900 fanless appliance:
    Q190G4N-S07
  • Qotom
    Intel Core i3-6100U fanless appliance:
    Q530G6
  • Protectli
    Celeron J3160 fanless appliance:
    FW4B
  • PC Engines
    AMD APU boards:
    apu2
  • Jetway
    Intel Celeron N3160 fanless appliance:
    JBC430U941 / HBJC430U941
  • Jetway
    Intel Quad Core Celeron board:
    NF9HG-2930
  • Lanner
    Intel Atom C2358 fanless appliance:
    FW-7525B
  • HP Enterprise
    AMD X3421 ProLiant:
    MicroServer Gen10
  • Generic 64-bit, x86_64 PC Hardware with Legacy (non-UEFI) BIOS

Supported Virtual Machine guest environments include:

  • VMware
    x86_64 Virtualization:
    VMware Fusion
    VMware vSphere ESXi
  • Proxmox
    KVM x86_64 Virtualization:
    Proxmox VE
  • Linode
    Hosted KVM x86_64 Virtualization:
    Linode KVM
  • Vultr
    Hosted KVM x86_64 Virtualization:
    Vultr KVM
  • Other x86_64 Virtualization:
    Hyper-V
    VirtualBox
    XenServer

The following telephony hardware cards are supported via DAHDI:

  • Digium
  • DAHDI compatible hardware (without extra drivers) like HFC cards

Computing resources are provided courtesy TechNosis, Inc.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *