Как найти обрыв SIP и RTP в FreePBX внутри Docker
Если регистрация SIP проходит, а входящий вызов молчит или звук есть только в одну сторону, проверяйте по цепочке: сигнализацию, адреса в SDP, RTP-порты и публикацию портов Docker. Я покажу, как отделить сетевой сбой от ошибки FreePBX и какие настройки сверить до перезапуска.
Сначала отделяю SIP от звука
Я начинаю не с перезапуска, а с вопроса: вызов вообще устанавливается? Если телефон или транк зарегистрирован, но собеседник не слышит речь, это ещё не «сломался FreePBX». SIP отвечает за установление и управление вызовом, а голос передаётся отдельным медиапотоком RTP. Один путь может работать, пока второй упирается в firewall, неверный адрес или непубликованный UDP-порт. Поэтому фраза «регистрация зелёная» сообщает только часть картины.
В моих проектах полезнее всего взять один контролируемый тест: позвонить с внутреннего номера на заранее известный маршрут, записать время и отметить, кто кого слышит. Оба направления важны. Тишина в обе стороны, односторонний звук и вызов, который даже не устанавливается, ведут к разным участкам диагностики. Для сверки сетевого пути я отдельно смотрю настройки обслуживания IT-инфраструктуры, а в статье разбираю именно сетевой диагноз FreePBX в контейнере.
Если вызовы пропадают именно после перезапуска сервера, это отдельный сценарий с адресацией и восстановлением сетевой конфигурации; в каталоге есть разбор пропажи звонков после перезагрузки Asterisk в Docker. Здесь я рассматриваю другой симптом: сигнализация проходит или частично работает, а медиа не доходит. Такой фокус экономит время: не приходится чинить рестарт, когда проблема в RTP.
- Уточните симптом: вызов не устанавливается, нет звука или звук односторонний.
- Проведите один тестовый звонок и запишите время, направление и результат.
- Сопоставляйте SIP-события и RTP-пакеты одного вызова.
Что проверяю в настройках NAT
В Docker bridge контейнер получает собственный адрес в своей сети. Docker публикует заданные порты на адресах хоста и использует маскарадинг для исходящего доступа; удалённые устройства обычно видят внешний адрес хоста, а не контейнера. Это штатная модель, а не автоматически поломка. Сбой возникает, когда адрес, который Asterisk сообщает в SIP или SDP, не соответствует маршруту, доступному другой стороне, либо входящие пакеты не попадают в контейнер. Документация Docker прямо разделяет внутреннюю сеть bridge и опубликованные порты.
Для PJSIP у Asterisk есть параметры транспорта local_net, external_signaling_address и external_media_address. Первый описывает локальную сеть, второй относится к SIP-сигнализации, третий — к адресу медиа в RTP/SDP. Значения нужны только при соответствующей NAT-схеме: внешний адрес и подсеть должны совпадать с реальной топологией. Не надо вставлять параметры вслепую в случайный pjsip.conf: FreePBX управляет генерируемой конфигурацией, поэтому сначала ищите соответствующие поля в установленной версии интерфейса и проверяйте, что именно сгенерировал Asterisk.
В базе знаний отдельно подтверждены все три настройки PJSIP и их назначение; документация Asterisk поясняет, что переписывание адреса SDP происходит при определённых условиях — адрес назначения вне local_net, а адрес медиа внутри локальной сети. Это не универсальное «включить NAT». Для диагностики сравните внешний адрес, локальную подсеть и адрес в SDP тестового вызова. Если значения уже согласованы, дальнейшее переключение NAT наугад только добавит неизвестных.
- Сверьте локальную подсеть с фактической сетью контейнера и хоста.
- Проверьте, какой IP и порт указаны в SIP-заголовках и SDP.
- Убедитесь, что настройки в GUI FreePBX применены и попали в конфигурацию PJSIP.
Порты: не открываю всё подряд
Порт 5060 часто используют для SIP по UDP или TCP, а 5061 часто назначают SIP поверх TLS. Это распространённые значения, но не обязательная пара для любой установки: транспорт и порт определяются конфигурацией Asterisk, транка и телефонов. В исходной статье предлагалось открыть оба порта без выяснения протокола — это плохая инструкция. Открывать нужно тот транспорт, который действительно настроен, и только от нужных источников, если провайдер публикует свои диапазоны адресов.
Для RTP важен не мифический универсальный диапазон, а фактический диапазон конкретной установки. В FreePBX его смотрят в SIP Settings; в Asterisk базовая настройка RTP задаётся в rtp.conf параметрами rtpstart и rtpend. В образце конфигурации Asterisk указан диапазон 10000–20000, а значения по умолчанию в том же файле — 5000–31000. В сборке FreePBX настройки могут отличаться, поэтому ориентируйтесь на её фактический диапазон: firewall и Docker должны ему соответствовать. Несовпадение даже на один слой даёт знакомый результат: SIP-сессия установилась, а звук пропал.
Проверяю настройки с обеих сторон проброса: firewall хоста разрешает нужный входящий UDP, а Docker публикует тот же порт контейнера на ожидаемом адресе хоста. docker port <имя_контейнера> показывает опубликованные порты для bridge-сети; ss -lunp помогает увидеть UDP-сокеты на хосте, но сам по себе не доказывает, что внешний трафик доходит. Для режима host логика публикации портов другая: Docker игнорирует -p, потому что контейнер разделяет сетевой стек хоста. Один и тот же чек-лист для обоих режимов не годится. Разрешение порта в панели провайдера также не заменяет проверку локального firewall: пакет должен пройти все применимые фильтры. Если на пути есть маршрутизатор перед Docker-хостом, проверьте его перенаправление отдельно. Слои проверяются по фактическому маршруту, а не по одному зелёному индикатору.
- Сверьте транспорт SIP и порт с настройкой транка.
- Возьмите RTP-диапазон из конфигурации FreePBX/Asterisk.
- Проверьте соответствие firewall, публикации Docker и фактического адреса привязки.
Bridge или host: решение зависит от схемы
Bridge даёт контейнеру отдельный сетевой адрес и требует явной публикации портов, если к службе должны обращаться извне. Это удобно для изоляции и обычно понятнее в Compose, но для телефонии нужно согласовать SIP, RTP, NAT и правила firewall. Проброс 5060 не означает, что автоматически опубликован весь RTP-диапазон. Нельзя сказать, что bridge ломает звонки: он просто добавляет места, где конфигурации должны совпасть.
Host использует сетевой стек машины-хоста и не создаёт отдельный адрес контейнера. По документации Docker в этом режиме публикация -p не применяется, а сетевое пространство контейнера не изолировано от хоста. Это иногда упрощает работу с большим количеством RTP-портов, однако не исправляет неверный SDP или ошибочную NAT-настройку. Я выбираю режим только после схемы портов, оценки изоляции и требований образа FreePBX. «Поставим host, и точно заработает» — не технический план.
Перед сменой режима фиксирую текущую конфигурацию Compose и правила firewall, затем сверяю, какие порты и интерфейсы реально используются. Если менять сетевой режим в рабочее время без окна и отката, легко получить уже не односторонний звук, а полностью недоступную АТС. При этом перезапуск нужен не после любого изменения: сначала выясняю, применяет ли конкретная настройка FreePBX reload, просит перезапустить Asterisk или требует пересоздания контейнера. Это разные действия.
- Для bridge проверьте публикацию всех реально используемых портов.
- Для host проверьте занятость портов и сетевую изоляцию хоста.
- Меняйте режим только вместе с обновлённой схемой доступа и планом возврата.
Команды и наблюдения, которые дают ответ
Сначала смотрю состояние регистрации и транспорта из CLI Asterisk: docker exec <контейнер> asterisk -rx "pjsip show registrations" и docker exec <контейнер> asterisk -rx "pjsip show transports". Для контактов и endpoint в зависимости от версии пригодится docker exec <контейнер> asterisk -rx "pjsip show endpoints". Старую команду sip show peers нельзя выдавать как универсальную: она относится к драйверу chan_sip, тогда как современные установки часто используют chan_pjsip. Если CLI отвечает, что команда неизвестна, это подсказка о драйвере, а не повод копировать случайную команду из форума.
Затем проверяю прохождение пакетов на хосте во время тестового звонка, например sudo tcpdump -ni any udp. Такая команда покажет UDP-трафик, но не объяснит автоматически его смысл: сопоставьте время вызова, адреса и порты с настройками транка и контейнера. Если в дампе виден SIP INVITE, а ожидаемых RTP-пакетов нет, ищите точку потери на медиапути и уточняйте, не использует ли система другой диапазон или транспорт. Если пакеты доходят до хоста, но не до контейнера, исследуйте публикацию портов и фильтрацию Docker/firewall.
Наконец, смотрю логи Asterisk и содержимое SDP в пределах диагностируемого вызова. Для PJSIP важно увидеть адрес и порт, куда абоненту предложено слать медиа; затем проверить, приходит ли RTP от удалённой стороны и уходит ли ответный поток. Не публикуйте полный дамп SIP: в нём могут оказаться номера телефонов и данные авторизации. Для разбора достаточно обезличенных строк, временной отметки и пары адрес/порт из тестового вызова.
- `pjsip show registrations` — состояние регистраций транков.
- `pjsip show transports` — загруженные SIP-транспорты.
- `tcpdump -ni any udp` — наблюдение UDP во время теста.
- Сверьте SDP, RTP и записи firewall для одного звонка.
Как закрепляю исправление
Когда причина найдена, меняю один слой за раз: сначала исправляю публикацию или правило firewall, затем проверяю настройки NAT и только после этого повторяю тестовый вызов. Так понятно, какое действие изменило результат. После каждого шага фиксирую направление вызова и слышимость в обе стороны. Если одновременно сменить сетевой режим, диапазон RTP и настройки транспорта, успешный тест не покажет, какое из изменений было необходимым. А следующий сбой придётся разбирать с нуля.
В условном разборе из исходной статьи описывался сбой после перезапуска и внутренний адрес контейнера. Я не выдаю приведённые там 15 минут, 90 % причин, конкретный IP или имя сети за измеренные факты: подтвердить их нельзя. Для реального случая нужно собрать схему, версию образа, режим сети и настройки портов. Сам факт запуска FreePBX в контейнере не доказывает, что одинаково настроены все сборки: образ, версия и файлы Compose меняют детали. Поэтому для диагностики нужны фактические параметры установленной системы, а не чужой пример конфигурации.
После исправления сохраняю схему сетей, перечень опубликованных портов, RTP-диапазон, локальные сети и способ проверки вызова. В мониторинге отдельно отслеживаю регистрацию транка и доступность маршрута; наличие регистрации не подменяет проверку качества аудио. А перед обновлением образа повторяю короткий тест входящего и исходящего вызова. Здесь всё скучно, зато после обновления не приходится выяснять на слух, работает ли телефония.
- Запишите фактический режим Docker и настройки конкретного образа.
- Сохраните перечень портов и диапазон RTP рядом с Compose-конфигурацией.
- После изменения проверьте входящий и исходящий тест, включая звук в обе стороны.
Частые вопросы
Почему SIP зарегистрирован, а звука нет?
Регистрация подтверждает SIP-обмен, но голос идёт по RTP. Проверьте адрес и порт в SDP, фактический RTP-диапазон и прохождение UDP через firewall и Docker.
Нужно ли всегда открывать UDP 5060 и 5061?
Нет. Откройте настроенный SIP-транспорт и порт. 5060 часто используют для UDP/TCP, 5061 — для TLS, но конфигурация может отличаться.
Какой диапазон RTP у FreePBX?
Сверьте диапазон с SIP Settings и конфигурацией Asterisk в rtp.conf. Часто встречается 10000–20000 UDP, но это значение нельзя считать обязательным для каждой системы.
Как проверить регистрацию в PJSIP?
В CLI Asterisk используйте `pjsip show registrations` и `pjsip show endpoints`. Команда `sip show peers` относится к chan_sip и не универсальна для PJSIP.
Что выбрать для телефонии: bridge или host?
Bridge требует публикации нужных портов, host использует сетевой стек хоста и игнорирует публикацию `-p`. Выбор зависит от схемы, изоляции и требований образа.
Источники
- Configuring res_pjsip to work through NAT — Asterisk Documentation — https://docs.asterisk.org/Configuration/Channel-Drivers/SIP/Configuring-res_pjsip/Configuring-res_pjsip-to-work-through-NAT/
- res_pjsip — Asterisk Documentation — https://docs.asterisk.org/Asterisk_20_Documentation/API_Documentation/Module_Configuration/res_pjsip/
- Bridge network driver — Docker Docs — https://docs.docker.com/engine/network/drivers/bridge/
- Host network driver — Docker Docs — https://docs.docker.com/engine/network/drivers/host/
- rtp.conf.sample — Asterisk source code — https://github.com/asterisk/asterisk/blob/master/configs/samples/rtp.conf.sample
- RFC 3261: SIP — RFC Editor — https://www.rfc-editor.org/rfc/rfc3261.html



