Self-hosted VoIP-сервер: Asterisk чи FreePBX
Як запустити Asterisk або FreePBX на власному VPS: SIP-транки, діапазони RTP-портів, правила firewall проти сканерів і як починається toll fraud.
Що таке self-hosted VoIP-сервер
Self-hosted VoIP-сервер — це SIP-сервер, запущений на VPS під вашим керуванням. Тому виклики маршрутизує ваш власний сервер, а не hosted-телефонний сервіс. VoIP (voice over IP) передає голос у вигляді UDP-пакетів. SIP (session initiation protocol) — це протокол сигналізації, який встановлює та завершує виклик. Аудіо не передається через SIP. Саме цей факт спричиняє більшість описаних нижче проблем.
Для роботи системи потрібні чотири компоненти.
- Програмне забезпечення PBX (private branch exchange). Зазвичай використовують Asterisk. Воно зберігає внутрішні номери та dialplan.
- Кінцеві пристрої. Це настільні телефони або softphone, які реєструються на PBX за допомогою імені користувача та секрету.
- SIP trunk. Це платний обліковий запис у провайдера, який підключає вас до загальнодоступної телефонної мережі та надає реальні телефонні номери в оренду.
- Media path. RTP (real-time transport protocol) передає аудіо окремими потоками через власні UDP-порти.
Self-hosting PBX не означає self-hosting телефонних номерів. Номери надає оператор, і ви все одно платите за кожен номер та кожну хвилину. Під вашим контролем залишаються маршрутизація викликів, голосова пошта, записи розмов і список внутрішніх номерів. Також ви відповідаєте за безпеку сервісу, який зловмисники атакують заради грошей.
Які порти потрібні self-hosted VoIP-серверу?
SIP-сигналізація використовує порт 5060 для UDP і TCP, а порт 5061 — для SIP через TLS (безпека транспортного рівня). Ці порти використовуються лише для встановлення виклику. Аудіо кожного виклику передається окремим потоком UDP на порт із діапазону RTP. Asterisk постачається зі зразком rtp.conf, який задає rtpstart=10000 і rtpend=20000, а вбудовані значення за замовчуванням — 5000 і 31000. Для кожного виклику потрібні два порти з цього діапазону: один для RTP, інший для RTCP (протокол керування RTP).
Саме через цей поділ більшість перших спроб завершується невдало. Виклик встановлюється, обидва телефони показують, що його прийнято, але жодна сторона не чує звуку, оскільки міжмережевий екран дозволяє порт 5060 і відкидає всі пакети RTP. Сигналізація та медіадані передаються окремими потоками, тому для них потрібні окремі правила міжмережевого екрана. Якщо цей поділ для вас новий, перед відкриттям портів варто прочитати як працюють порти та сокети, що прослуховуються, у Linux.
Зменште діапазон перед тим, як відкривати його. Двадцять тисяч портів — значно більше, ніж потрібно невеликій системі. Два порти на один виклик означають, що діапазону з двохсот портів достатньо для ста одночасних викликів.
[general]
rtpstart=10000
rtpend=10200Застосуйте це за допомогою sudo asterisk -rx "core reload".
Чи варто встановлювати Asterisk або FreePBX?
Asterisk — це рушій. Ви налаштовуєте його за допомогою текстових файлів у /etc/asterisk і самостійно пишете dialplan. FreePBX — це вебінтерфейс на PHP і JavaScript, який працює поверх Asterisk, генерує ці файли та додає модулі для голосової пошти й черг викликів.
На VPS важливо, кому належить машина. Станом на August 2026 офіційний інсталятор FreePBX 17 очікує чисту систему Debian 12 і встановлює Asterisk, вебсервер, сервер баз даних і PHP. Якщо запустити його на сервері, де вже працюють інші сервіси, результат буде проблемним. Виділіть FreePBX окремий VPS.
wget https://github.com/FreePBX/sng_freepbx_debian_install/raw/master/sng_freepbx_debian_install.sh -O /tmp/sng_freepbx_debian_install.sh
sudo bash /tmp/sng_freepbx_debian_install.shЖурнал інсталяції зберігається в /var/log/pbx/freepbx17-install.log. Це перше місце, яке слід перевірити, якщо скрипт завершується передчасно.
FreePBX керує згенерованими ним файлами конфігурації. Якщо вручну змінити pjsip.conf на сервері з FreePBX, зміна зникне наступного разу, коли GUI запише цей файл. FreePBX читає окремі файли, у назві яких є _custom, для конфігурації, написаної вручну, і не змінює їх.
Компроміс полягає в такому. FreePBX надає GUI, але водночас розміщує сторінку входу до телефонної системи у публічному інтернеті. У Asterisk без вебінтерфейсу взагалі немає вебповерхні атаки, а кожне налаштування є документованою директивою, яку можна прочитати у файлі та зберігати в git. Якщо ви встановлюєте FreePBX, обмежте доступ до його вебпорту власною IP-адресою або підключайтеся через VPN, оскільки адміністративний GUI для PBX є ціллю з прямим шляхом до фінансових ресурсів.
Примітка щодо версій, актуальна станом на August 2026: Asterisk 22 — поточний випуск із довгостроковою підтримкою, опублікований у October 2024; виправлення безпеки для нього надаватимуться до October 2028. Asterisk 23 — стандартний випуск. Ubuntu 24.04 містить Asterisk 20.6.0 у репозиторії universe.
Встановлення Asterisk в Ubuntu 24.04
Пакет із репозиторію дистрибутива — найшвидший варіант. Ubuntu застосовує до нього власні виправлення, і він автоматично запускається через systemd.
sudo apt update
sudo apt install -y asterisk
sudo asterisk -rx "core show version"Збирання з вихідного коду натомість дає змогу отримати поточний реліз із довгостроковою підтримкою.
sudo apt update
sudo apt install -y build-essential wget
cd /usr/local/src
sudo wget https://downloads.asterisk.org/pub/telephony/asterisk/asterisk-22-current.tar.gz
sudo tar -xzf asterisk-22-current.tar.gz
cd asterisk-22.*
sudo contrib/scripts/install_prereq install
sudo ./configure
sudo make menuselect
sudo make -j"$(nproc)"
sudo make install
sudo make samples
sudo make config
sudo ldconfiginstall_prereq install встановлює залежності для збирання у вашому дистрибутиві, а install_prereq test виводить команди, які буде виконано, не вносячи жодних змін. make menuselect відкриває вибір модулів. Саме тут у розділі Codec Translators потрібно увімкнути codec_opus. Виконуйте make samples лише під час нового встановлення, оскільки команда записує приклад конфігурації в /etc/asterisk. make config встановлює init-скрипт у /etc/init.d/asterisk, а systemd запускає його через шар сумісності із SysV, тому після цього працює sudo systemctl enable --now asterisk.
Незалежно від вибраного способу, sudo asterisk -rvvv підключається до запущеного daemon і надає CLI. Виконання core show version у ньому показує, що саме встановлено.
Налаштування SIP-транка та одного внутрішнього номера
PJSIP — це драйвер SIP-каналу в актуальних версіях Asterisk. Його конфігурація зберігається в /etc/asterisk/pjsip.conf і складається з невеликих типізованих секцій, які посилаються одна на одну за іменем. Секції різних типів можуть мати спільне ім’я, тому кожен блок нижче називається mytrunk.
[transport-udp]
type=transport
protocol=udp
bind=0.0.0.0
[mytrunk]
type=registration
outbound_auth=mytrunk
server_uri=sip:sip.example.com
client_uri=sip:1234567890@sip.example.com
retry_interval=60
[mytrunk]
type=auth
auth_type=userpass
username=1234567890
password=REPLACE_WITH_A_LONG_RANDOM_SECRET
[mytrunk]
type=aor
contact=sip:sip.example.com:5060
[mytrunk]
type=endpoint
context=from-trunk
disallow=all
allow=ulaw
outbound_auth=mytrunk
aors=mytrunk
[mytrunk]
type=identify
endpoint=mytrunk
match=sip.example.comОб’єкт registration надсилає REGISTER, який повідомляє провайдеру, куди доставляти ваші виклики. Об’єкт identify визначає, як виклик від провайдера зіставляється з цим endpoint за IP-адресою джерела. Провайдер зазвичай публікує кілька адрес, які потрібно вказати в цьому об’єкті. Вихідна реєстрація та endpoint навмисно є окремими об’єктами: перший повідомляє провайдеру, де ви перебуваєте, а другий визначає, що робити з вхідними викликами.
Для настільного телефона потрібні ще три об’єкти.
[6001]
type=endpoint
context=internal
disallow=all
allow=ulaw
auth=auth6001
aors=6001
direct_media=no
[auth6001]
type=auth
auth_type=userpass
username=6001
password=REPLACE_WITH_A_LONG_RANDOM_SECRET
[6001]
type=aor
max_contacts=1direct_media=no залишає Asterisk у медіатракті. Якщо не вказати цей параметр, Asterisk спробує змусити два endpoint надсилати RTP безпосередньо один одному. Це не працює, коли телефон перебуває за NAT (трансляцією мережевих адрес) на домашньому маршрутизаторі. Секрет ніколи не повинен збігатися з номером внутрішньої лінії. У прикладі провайдера для внутрішнього номера 6001 використовується password=6001, щоб приклад було легше читати. Сканери перевіряють саме такі шаблони насамперед.
План нумерації у /etc/asterisk/extensions.conf визначає, що дозволено робити в кожному контексті.
[internal]
exten => 6001,1,Dial(PJSIP/6001,20)
exten => _9X.,1,Dial(PJSIP/${EXTEN:1}@mytrunk,60)
[from-trunk]
exten => 1234567890,1,Dial(PJSIP/6001,20)
same => n,Hangup()Ці два контексти утворюють межу безпеки. from-trunk обробляє виклики від провайдера та може викликати лише внутрішній номер 6001. Він не має доступу до шаблону _9X., тому зовнішній виклик не може повторно вийти через ваш транк. Якщо об’єднати контексти, ви створите типовий шлях для телефонного шахрайства: зловмисник телефонує на ваш номер, ваш план нумерації виконує вихідний виклик через ваш обліковий запис, а платите за нього ви.
Застосуйте конфігурацію та перевірте її.
sudo asterisk -rx "pjsip reload"
sudo asterisk -rx "pjsip show registrations"
sudo asterisk -rx "pjsip show endpoints"pjsip show registrations має показати mytrunk зі статусом Registered. Rejected означає, що провайдер відхилив ваші облікові дані. Unregistered означає, що на ваш REGISTER немає відповіді, тому спочатку перевірте firewall.
Правила брандмауера для SIP і RTP
Сигналізація та медіадані потребують різного підходу, оскільки вони несуть різні ризики. Обмежте 5060 адресами, які фактично використовує ваш провайдер, і мережами, у яких розташовані ваші телефони.
sudo ufw allow proto udp from 203.0.113.10 to any port 5060
sudo ufw allow proto tcp from 203.0.113.10 to any port 5060
sudo ufw allow 10000:10200/udp
sudo ufw status verboseДіапазон RTP не можна звузити так само сильно, оскільки медіадані часто надходять з іншої адреси, ніж сигналізація. Запитайте у провайдера його підмережі для медіаданих і обмежте доступ ними, якщо провайдер їх публікує. Залишайте діапазон лише таким широким, як потрібно в період найбільшого навантаження. Політики за замовчуванням, порядок правил та інші аспекти моделі ufw описано в посібнику з основ брандмауера ufw для VPS.
Також перевірте IPv6. Якщо в /etc/default/ufw встановлено IPV6=no, ufw взагалі не фільтрує IPv6, тому демон, прив’язаний до ::, буде доступний через IPv6, і жодне з наведених вище правил не застосовуватиметься. У матеріалі Відкриття портів для IPv6 за допомогою ufw пояснено відмінності між цими двома протоколами. Більшість провайдерів також надає окремий мережевий брандмауер у панелі керування. Він застосовується до того, як пакети досягнуть VPS, тому порт має бути відкритий в обох місцях.
SIP-брутфорс і toll fraud — це обов’язкові до врахування проблеми
Відкрийте 5060 на публічній адресі — і почнуться сканування. Схема стабільна: запити REGISTER та INVITE з багатьох адрес-джерел, які перебирають поширені номери внутрішніх абонентів із поширеними секретами. Asterisk записує кожну невдалу спробу в журнал. Рядок має такий вигляд.
Request 'REGISTER' from '<sip:1000@198.51.100.20>' failed for '198.51.100.20:5060' (callid: 5f1a5c0d) - No matching endpoint foundЦя проблема потребує реальних заходів через фінансові ризики. Викрадений внутрішній номер використовують для дорогих міжнародних дзвінків, часто на номери з підвищеною тарифікацією, які виплачують зловмиснику частину доходу. Рахунок сплачуєте ви, оскільки дзвінки виконувалися з вашими обліковими даними. Атака працює зі швидкістю машини й зазвичай триває вночі.
Потрібно застосувати шість засобів захисту. Це не додаткове посилення безпеки.
- Ніколи не створюйте внутрішній номер, секретом якого є його власний номер або коротке слово. Згенеруйте секрет за допомогою
openssl rand -base64 24і вставте його. - Не дозволяйте анонімні вхідні дзвінки. PJSIP за замовчуванням відхиляє виклики від невідомих абонентів і приймає їх лише за наявності endpoint з іменем
anonymous. Не створюйте такий endpoint. - Зберігайте context транку окремо від будь-якого context, з якого можна здійснювати вихідні дзвінки, як показано вище.
- Обмежте сигнальний трафік за адресою-джерелом у ufw і в мережевому firewall вашого провайдера.
- Встановіть ліміт витрат у провайдера SIP-транку та вимкніть міжнародні напрямки, на які ви ніколи не телефонуєте. Це єдиний засіб, який обмежує збитки, якщо інші засоби не спрацюють.
- Запустіть fail2ban для журналу Asterisk.
Asterisk також може створювати подію безпеки після повторних невідповідних запитів з однієї адреси. Розділ [global] у pjsip.conf приймає unidentified_request_count, значення якого за замовчуванням дорівнює 5, і unidentified_request_period, значення якого за замовчуванням становить 5 секунд. Разом це означає, що п’ять невідповідних запитів з однієї адреси протягом п’яти секунд створюють подію безпеки, на яку може реагувати fail2ban.
Заблокуйте сканери за допомогою fail2ban
fail2ban уже містить готовий jail asterisk. Він охоплює порти 5060 і 5061, читає /var/log/asterisk/messages і за замовчуванням використовує maxretry = 10. Jail залишається вимкненим, доки ви не ввімкнете його в /etc/fail2ban/jail.local.
[asterisk]
enabled = true
maxretry = 5
findtime = 600
bantime = 86400sudo systemctl restart fail2ban
sudo fail2ban-client status asteriskКоректний результат містить шлях до файлу журналу jail і кількість адрес, які наразі заблоковано. Для відкритого порту 5060 це число перестає бути нульовим протягом доби. Готовий фільтр знаходить наведені вище повідомлення No matching endpoint found, а також структуровані рядки SecurityEvent від Asterisk. Ці події записуються в окремий канал журналу, який у /etc/asterisk/logger.conf закоментовано. Щоб обробляти їх, увімкніть цей канал і додайте файл до logpath jail.
[logfiles]
console => notice,warning,error
messages.log => notice,warning,error
security.log => securityПерезавантажте logger за допомогою sudo asterisk -rx "logger reload". Фільтр також містить journalmatch для asterisk.service, тому можна використовувати journal backend, якщо ви не хочете зберігати файли журналів. Встановлення, структуру jail.local і розблокування адреси, яку ви випадково заблокували, описано в посібнику з fail2ban для Ubuntu 24.04.
Затримка та вибір кодека на віддаленому VPS
Затримку визначає географія, і налаштуваннями її не усунути. ITU-T G.114 рекомендує підтримувати односторонню затримку меншою за 150 ms для звичайної розмови та вважає затримку приблизно до 400 ms ще придатною для використання. Аудіо з телефону надходить на ваш VPS, а потім передається провайдеру trunk, тому VPS у невдалому регіоні проходить цей шлях двічі. Розміщуйте його ближче до телефонів або до провайдера. Якщо ці напрямки суперечать один одному, обирайте розміщення ближче до телефонів, оскільки ця ділянка зазвичай проходить через споживчий інтернет, де jitter найбільший.
Вибір кодека визначає пропускну здатність на один виклик. Кожен кодек у цьому розділі надсилає пакет кожні 20 ms, тобто 50 пакетів на секунду. Кожен пакет містить 40 bytes заголовків IP, UDP і RTP додатково до аудіонавантаження.
The data behind this chart
[
{
"label": "G.711 ulaw",
"payload_kbps": 64,
"ip_kbps": 80
},
{
"label": "G.722",
"payload_kbps": 64,
"ip_kbps": 80
},
{
"label": "Opus at 24 kbps",
"payload_kbps": 24,
"ip_kbps": 40
},
{
"label": "G.729",
"payload_kbps": 8,
"ip_kbps": 24
}
]G.711 ulaw є типовим кодеком у більшості trunk. Його навантаження становить 64 kbps, а з урахуванням заголовків активний виклик використовує 80 kbps у кожному напрямку. Opus зі швидкістю 24 kbps використовує 40 kbps, а G.729 зменшує цей показник до 24 kbps ціною якості аудіо та процесорного часу. Це розрахункові значення з урахуванням заголовків, а не результати вимірювань: швидкість навантаження плюс 40 bytes на пакет за 50 пакетів на секунду. Ethernet або VLAN framing додає ще трохи до обсягу даних у мережі.
Transcoding потребує процесорних ресурсів. Якщо ваші телефони та trunk використовують ulaw, дозвольте лише ulaw, і Asterisk передаватиме аудіо без змін. Opus добре працює в мережах із втратою пакетів, але transcoding між Opus і G.711 потребує зовнішнього модуля codec_opus. Його вибирають у make menuselect, і цей модуль не збирається за замовчуванням.
Що саме ламається та який рядок ви побачите
Виклик з’єднується, але ніхто нікого не чує. RTP не надходить. Перевірте, чи діапазон у rtp.conf збігається з діапазоном, відкритим у firewall, а під час виклику відстежуйте пакети за допомогою sudo tcpdump -ni any udp portrange 10000-10200. Якщо пакетів немає зовсім, їх блокує ваш firewall або мережевий firewall провайдера.
Аудіо працює лише в одному напрямку. Одна сторона надсилає RTP на адресу, яка не може його прийняти. Це проблема адреси, а не порту. Якщо VPS має публічну адресу безпосередньо на своєму інтерфейсі, обробка NAT не потрібна. Якщо провайдер надає VPS приватну адресу з однозначним зіставленням із публічною адресою, задайте публічну адресу в transport і вкажіть приватний діапазон у local_net.
[transport-udp]
type=transport
protocol=udp
bind=0.0.0.0
local_net=10.0.0.0/8
external_media_address=198.51.100.5
external_signaling_address=198.51.100.5No matching endpoint found у журналі. Запит не зіставлено з жодним endpoint за IP-адресою або іменем користувача. Для сканера це нормально, і fail2ban обробить такий запит. Якщо запит надходить від вашого провайдера, це означає, що в секції identify не вказано адресу, з якої він телефонує вам.
Статус реєстрації — Rejected. Провайдер відхилив облікові дані в секції auth. Виконайте pjsip set logger on у CLI, відстежте один REGISTER і відповідь на нього, а потім порівняйте client_uri та username зі значеннями, які надав провайдер.
У журналі взагалі немає корисної інформації. За замовчуванням Asterisk записує повідомлення рівня notice і вище в messages.log. Підвищте рівень за допомогою core set verbose 4 і pjsip set logger on на час відтворення проблеми, а потім вимкніть обидва параметри, оскільки SIP logger записує кожен пакет.
Перед тим як відкрити доступ
PBX — не такий, як інші сервіси, які ви розміщуєте самостійно. Несправний вебзастосунок лише зробить сторінку недоступною. Несправний PBX за кілька годин може спричинити значні витрати на телефонні дзвінки, поки ви спите. Запускайте його на VPS, де немає інших сервісів, обмежте доступ до 5060 відомими адресами, задайте для кожного extension випадковий secret і встановіть ліміт витрат для облікового запису trunk. Для решти системи потрібен такий самий базовий захист, як для будь-якого доступного ззовні сервера. Його описано в цьому огляді реального рівня безпеки VPS-хостингу.
FAQ
Які порти потрібно відкрити для self-hosted VoIP-сервера?
Порт 5060 для SIP-сигналізації через UDP і TCP, порт 5061, якщо ви використовуєте SIP через TLS, а також діапазон UDP-портів для RTP-медіа. У прикладі rtp.conf для Asterisk використовується діапазон від 10000 до 20000, а вбудовані значення за замовчуванням — від 5000 до 31000. Кожен виклик використовує два порти з цього діапазону, тому діапазон із двохсот портів підтримує сто одночасних викликів. Відкрийте діапазон RTP для UDP і обмежте доступ до 5060 адресами вашого провайдера та власними мережами, а не залишайте його відкритим для всіх.
Чи потрібно встановлювати Asterisk окремо або використовувати FreePBX?
Встановлюйте чистий Asterisk, якщо вам потрібна мала площа атаки, конфігураційні файли, які можна зберігати в git, і ви готові самостійно писати dialplan. Встановлюйте FreePBX, якщо вам потрібен GUI для extensions, voicemail і call queues. Станом на August 2026 інсталятор FreePBX 17 очікує чисту систему Debian 12 і встановлює Asterisk, web server, database server та PHP, тому виділіть для нього окремий VPS. FreePBX повторно генерує конфігураційні файли, якими керує, тому ручні зміни потрібно вносити у файли _custom.
Чому після встановлення виклику немає аудіо?
Сигналізація спрацювала, а медіа — ні. SIP встановив виклик через порт 5060, а аудіо передається окремим UDP-потоком на порт із діапазону RTP, який щось блокує. Перевірте, що діапазон у rtp.conf збігається з діапазоном, відкритим у вашому firewall. Також перевірте мережевий firewall провайдера та firewall на сервері. Виконайте sudo tcpdump -ni any udp portrange 10000-10200 під час виклику: якщо пакетів немає, їх блокують до того, як вони надходять на сервер.
Як зупинити brute force-атаки на SIP і шахрайство з тарифікацією?
Задайте для кожного extension довгий випадковий secret, який ніколи не збігається з номером extension. Тримайте context, що використовується вашим trunk, окремо від будь-якого context, з якого можна здійснювати вихідні виклики, щоб вхідний виклик не міг виконати зворотний вихідний виклик через ваш обліковий запис. Обмежте доступ до порту 5060 адресами вашого провайдера. Увімкніть jail asterisk у fail2ban. Він читає /var/log/asterisk/messages і блокує адреси, з яких надходить No matching endpoint found невдалих спроб. Потім установіть ліміт витрат і заблокуйте невикористовувані міжнародні напрямки у провайдера, оскільки лише це обмеження контролює суму збитків, якщо інші заходи не спрацюють.
Чи погіршує якість викликів VPS у віддаленому регіоні?
Так, оскільки аудіо проходить дві ділянки: від телефону до VPS, а потім від VPS до trunk-провайдера. ITU-T G.114 рекомендує односторонню затримку менше ніж 150 ms, а неправильно розміщений VPS може витратити більшу частину цього запасу лише на відстань. Обирайте регіон, розташований близько до телефонів, оскільки ця ділянка зазвичай проходить через споживчий інтернет, де jitter найбільший. Вибір codec не усуває затримку, а лише змінює пропускну здатність, тому G.729 заощаджує байти, але не усуне проблему на маршруті із затримкою 200 ms.