
Всем привет! Меня зовут Илья Чубко, я технический архитектор К2Тех.
IP-телефония давно стала важной частью корпоративных коммуникаций. Она позволяет компаниям эффективно управлять голосовыми вызовами через интернет, а собственный SIP-клиент дает возможность глубже интегрировать телефонные функции в веб-приложения. Это улучшает взаимодействие с пользователями и повышает продуктивность.
В этой статье я расскажу, как создается прототип SIP-клиента — минимально жизнеспособный продукт (MVP), который позволит совершать голосовые вызовы прямо из браузера через SIP-подключение. Такое решение поможет компаниям встроить голосовую связь в свои веб-приложения без установки дополнительного программного обеспечения.
Ниже – пошаговая инструкция по созданию веб-SIP-клиента на Angular с использованием sip.js, его подключению к серверу Asterisk и настройке защищенного соединения через TLS с поддержкой WebRTC.
Для реализации проекта используются следующие технологии:
Angular — современный фреймворк для создания веб-приложений;
sip.js — популярная JavaScript-библиотека для работы с SIP-протоколом в браузере;
Asterisk — мощная IP-АТС с поддержкой VoIP;
CentOS 9 — серверная операционная система семейства RedHat для развертывания Asterisk;
TLS — защищенный протокол для шифрования SIP-соединений;
WebRTC — технология для передачи аудио и видео в реальном времени через браузер.
Установка и настройка Asterisk на CentOS 9
Для работы SIP-клиента необходимо настроить серверную часть на базе Asterisk — одной из самых популярных IP-АТС с открытым исходным кодом. Она позволяет управлять голосовыми вызовами, обрабатывать SIP-сообщения и поддерживает WebRTC.
В этом разделе разберем установку Asterisk на CentOS 9: подготовку системы, установку зависимостей, компиляцию и настройку конфигурационных файлов. После этого сервер будет готов принимать SIP-подключения и обрабатывать звонки.
Создадим пользователя, под которым будет работать Asterisk
sudo useradd -r -s /sbin/nologin asterisk sudo mkdir -p /home/asterisk sudo chown asterisk:asterisk /home/asterisk sudo usermod -d /home/asterisk asterisk
Устанавливаем инструменты для сборки
sudo dnf groupinstall "Development Tools" -y sudo dnf install epel-release wget git net-tools -y sudo dnf config-manager --set-enabled crb sudo dnf install libedit-devel libuuid-devel ncurses-devel libxml2-devel libsqlite3x-devel libicu-devel libsrtp libsrtp-devel openssl openssl-devel -y
Устанавливаем кодеки
sudo dnf install https://mirrors.rpmfusion.org/free/el/rpmfusion-free-release-9.noarch.rpm https://mirrors.rpmfusion.org/nonfree/el/rpmfusion-nonfree-release-9.noarch.rpm -y sudo dnf install ffmpeg ffmpeg-devel -y
Установка и настройка базы данных (MariaDB)
sudo dnf install mariadb-server mariadb -y sudo systemctl start mariadb && sudo systemctl enable mariadb sudo mysql_secure_installation
Установка PHP
sudo dnf install -y dnf-utils sudo dnf install -y https://rpms.remirepo.net/enterprise/remi-release-9.rpm sudo dnf module list php sudo dnf module enable php:8.2 sudo dnf install -y php php-cli php-common php-fpm php-pear php-mbstring php-xml php-json php-process php-mysqlnd chown asterisk:asterisk /etc/php-fpm.d/ -R chown asterisk:asterisk /var/run/php-fpm -R chown asterisk:asterisk /var/log/php-fpm/ -R sudo sed -i 's/^user = apache/user = asterisk/' /etc/php-fpm.d/www.conf sudo sed -i 's/^group = apache/group = asterisk/' /etc/php-fpm.d/www.conf sudo sed -i 's/^;listen.mode = 0660/listen.mode = 0660/' /etc/php-fpm.d/www.conf sudo sed -i 's/^listen.acl_users = apache,nginx/listen.acl_users = asterisk/' /etc/php-fpm.d/www.conf
Вручную добавить пользователя в сервис /usr/lib/systemd/system/php-fpm.service:
[Service] ... User=asterisk Group=asterisk ...
Перезапускаем службу:
sudo vi /etc/systemd/system/php-fpm.service systemctl daemon-reload sudo systemctl restart php-fpm
Установка Httpd
sudo dnf install httpd -y sudo sed -i 's/^User asterisk/User asterisk/' /etc/httpd/conf/httpd.conf sed -i 's/AllowOverride None/AllowOverride All/' /etc/httpd/conf/httpd.conf systemctl restart httpd && systemctl enable httpd sudo sed -i 's/^User apache/User asterisk/' /etc/httpd/conf/httpd.conf sudo sed -i 's/^Group apache/Group asterisk/' /etc/httpd/conf/httpd.conf
Установка NodeJs
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash source ~/.bashrc nvm install --lts curl -sL https://rpm.nodesource.com/setup_18.x | sudo bash - sudo dnf install -y nodejs-18.16.0
Установка Jansson
wget https://github.com/akheron/jansson/releases/download/v2.13.1/jansson-2.13.1.tar.gz tar -xzvf jansson-2.13.1.tar.gz cd jansson-2.13.1 sudo ./configure sudo make sudo make install
Установка Pjproject
cd /usr/src wget https://github.com/pjsip/pjproject/archive/refs/tags/2.11.tar.gz tar -xvf 2.11.tar.gz cd pjproject-2.11 ./configure make make install
Установка Asterisk
cd /usr/src/ sudo wget http://downloads.asterisk.org/pub/telephony/asterisk/asterisk-22-current.tar.gz sudo tar xvf asterisk-22-current.tar.gz cd asterisk-22.*/ sudo ./configure sudo make menuselect sudo make sudo make install sudo make samples sudo make config sudo chown -R asterisk:asterisk /var/run/asterisk && \ sudo chown -R asterisk:asterisk /var/lib/asterisk && \ sudo chown -R asterisk:asterisk /var/log/asterisk && \ sudo chown -R asterisk:asterisk /var/spool/asterisk sudo -u asterisk /usr/sbin/asterisk sudo chown -R asterisk:asterisk /etc/asterisk /var/{lib,log,spool}/asterisk /usr/lib/asterisk sudo mkdir -p /var/run/asterisk sudo chown -R asterisk:asterisk /var/run/asterisk sudo chmod -R 775 /var/run/asterisk
Если отсутствуют файл modules.conf, то создаем его командой и следующим содержанием:
vi /etc/asterisk/modules.conf [modules] load => chan_sip.so load => chan_pjsip.so load => pbx_config.so
Регистрация службы:
sudo vi /etc/systemd/system/asterisk.service
[Unit] Description=Asterisk PBX and telephony daemon After=network.target [Service] Type=simple User=asterisk Group=asterisk ExecStart=/usr/sbin/asterisk -f -C /etc/asterisk/asterisk.conf ExecStop=/usr/sbin/asterisk -rx 'core stop now' Restart=on-failure RestartSec=5s [Install] WantedBy=multi-user.target
sudo systemctl daemon-reload sudo systemctl start asterisk sudo systemctl enable asterisk
Установка FreePBX (опционально)
cd /usr/src/ sudo wget http://mirror.freepbx.org/modules/packages/freepbx/freepbx-17.0-latest.tgz sudo tar xvf freepbx-17.0-latest.tgz cd freepbx sudo ./start_asterisk start sudo ./install -n fwconsole ma list fwconsole ma install core fwconsole ma installall fwconsole ma upgradeall fwconsole restart sudo fwconsole chown sudo fwconsole reload sudo fwconsole ma refreshsignatures sudo chown -R asterisk:asterisk /var/www/html/admin/libraries/BMO/ sudo chmod -R 755 /var/www/html/admin/libraries/BMO/
В итоге мы получили готовый сервер Asterisk, все службы работают под пользователем asterisk.
Обеспечение безопасности: настройка TLS для SIP-соединений
Для работы SIP-клиента в браузере необходимо использовать защищенное соединение, так как современные браузеры поддерживают WebRTC и SIP-соединения только при использовании TLS. Это позволяет зашифровать передаваемые данные и защитить их от перехвата.
В этом разделе мы настроим TLS в Asterisk, чтобы SIP-клиенты могли устанавливать безопасное соединение с сервером. Для этого потребуется:
сгенерировать самоподписанный сертификат или использовать сертификат от доверенного центра сертификации (например, Let's Encrypt);
настроить Asterisk для работы с TLS;
настроить Asterisk для работы с WSS.
После настройки клиенты могут подключаться к телефонии как с использованием TLS для софтфонов, например, microsip, так и с помощью веб-сокетов по защищенному протоколу WSS. Передача аудио данных после подключение будет происходить по WebRTC.
Генерация самоподписанного сертификата
Выполняем следующие команды для создания самоподписанного сертификата и настройки его в Asterisk:
# Создаём каталог для хранения сертификатов mkdir -p /etc/asterisk/keys && cd /etc/asterisk/keys # Генерируем закрытый ключ openssl genrsa -out asterisk.key 2048 # Создаём запрос на сертификат (CSR) openssl req -new -key asterisk.key -out asterisk.csr \ -subj "/C=RU/ST=Moscow/L=Moscow/O=MyCompany/OU=IT/CN=$(hostname -f)" # Подписываем сертификат (действителен 1 год) openssl x509 -req -days 365 -in asterisk.csr -signkey asterisk.key -out asterisk.crt # Создаём сертификат CA (Certification Authority) openssl req -new -x509 -days 365 -key asterisk.key -out ca.crt \ -subj "/C=RU/ST=Moscow/L=Moscow/O=MyCompany/OU=IT/CN=CA" # Устанавливаем права доступа chmod 600 asterisk.key chmod 644 asterisk.crt ca.crt chown asterisk:asterisk asterisk.key asterisk.crt ca.crt
Настроим Asterisk для работы с TLS
Добавить транспорт можно через файл /etc/asterisk/pjsip.transports.conf или pjsip.transports_custom.conf (если у вас FreePBX). Содержимое файла будет следующее:
[0.0.0.0-tls] type=transport protocol=tls bind=0.0.0.0:5061 external_media_address=<ip сервера> external_signaling_address=<ip сервера> ca_list_file=/etc/pki/tls/certs/ca-bundle.crt cert_file=/etc/asterisk/keys/asterisk.crt priv_key_file=/etc/asterisk/keys/asterisk.key method=tlsv1_2 verify_client=no verify_server=no allow_reload=yes tos=cs3 cos=3 local_net=<локальные адреса>
Аналогичные настройки можно сделать через FreePBX в разделе Settings > Asterisk SIP Settings > SIP Settings [chan_pjsip].
Настроим Asterisk для работы с WSS
Для добавления транспорта wss также используем файлы pjsip.transports.conf или pjsip.transports_custom.conf.
[0.0.0.0-wss] type=transport protocol=wss bind=0.0.0.0:8089 external_media_address=<ip сервера> external_signaling_address=<ip сервера> allow_reload=yes tos=cs3 cos=3 local_net=<локальные адреса> ca_list_file=/etc/pki/tls/certs/ca-bundle.crt cert_file=/etc/asterisk/keys/asterisk.crt priv_key_file=/etc/asterisk/keys/asterisk.key
Настройка расширений (extensions) в Asterisk
После настройки TLS и WSS необходимо создать SIP-учетные записи и диалпланы, чтобы клиенты могли регистрироваться на сервере и совершать звонки. В Asterisk это реализуется через файл pjsip.endpoint.conf или pjsip.endpoint_custom.conf, pjsip.endpoint_custom_post.conf (при наличии FreePBX). В качестве примера давайте настроим номер 100 для работы WSS, а 101 для TLS для софтфона. Файл pjsip.endpoint.conf будет выглядеть так:
[100] type=endpoint aors=100 auth=100-auth tos_audio=ef tos_video=af41 cos_audio=5 cos_video=4 allow=ulaw,alaw,gsm,g726,g722,opus,g729 context=from-internal callerid=100 <100> dtmf_mode=rfc4733 direct_media=yes transport=0.0.0.0-tls aggregate_mwi=yes use_avpf=yes rtcp_mux=yes max_audio_streams=1 max_video_streams=1 bundle=yes ice_support=yes media_use_received_transport=no trust_id_inbound=yes user_eq_phone=no send_connected_line=yes media_encryption=dtls timers=yes timers_min_se=90 media_encryption_optimistic=no refer_blind_progress=yes rtp_timeout=30 rtp_timeout_hold=300 rtp_keepalive=0 send_pai=yes rtp_symmetric=yes rewrite_contact=yes force_rport=yes language=en one_touch_recording=on record_on_feature=apprecord record_off_feature=apprecord dtls_verify=fingerprint dtls_setup=actpass dtls_rekey=0 dtls_cert_file=/etc/asterisk/keys/asterisk.crt dtls_private_key=/etc/asterisk/keys/asterisk.key [101] type=endpoint aors=101 auth=101-auth tos_audio=ef tos_video=af41 cos_audio=5 cos_video=4 allow=ulaw,alaw,gsm,g726,g722,opus,g729 context=from-internal callerid=101 <101> dtmf_mode=rfc4733 direct_media=yes transport=0.0.0.0-tls aggregate_mwi=yes use_avpf=yes rtcp_mux=yes max_audio_streams=1 max_video_streams=1 bundle=no ice_support=yes media_use_received_transport=no trust_id_inbound=yes user_eq_phone=no send_connected_line=yes media_encryption=dtls timers=yes timers_min_se=90 media_encryption_optimistic=no refer_blind_progress=yes rtp_timeout=30 rtp_timeout_hold=300 rtp_keepalive=0 send_pai=yes rtp_symmetric=yes rewrite_contact=yes force_rport=yes language=en one_touch_recording=on record_on_feature=apprecord record_off_feature=apprecord dtls_verify=fingerprint dtls_setup=actpass dtls_rekey=0 dtls_cert_file=/etc/asterisk/keys/asterisk.crt dtls_private_key=/etc/asterisk/keys/asterisk.key
Также нужно скорректировать файлы pjsip.auth.conf и другие. Лучше создать пользователей в FreePBX либо обратиться к официальной документации по созданию extensions.
Хочу обратить внимание на то, что через FreeBPX нельзя указать транспорт wss для extension, и для решения этой проблемы можно использовать файл pjsip.transports_custom_post.conf, либо общий файл pjsip_custom_post.conf со следующим содержанием:
[100](+) transport=0.0.0.0-wss [101](+) media_encryption=sdes
Причем у 101 нужно использовать более старый кодировщик, так как многие софтфоны могут не поддерживать новые.
Настройка обратного прокси
Если необходимо, можно настроить обратный прокси, чтобы разрешить websocket-соединение с сервером телефонии. Для примера приведу настройки nginx:
location /ws { proxy_pass https://<ip-адрес>:8089/ws; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_read_timeout 86400; proxy_connect_timeout 60; }
Настройка SIP-клиента Angular с sip.js
Подробности о самом приложении рассказывать не буду. Приведу минимальную функциональность для установления соединения и совершения звонка на введённый номер.

Исходный код находится по адресу: https://github.com/chubkoiv/sip-client.git
Для подключение к серверу телефонии необходимо скорректировать переменные url, login, secret в sip.service.ts.
При запуске проекта с настройками произойдет поднятие websocket-соединения и регистрация номера в телефонии. Консоль браузера выглядит примерно так:

Состояние подключений endpoint можно посмотреть на сервере Asterisk, выполнив вход в CLI либо следующей командой:
asterisk -rx "pjsip show endpoints"

Настройка SIP-клиента с использованием софтфона microSip
Софтфон microsip вы можете скачать с официального сайта https://www.microsip.org.
Для регистрации номера выполним настройки для ранее созданного extension 101.
SIP-сервер: <ip>:5061 Имя пользователя: 101 Домен: <ip или dns-имя> Логин: 101 Пароль: <secret из Asterisk> Шифрование: необязательное Транспорт: TKS
После этого в левом нижнем углу отобразится иконка зашифрованного соединения:

Теперь если мы введем в приложении 101 и нажмем "Вызвать", то получим входящий звонок в microsip.
Заключение
В процессе работы мы развернули Asterisk 22 на CentOS 9 Stream, настроили безопасное TLS-подключение, включили поддержку WebRTC и WSS (WebSocket Secure), а также создали SIP-клиент на Angular с использованием sip.js. В результате у нас получилось полноценное решение для VoIP-звонков прямо из браузера через защищенное соединение. Кроме того, можно подключать сторонние SIP-клиенты, например MicroSIP.
В дальнейшем проект можно развивать, добавляя поддержку видеозвонков, интеграцию с базой данных для хранения SIP-учетных данных и истории вызовов, настройку STUN/TURN-серверов для работы WebRTC за NAT, подключение к мобильным SIP-клиентам и интеграцию с FreePBX для удобного управления Asterisk. Это решение можно использовать как основу для построения VoIP-инфраструктуры в корпоративных веб-приложениях, колл-центрах и CRM-системах.
