Ниже — руководство + полный установочный скрипт для Debian 12, собирающий Asterisk 22.5.1 из исходников, включающий TLS + SRTP, 3 абонента (1001–1003), блокировку анонимов, короткие сообщения (SIP MESSAGE) для Linphone, и видеозвонки по H.264.
Скрипт автоматически учитывает NAT: если задать локальную сеть — пропишет external_* и local_net; если не задавать — считает, что сервер не за NAT.
Что получится
- Сигнализация: TLS 5061/tcp для
domain.name.com(Let’s Encrypt). - Медиа (аудио+видео): RTP/RTCP 10000–20000/udp (SRTP для аудио/видео).
- Абоненты: 1001, 1002, 1003 (пароли сгенерируются).
- Диалплан: внутренние вызовы
10XX, эхо-тест 600, и контекстmessagesдля SIP MESSAGE. - H.264 для видео (pass-through; без транскодирования).
- Блокировка анонимов (контекст
public→Hangup()). - Автопродление LE-сертификата + deploy-hook, который подкладывает ключи и делает
core reload. - systemd-юнит (нативный), запуск под пользователем
asterisk. - Без записи звонков (ничего не включаем).
Параметры, которые можно (и нужно) задать
-
DOMAIN— имя домена (по умолчаниюdomain.name.com). -
LE_EMAIL— e-mail для Let’s Encrypt (рекомендовано). -
Если сервер за NAT:
LOCAL_NET— локальная IP адрес сервера (например,10.1.2.24).PUBLIC_IP— внешний IP (если не указать, скрипт попробует взять A-запись домена).
Примеры запуска (все — от root):
# Сервер с публичным IP (НЕ за NAT)
DOMAIN=domain.name.com ASTVER=22.5.1 ./install-asterisk-22.sh
# Сервер за NAT
DOMAIN=domain.name.com ASTVER=22.5.1 PUBLIC_IP=203.0.113.10 LOCAL_NET=10.1.2.24 LE_EMAIL=you@example.com ./install-asterisk-22.sh
Скрипт установки «под ключ»
Сохраните в файл install-asterisk-22.sh, затем:
chmod +x install-asterisk-22.sh
sudo ./install-asterisk-22.sh
#!/usr/bin/env bash
set -euo pipefail
# ====== Параметры (можно задавать как переменные окружения) ======
DOMAIN="${DOMAIN:-domain.name.com}"
PUBLIC_IP="${PUBLIC_IP:-}" # если за NAT; иначе оставьте пустым
LOCAL_NET="${LOCAL_NET:-}" # если за NAT, напр. 10.1.2.0/24
LE_EMAIL="${LE_EMAIL:-}" # e-mail для Let's Encrypt
ASTVER="22.5.1"
TARBALL="asterisk-${ASTVER}.tar.gz"
SRC_URL="https://downloads.asterisk.org/pub/telephony/asterisk/${TARBALL}"
SRC_DIR="/usr/src/asterisk-${ASTVER}" # внутри архива именно asterisk-22.5.1
AST_USER="asterisk"
AST_GROUP="asterisk"
say(){ printf "\n\033[1;32m[*]\033[0m %s\n" "$*"; }
warn(){ printf "\n\033[1;33m[!]\033[0m %s\n" "$*"; }
die(){ printf "\n\033[1;31m[x]\033[0m %s\n" "$*"; exit 1; }
[[ $EUID -eq 0 ]] || die "Запускайте как root."
# ====== Базовые пакеты ======
say "Установка зависимостей"
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y \
build-essential git curl wget gnupg2 ca-certificates \
libssl-dev libncurses5-dev libnewt-dev libxml2-dev libsqlite3-dev uuid-dev \
libjansson-dev libedit-dev pkg-config libcurl4-openssl-dev \
libspeexdsp-dev libopus-dev libsrtp2-dev \
python3 python3-venv \
certbot socat
# ====== Системный пользователь ======
say "Создание пользователя/группы asterisk"
id -u "$AST_USER" &>/dev/null || adduser --system --group --home /var/lib/asterisk --no-create-home "$AST_USER"
# ====== Сборка Asterisk 22.5.1 ======
say "Загрузка и сборка Asterisk ${ASTVER}"
cd /usr/src
wget -O "$TARBALL" "$SRC_URL"
tar xzf "$TARBALL"
cd "$SRC_DIR"
contrib/scripts/install_prereq install
contrib/scripts/get_mp3_source.sh || true
./configure --with-pjproject-bundled --with-ssl=openssl
make menuselect.makeopts
# включим SRTP, сообщения и H.264 (pass-through)
menuselect/menuselect \
--enable res_srtp \
--enable res_pjsip_messaging \
--enable format_h264 --enable res_format_attr_h264 \
menuselect.makeopts
make -j"$(nproc)"
make install
make samples
make config
ldconfig
# ====== Каталоги и права ======
say "Каталоги/права"
install -d -m 0750 -o "$AST_USER" -g "$AST_GROUP" /var/lib/asterisk /var/spool/asterisk /var/log/asterisk
install -d -m 0755 -o "$AST_USER" -g "$AST_GROUP" /var/run/asterisk
chown -R "$AST_USER:$AST_GROUP" /var/lib/asterisk /var/log/asterisk /var/spool/asterisk
# ====== Let's Encrypt (standalone) ======
say "Выпуск сертификата Let’s Encrypt для ${DOMAIN}"
systemctl stop asterisk || true
if [[ -n "$LE_EMAIL" ]]; then
certbot certonly --standalone -d "$DOMAIN" -m "$LE_EMAIL" --agree-tos --no-eff-email --non-interactive
else
warn "LE_EMAIL не указан — регистрируемся без e-mail"
certbot certonly --standalone -d "$DOMAIN" --agree-tos --register-unsafely-without-email --non-interactive
fi
say "Развёртывание сертификатов в /etc/asterisk/keys"
install -d -m 0750 -o root -g "$AST_GROUP" /etc/asterisk/keys
install -m 0640 -o root -g "$AST_GROUP" /etc/letsencrypt/live/$DOMAIN/fullchain.pem /etc/asterisk/keys/asterisk.crt
install -m 0640 -o root -g "$AST_GROUP" /etc/letsencrypt/live/$DOMAIN/privkey.pem /etc/asterisk/keys/asterisk.key
# ====== asterisk.conf ======
say "Правка /etc/asterisk/asterisk.conf"
sed -i \
-e 's~^\s*;*\s*runuser\s*=.*~runuser = asterisk~' \
-e 's~^\s*;*\s*rungroup\s*=.*~rungroup = asterisk~' \
-e 's~^\s*;*\s*astrundir\s*=.*~astrundir = /var/run/asterisk~' \
-e 's~^\s*;*\s*astctl\s*=.*~astctl = asterisk.ctl~' \
/etc/asterisk/asterisk.conf
# ====== modules.conf ======
say "Модули: autoload + PJSIP/SRTP/MESSAGE/H.264"
cat >/etc/asterisk/modules.conf <<'EOF'
[modules]
autoload=yes
load = res_pjsip.so
load = res_pjsip_session.so
load = chan_pjsip.so
load = res_srtp.so
load = res_pjsip_messaging.so
load = format_h264.so
load = res_format_attr_h264.so
EOF
# ====== RTP ======
say "RTP порты 10000–20000"
cat >/etc/asterisk/rtp.conf <<'EOF'
[general]
rtpstart=10000
rtpend=20000
EOF
# ====== Пароли абонентов ======
say "Генерация паролей абонентов"
P1="$(tr -dc 'A-Za-z0-9' </dev/urandom | head -c 60)"
P2="$(tr -dc 'A-Za-z0-9' </dev/urandom | head -c 60)"
P3="$(tr -dc 'A-Za-z0-9' </dev/urandom | head -c 60)"
# ====== PJSIP (TLS, SRTP, H.264, MESSAGE, NAT опционально) ======
say "Формирование pjsip.conf"
{
cat >/etc/asterisk/pjsip.conf <<EOF
[global]
type=global
endpoint_identifier_order=auth_username,username,ip,anonymous
; ===== Транспорт TLS =====
[transport-tls]
type=transport
protocol=tls
bind=0.0.0.0:5061
method=tlsv1_2
cert_file=/etc/asterisk/keys/asterisk.crt
priv_key_file=/etc/asterisk/keys/asterisk.key
EOF
# NAT-блок только если задана локальная сеть
if [[ -n "$LOCAL_NET" ]]; then
# если PUBLIC_IP не задан — попробуем взять из DNS домена
if [[ -z "$PUBLIC_IP" ]]; then
PUBLIC_IP="$(getent hosts "$DOMAIN" | awk '{print $1; exit}')"
[[ -z "$PUBLIC_IP" ]] && warn "Не удалось определить PUBLIC_IP из DNS — пропускаю external_*"
fi
if [[ -n "$PUBLIC_IP" ]]; then
cat >>/etc/asterisk/pjsip.conf <<EOF
; NAT / публичные адреса
external_signaling_address=${PUBLIC_IP}
external_signaling_port=5061
external_media_address=${PUBLIC_IP}
local_net=${LOCAL_NET}
EOF
else
warn "LOCAL_NET задан, но PUBLIC_IP пуст — external_* не будут прописаны"
fi
fi
cat >>/etc/asterisk/pjsip.conf <<'EOF'
; ===== Шаблоны =====
[endpoint-template](!)
type=endpoint
context=internal
message_context=messages
disallow=all
; ВИДЕО: H.264 первым, затем аудио
allow=h264,opus,alaw,ulaw,g722
dtmf_mode=rfc4733
direct_media=no ; при желании можно включить yes для прямой медиа
rewrite_contact=yes
force_rport=yes
rtp_symmetric=yes
ice_support=yes
rtp_keepalive=20
media_encryption=sdes
srtp_tag_32=yes ; совместимость с 32-бит SRTP-тегом
max_video_streams=1
max_audio_streams=1
transport=transport-tls
[aor-template](!)
type=aor
max_contacts=1
remove_existing=yes
[auth-template](!)
type=auth
auth_type=userpass
; ===== Абоненты =====
[1001](endpoint-template)
aors=1001
auth=1001
[1001](aor-template)
[1001](auth-template)
username=1001
password=__PASS1001__
[1002](endpoint-template)
aors=1002
auth=1002
[1002](aor-template)
[1002](auth-template)
username=1002
password=__PASS1002__
[1003](endpoint-template)
aors=1003
auth=1003
[1003](aor-template)
[1003](auth-template)
username=1003
password=__PASS1003__
EOF
}
sed -i "s/__PASS1001__/${P1}/" /etc/asterisk/pjsip.conf
sed -i "s/__PASS1002__/${P2}/" /etc/asterisk/pjsip.conf
sed -i "s/__PASS1003__/${P3}/" /etc/asterisk/pjsip.conf
# ====== Диалплан (внутренние, эхо, сообщения, блок анонимов) ======
say "Формирование extensions.conf"
cat >/etc/asterisk/extensions.conf <<'EOF'
[internal]
exten => _10XX,1,NoOp(Internal call to ${EXTEN})
same => n,Dial(PJSIP/${EXTEN},30)
same => n,Hangup()
; Эхо-тест
exten => 600,1,Answer()
same => n,Playback(demo-echotest)
same => n,Echo()
same => n,Hangup()
; Контекст для SIP MESSAGE
[messages]
exten => _10XX,1,NoOp(SIP MESSAGE to ${EXTEN} from ${MESSAGE(from)})
same => n,MessageSend(pjsip:${EXTEN})
same => n,NoOp(Send status: ${MESSAGE_SEND_STATUS})
same => n,Hangup()
; Блок анонимного доступа
[public]
exten => _.,1,NoOp(Block anonymous)
same => n,Hangup()
EOF
# ====== systemd unit (нативный) ======
say "Создание systemd-юнита"
cat >/etc/systemd/system/asterisk.service <<'EOF'
[Unit]
Description=Asterisk PBX
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=asterisk
Group=asterisk
RuntimeDirectory=asterisk
RuntimeDirectoryMode=0755
ExecStartPre=/usr/bin/install -d -m 0755 -o asterisk -g asterisk /var/run/asterisk
ExecStart=/usr/sbin/asterisk -f -U asterisk -G asterisk
ExecStop=/usr/sbin/asterisk -rx 'core stop gracefully'
Restart=on-failure
LimitCORE=infinity
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
# ====== Certbot deploy-hook ======
say "Настройка deploy-hook для автопродления LE"
install -d -m 0755 /etc/letsencrypt/renewal-hooks/deploy
cat >/etc/letsencrypt/renewal-hooks/deploy/asterisk-reload.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
DOMAIN="${DOMAIN:-domain.name.com}"
install -m 0640 -o root -g asterisk /etc/letsencrypt/live/${DOMAIN}/fullchain.pem /etc/asterisk/keys/asterisk.crt
install -m 0640 -o root -g asterisk /etc/letsencrypt/live/${DOMAIN}/privkey.pem /etc/asterisk/keys/asterisk.key
if systemctl is-active --quiet asterisk; then
/usr/sbin/asterisk -rx "core reload" || systemctl restart asterisk
fi
EOF
chmod +x /etc/letsencrypt/renewal-hooks/deploy/asterisk-reload.sh
# ====== Запуск ======
say "Запуск Asterisk"
systemctl enable --now asterisk
sleep 1
asterisk -rx "core show version" || true
asterisk -rx "module show like format_h264" || true
asterisk -rx "core show codecs video" | sed -n '1,80p' || true
asterisk -rx "pjsip show transports" || true
asterisk -rx "dialplan reload" || true
say "ГОТОВО. Данные для подключения:"
cat <<OUT
SIP по TLS:
Host: ${DOMAIN}
Port: 5061
SRTP: SDES (желательно включить в клиенте)
Абоненты:
1001 : ${P1}
1002 : ${P2}
1003 : ${P3}
Проверка на сервере:
asterisk -rvvvvv
pjsip show endpoints
pjsip show aor 1001
pjsip show contacts like 1001
dialplan show internal
(Эхо-тест: набрать 600)
Если сервер за NAT и вы задали LOCAL_NET (и PUBLIC_IP), мы прописали external_* и local_net
и включили rtp_symmetric/rewrite_contact/force_rport/ice_support на эндпойнтах.
OUT
Подключение с Android (Zoiper / Linphone / GS Wave)
- Username:
1001(или1002,1003) - Password: (из вывода скрипта /
/etc/asterisk/pjsip.conf) - Domain/Host:
domain.name.com - Transport: TLS
- Port: 5061
- SRTP: SRTP (SDES)
- Видео: включить, кодек H.264 (на обоих устройствах); на время отладки можно отключить прочие видеокодеки.
- NAT: включить ICE и указать STUN (например,
stun.linphone.org) — это помогает с публичными кандидатами для RTP и снижает шанс «тишины».
Проверки и отладка
-
Регистрация:
pjsip show aor 1001→Contacts: 1pjsip show contacts like 1001 -
Видео-кодеки:
core show codecs video→ должен быть H.264pjsip show endpoint 1001→Allow: h264,...,max_video_streams=1 -
Медиа/SDP (во время вызова):
asterisk -rvvvvv pjsip set logger on rtp set debug onВ SDP будет
m=video ...иa=rtpmap:H264/90000, а вrtp debug— RTP-пакеты и для аудио, и для видео. -
Сообщения (SIP MESSAGE): В Linphone откройте чат с
1002и отправьте текст. В консоли увидитеMESSAGE_SEND_STATUS=SUCCESS. -
Анонимы: все неизвестные входящие попадают в
publicи завершаютсяHangup().
Короткая теория и полезные справки
- PJSIP и NAT:
external_signaling_address,external_media_address,local_netна транспорте;rtp_symmetric,rewrite_contact,force_rport,ice_supportна эндпойнтах. - TLS в PJSIP:
protocol=tls,method=tlsv1_2,cert_file/priv_key_fileс путями к LE-файлам. - SRTP (SDES):
media_encryption=sdes(подходит для мобильных SIP-клиентов). - Видеозвонки: Asterisk не транскодирует видео — клиенты должны договориться по одному кодеку (мы используем H.264).
- SIP MESSAGE:
message_contextв endpoint +MessageSend()в диалплане. - Автопродление LE:
certbot.timerделает renew, deploy-hook копирует файлы и выполняетcore reload.
(Имена разделов и ключевые слова легко находятся в официальной документации Asterisk: разделы по PJSIP Configuration, NAT Traversal, TLS, MessageSend(), Video Codecs/H.264.)
Настраиваем Linphone
1) Создание SIP-аккаунта
Linphone → Settings → Accounts → + (Add account) → SIP (в некоторых версиях: Menu → Accounts → “+” → Use a SIP account)
Заполни:
- Username:
1001(или1002/1003) - Password: пароль из
/etc/asterisk/pjsip.conf(секцияtype=authу соответствующего номера) - Domain (Server):
domain.name.com - Display name: любое (не важно)
- Transport: TLS
- Port: 5061
- Outbound proxy (рекомендуется, чтобы не гадал транспорт):
sip:domain.name.com:5061;transport=tls - Registration: ON (включена), Expires: 3600 (по умолчанию ок)
Важно: используй домен, а не IP, иначе сломается проверка TLS-сертификата.
2) Безопасность / шифрование
- Media encryption: SRTP (SDES) (Prefer/Mandatory — лучше Prefer)
- TLS certificate: проверка включена (по умолчанию). Сертификат LE подойдёт автоматически.
3) Аудио-кодеки (минимум для совместимости)
Settings → Audio codecs:
- Включи: PCMA (G.711 A-law), PCMU (G.711 μ-law), Opus, G722
- Остальные можно отключить для чистоты переговоров.
4) Видео (H.264)
Settings → Video:
- Enable video: ON (и дай разрешение камере/микрофону в Android)
- Video codecs: H.264 — ON, VP8 — OFF (мы используем H.264 в Asterisk)
- Желательно включить аппаратное ускорение (Hardware acceleration), если пункт есть.
- На время отладки звони сразу “Video call” (иконка камеры), а не включай камеру посередине аудио — так меньше re-INVITE-сюрпризов.
5) Чат (SIP MESSAGE)
Ничего особого: просто открой контакт (например, 1002) и отправь сообщение.
У нас на Asterisk задан message_context=messages + MessageSend() — сообщения дойдут, если адресат зарегистрирован.
6) Быстрые тесты
- Проверь регистрацию: статус аккаунта в Linphone должен стать Registered.
На сервере:
pjsip show aor 1001→Contacts: 1. - Эхо-тест: набери 600 — услышишь своё эхо.
- Звонок 1002 → 1001: должен идти звук в обе стороны.
- Видеозвонок: запусти «Video call» 1002 → 1001. В обоих клиентах должна быть включена камера и H.264.
- Чат: отправь текст от 1001 к 1002, проверь доставку.
7) Если что-то не работает — мини-чеклист
- TLS: домен в аккаунте ровно
domain.name.com, не IP; дата/время телефона верные. - Нет звука/видео:
— включи ICE и STUN как выше;
— оба абонента должны быть Registered;
— на сервере
pjsip show transport transport-tlsдолжен показыватьexternal_*/local_net, если сервер за NAT. - Видео падает при включении камеры:
— на обоих клиентах включи H.264 и временно выключи VP8;
— делай сразу «Video call»;
— при упорных проблемах на сервере можно попробовать
direct_media=yes(мы его оставили OFF по умолчанию). - Сообщения не доходят: убедись, что адресат онлайн (SIP MESSAGE не буферизуется сервером).





