← На главную

Установка и удаление Asterisk: разбор bash-скриптов

Установка и удаление Asterisk: разбор bash-скриптов

Подробный разбор того, что делает интерактивный скрипт установки Asterisk (с выбором версии 20 LTS / 21 / 22 / 23) под Ubuntu и Debian, и симметричный скрипт полного удаления. Ниже — пошаговое описание каждого этапа и полный исходный код обоих скриптов.

Проверенные версии: 20.19.0 LTS, 21.12.2, 22.9.0, 23.4.0 Поддерживаемые ОС: Ubuntu 20.04/22.04/24.04, Debian 10/11/12 Запуск: от root

Содержание

  1. Что делает скрипт установки Asterisk
  2. Что делает скрипт удаления Asterisk
  3. Полный исходный код обоих скриптов

Что делает скрипт установки Asterisk

1. Проверки и инициализация

  • Проверяет что запущен от root — иначе завершается с ошибкой
  • Определяет ОС (поддерживает только Ubuntu и Debian)
  • Выводит баннер с информацией об ОС и архитектуре процессора

2. Выбор версии

Показывает интерактивное меню с 5 вариантами:

Вариант Версия Тип
1 20.19.0 LTS — поддержка до 2027
2 21.12.2 Standard — стабильная
3 22.9.0 Standard — новейшая
4 23.4.0 Development — для тестов
5 любая ввод вручную

После выбора запрашивает подтверждение перед началом установки.


3. Установка зависимостей (два этапа)

Первый этап — базовые пакеты через apt-get: build-essential, libssl-dev, libxml2-dev, libsqlite3-dev, libjansson-dev, libcurl4-openssl-dev, sox, mpg123 и другие библиотеки необходимые для компиляции.

Второй этап — официальный скрипт Asterisk contrib/scripts/install_prereq install — автоматически доустанавливает специфические зависимости которые Asterisk определяет сам, например libpq-dev (PostgreSQL), libsnmp-dev, libopus-dev, libc-client2007e-dev и другие.


4. Скачивание и распаковка исходников

  • Скачивает архив с официального сервера downloads.asterisk.org
  • Если архив уже скачан — пропускает загрузку
  • Распаковывает в /usr/src/asterisk/asterisk-<версия>/

5. Загрузка MP3-кодека

Запускает contrib/scripts/get_mp3_source.sh — скачивает исходники MPGLIB из SVN репозитория Digium. Это нужно для поддержки воспроизведения MP3 файлов в Asterisk.


6. Configure

Запускает ./configure с двумя ключевыми флагами:

  • --with-jansson-bundled — использует встроенную библиотеку jansson (JSON) вместо системной
  • --with-pjproject-bundled — использует встроенную библиотеку pjproject (SIP стек) вместо системной

Это обеспечивает совместимость и избегает конфликтов версий.


7. Выбор модулей (menuselect)

Запускает make menuselect.makeopts и включает дополнительные модули:

Модуль Назначение
format_mp3 Воспроизведение MP3 файлов
res_snmp SNMP мониторинг
res_http_websocket WebSocket для WebRTC
codec_opus Кодек Opus (высокое качество)
EXTRA-SOUNDS-EN-GSM Английские голосовые подсказки
EXTRA-SOUNDS-RU-GSM Русские голосовые подсказки
MOH-OPSOUND-GSM Музыка на удержании

8. Компиляция и установка

  • make -j$(nproc) — компилирует используя все доступные ядра процессора (ускоряет сборку)
  • make install — устанавливает бинарники в /usr/sbin/
  • make samples — устанавливает все конфигурационные файлы-примеры в /etc/asterisk/
  • make config — устанавливает init скрипты и logrotate
  • ldconfig — обновляет кэш динамических библиотек

9. Системный пользователь

  • Создаёт пользователя asterisk с домашней директорией /var/lib/asterisk и без возможности логина (/sbin/nologin)
  • Устанавливает владельца asterisk:asterisk на все директории: /etc/asterisk, /var/log/asterisk, /var/lib/asterisk, /var/spool/asterisk, /usr/lib/asterisk
  • Создаёт /var/run/asterisk с правами 750 заранее — до старта сервиса

10. Добавление root в группу asterisk

usermod -aG asterisk root

Это позволяет пользователю root подключаться к CLI через asterisk -rvvv без переключения на пользователя asterisk. После перелогина работает напрямую, без перелогина — через newgrp asterisk.


11. Настройка asterisk.conf

Прописывает в /etc/asterisk/asterisk.conf в секцию [options]:

runuser = asterisk          # запускать процесс от пользователя asterisk
rungroup = asterisk         # запускать процесс от группы asterisk
astctlpermissions = 0660    # права на сокет — доступен группе
astctlgroup = asterisk      # группа владельца сокета

Благодаря astctlpermissions = 0660 сокет /var/run/asterisk/asterisk.ctl доступен всем пользователям группы asterisk — в том числе root.


12. Настройка systemd

Создаёт два файла:

/etc/systemd/system/asterisk.service — основной unit:

  • Тип simple — systemd считает сервис запущенным сразу
  • User=asterisk / Group=asterisk — процесс работает от непривилегированного пользователя
  • RuntimeDirectory=asterisk + RuntimeDirectoryMode=0750 — systemd создаёт /var/run/asterisk с правильными правами до запуска процесса (ключевое исправление — без этого сокет не создавался)
  • Restart=on-failure — автоматический перезапуск при падении

/etc/systemd/system/asterisk.service.d/override.conf — drop-in конфиг: дублирует RuntimeDirectory для надёжности.

Затем: systemctl daemon-reload → systemctl enable → systemctl start → ждёт 8 секунд → проверяет статус.


13. Итоговая сводка

Выводит полную информацию:

  • ОС, версия Asterisk, статус сервиса
  • Все директории (конфиги, логи, модули, звуки)
  • Команды управления (старт/стоп/перезапуск/CLI/логи)
  • Пути к основным конфигам (pjsip.conf, extensions.conf)
  • Следующие шаги для настройки

Сам скрипт:

Что делает скрипт удаления Asterisk

1. Проверки и инициализация

  • Проверяет запуск от root — иначе завершается с ошибкой
  • Выводит красный баннер со списком всего что будет удалено
  • Требует ввода yes (не просто y) для подтверждения — защита от случайного запуска

2. Остановка сервиса

  • Проверяет запущен ли сервис через systemctl is-active — если да, останавливает через systemctl stop
  • Проверяет включён ли автозапуск через systemctl is-enabled — если да, отключает через systemctl disable

3. Удаление через make uninstall

Ищет исходники Asterisk в /usr/src через find по наличию Makefile в директориях asterisk-*. Если найдены — запускает официальные команды:

  • make uninstall — удаляет бинарники и модули
  • make uninstall-all — удаляет также конфиги и звуковые файлы

Если исходники не найдены — переходит к ручному удалению файлов.


4. Удаление бинарников вручную

Удаляет конкретные исполняемые файлы если они существуют:

Файл Назначение
/usr/sbin/asterisk Основной бинарник
/usr/sbin/safe_asterisk Скрипт-обёртка для автоперезапуска
/usr/bin/astgenkey Генератор RSA ключей
/usr/bin/autosupport Утилита сбора диагностики
/usr/bin/rasterisk Клиент для подключения к CLI
/sbin/asterisk Симлинк (если есть)

5. Удаление директорий

Рекурсивно удаляет все директории Asterisk:

Директория Содержимое
/etc/asterisk Все конфигурационные файлы
/var/log/asterisk Логи (full, messages, cdr-csv)
/var/lib/asterisk Звуки, AGI скрипты, voicemail, ключи
/var/spool/asterisk Очереди, записи разговоров
/var/run/asterisk PID файл и сокет
/usr/lib/asterisk Все модули (.so файлы)
/usr/share/asterisk Документация и данные
/usr/include/asterisk Заголовочные файлы для разработки

6. Удаление исходников

Удаляет все директории по маске /usr/src/asterisk* — то есть все версии если их было несколько (например asterisk-20.19.0, asterisk-21.12.2).


7. Удаление systemd юнитов (три уровня)

Файлы юнитов — ищет и удаляет .service файлы во всех возможных путях: /etc/systemd/system/, /lib/systemd/system/, /usr/lib/systemd/system/, /run/systemd/system/, включая симлинки в multi-user.target.wants/.

Drop-in директории — удаляет папки asterisk.service.d во всех системных путях systemd (именно эту директорию с override.conf и нашли на сервере).

find по всем путям — на случай если остались любые другие файлы с именем asterisk в директориях systemd.

После удаления запускает:

  • systemctl daemon-reload — перечитывает конфигурацию
  • systemctl reset-failed — сбрасывает статус упавших юнитов из памяти systemd

8. Удаление init.d и logrotate

  • Удаляет /etc/init.d/asterisk если есть (для старых систем без systemd), убирает из автозапуска через update-rc.d
  • Удаляет /etc/logrotate.d/asterisk — правила ротации логов

9. Удаление cron заданий

Проверяет crontab root на наличие заданий связанных с asterisk — если есть, фильтрует их и сохраняет остальные задания.


10. Удаление пользователя и группы

  • userdel -r asterisk — удаляет пользователя вместе с домашней директорией (-r). Если не получается с флагом -r — пробует без него
  • groupdel asterisk — удаляет группу

11. Удаление apt-пакетов

Проверяет через dpkg -l | grep asterisk — были ли установлены пакеты Asterisk через apt (например если ставили asterisk из репозитория параллельно). Если найдены — удаляет через apt-get remove --purge.


12. Удаление зависимостей сборки (интерактивно)

Задаёт отдельный вопрос с предупреждением — так как эти пакеты могут использоваться другими программами. При согласии удаляет 24 пакета: build-essential, libssl-dev, libxml2-dev, sox, mpg123, autoconf, bison, flex и другие библиотеки. В конце запускает apt-get autoremove и autoclean.

При отказе всё равно запускает apt-get autoremove для очистки осиротевших зависимостей.


13. Финальная проверка

После удаления проверяет 4 условия:

  • Бинарник asterisk всё ещё доступен через which
  • Директория /etc/asterisk всё ещё существует
  • Директория /var/log/asterisk всё ещё существует
  • systemd всё ещё видит юнит asterisk
Если всё чисто — зелёный баннер "Asterisk полностью удалён". Если что-то осталось — жёлтый баннер с предупреждениями о том что именно не удалилось.

Сам скрипт Установки:

#!/usr/bin/env bash
# ============================================================
#  Asterisk — установка с выбором версии
#  ОС: Ubuntu 20.04/22.04/24.04 | Debian 10/11/12
# ============================================================

set -euo pipefail

# ─── Цвета ───────────────────────────────────────────────────
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
BLUE='\033[0;34m'; CYAN='\033[0;36m'; BOLD='\033[1m'; NC='\033[0m'

info()    { echo -e "${CYAN}[INFO]${NC} $*"; }
success() { echo -e "${GREEN}[OK]${NC}   $*"; }
warn()    { echo -e "${YELLOW}[WARN]${NC} $*"; }
error()   { echo -e "${RED}[ERR]${NC}  $*"; exit 1; }

# ─── Root check ──────────────────────────────────────────────
[[ $EUID -ne 0 ]] && error "Запустите от root: sudo bash $0"

# ─── Определяем ОС ───────────────────────────────────────────
[[ -f /etc/os-release ]] && source /etc/os-release \
  || error "Не удалось определить ОС."
[[ "$ID" == "ubuntu" || "$ID" == "debian" ]] \
  || error "Поддерживаются Ubuntu и Debian. Обнаружена: $ID"

# ─── Баннер ──────────────────────────────────────────────────
clear
echo ""
echo -e "${BLUE}${BOLD}╔══════════════════════════════════════════════════════════╗${NC}"
echo -e "${BLUE}${BOLD}║           Asterisk PBX  —  Установщик                   ║${NC}"
echo -e "${BLUE}${BOLD}╚══════════════════════════════════════════════════════════╝${NC}"
echo ""
echo -e "  ОС      : ${CYAN}${PRETTY_NAME}${NC}"
echo -e "  Arch    : ${CYAN}$(uname -m)${NC}"
echo ""

# ─── Выбор версии ────────────────────────────────────────────
echo -e "${BOLD}  Доступные версии Asterisk:${NC}"
echo ""
echo -e "  ${GREEN}1)${NC} Asterisk 20.19.0  ${YELLOW}[LTS]${NC}  — Long Term Support, до 2027"
echo -e "  ${GREEN}2)${NC} Asterisk 21.12.2  ${CYAN}[STA]${NC}  — Standard, стабильная"
echo -e "  ${GREEN}3)${NC} Asterisk 22.9.0   ${CYAN}[STA]${NC}  — Standard, новейшая"
echo -e "  ${GREEN}4)${NC} Asterisk 23.4.0   ${YELLOW}[DEV]${NC}  — Development, для тестов"
echo -e "  ${GREEN}5)${NC} Ввести свою версию"
echo ""

while true; do
  read -rp "$(echo -e ${BOLD}"  Выберите версию [1-5]: "${NC})" VERSION_CHOICE
  case "$VERSION_CHOICE" in
    1) AST_VERSION="20.19.0"; AST_BRANCH="20"; break ;;
    2) AST_VERSION="21.12.2"; AST_BRANCH="21"; break ;;
    3) AST_VERSION="22.9.0";  AST_BRANCH="22"; break ;;
    4) AST_VERSION="23.4.0";  AST_BRANCH="23"; break ;;
    5)
      read -rp "  Введите версию (например 20.19.0): " AST_VERSION
      AST_BRANCH=$(echo "$AST_VERSION" | cut -d. -f1)
      [[ -z "$AST_VERSION" ]] && { warn "Версия не может быть пустой."; continue; }
      break
      ;;
    *) warn "Введите число от 1 до 5." ;;
  esac
done

echo ""
info "Выбрана версия: Asterisk ${AST_VERSION}"

# ─── Подтверждение ───────────────────────────────────────────
read -rp "$(echo -e ${BOLD}"  Продолжить установку? [y/N]: "${NC})" CONFIRM
[[ "$CONFIRM" =~ ^[Yy]$ ]] || { echo "Отменено."; exit 0; }

# Отключаем set -e дальше — обрабатываем ошибки вручную
set +e

# ─── Переменные ──────────────────────────────────────────────
AST_USER="asterisk"
AST_DIR="/usr/src/asterisk"
AST_TAR="asterisk-${AST_VERSION}.tar.gz"
AST_URL="https://downloads.asterisk.org/pub/telephony/asterisk/releases/${AST_TAR}"
NPROC=$(nproc)

# ─── Зависимости ─────────────────────────────────────────────
echo ""
info "Обновление пакетов..."
apt-get update -qq || error "apt-get update завершился с ошибкой."

info "Установка зависимостей сборки..."
DEBIAN_FRONTEND=noninteractive apt-get install -y \
  build-essential curl wget git \
  libssl-dev libncurses5-dev libnewt-dev libxml2-dev \
  libsqlite3-dev uuid-dev libjansson-dev libedit-dev \
  libxslt1-dev pkg-config autoconf automake libtool \
  bison flex sox mpg123 libspeex-dev libspeexdsp-dev \
  libogg-dev libvorbis-dev libcurl4-openssl-dev \
  subversion unixodbc-dev libiksemel-dev \
  || error "Не удалось установить зависимости."

success "Зависимости установлены."

# ─── Скачивание исходников ────────────────────────────────────
echo ""
info "Скачивание Asterisk ${AST_VERSION}..."
mkdir -p "$AST_DIR"
cd "$AST_DIR"

if [[ -f "$AST_TAR" ]]; then
  info "Архив уже скачан, пропускаем."
else
  wget -q --show-progress "$AST_URL" -O "$AST_TAR"
  if [[ $? -ne 0 ]]; then
    rm -f "$AST_TAR"
    error "Не удалось скачать Asterisk ${AST_VERSION}. Проверьте версию на https://downloads.asterisk.org"
  fi
fi

info "Распаковка архива..."
tar -xzf "$AST_TAR" || error "Ошибка распаковки архива."

# Удаляем старую сборку если есть, чтобы не было конфликтов
BUILD_DIR="${AST_DIR}/asterisk-${AST_VERSION}"
cd "$BUILD_DIR" || error "Не удалось войти в директорию ${BUILD_DIR}"

success "Исходники распакованы."

# ─── Установка зависимостей через contrib скрипт ─────────────
echo ""
info "Установка дополнительных зависимостей через contrib/scripts..."
if [[ -f contrib/scripts/install_prereq ]]; then
  contrib/scripts/install_prereq install 2>&1 | grep -v "^$" || true
  success "Дополнительные зависимости установлены."
else
  warn "Скрипт install_prereq не найден — пропускаем."
fi

# ─── Загрузка mp3-кодека ─────────────────────────────────────
echo ""
info "Скачивание mp3-кодека..."
if [[ -f contrib/scripts/get_mp3_source.sh ]]; then
  contrib/scripts/get_mp3_source.sh 2>/dev/null || warn "mp3-кодек не скачан, продолжаем без него."
fi

# ─── Предварительное скачивание bundled-зависимостей ─────────
# Configure пытается скачать jansson и pjproject через wget во время
# сборки. На некоторых серверах wget не работает (нет TLS, прокси,
# и т.д.), хотя curl работает нормально. Решение: скачиваем заранее
# через curl и кладём в /tmp — configure найдёт файлы и не будет
# качать сам.
echo ""
info "Предварительное скачивание bundled-зависимостей (jansson, pjproject)..."

JANSSON_VER="2.14.1"
JANSSON_TAR="jansson-${JANSSON_VER}.tar.bz2"
JANSSON_URL="https://raw.githubusercontent.com/asterisk/third-party/master/jansson/${JANSSON_VER}/${JANSSON_TAR}"

PJPROJECT_VER="2.16"
PJPROJECT_TAR="pjproject-${PJPROJECT_VER}.tar.bz2"
PJPROJECT_URL="https://raw.githubusercontent.com/asterisk/third-party/master/pjproject/${PJPROJECT_VER}/${PJPROJECT_TAR}"

# Скачиваем jansson если ещё нет
if [[ ! -s "/tmp/${JANSSON_TAR}" ]]; then
  info "Скачивание ${JANSSON_TAR}..."
  curl -fsSL --retry 3 --retry-delay 2 -o "/tmp/${JANSSON_TAR}" "$JANSSON_URL" \
    && success "${JANSSON_TAR} скачан." \
    || warn "${JANSSON_TAR} не скачан — configure попробует сам."
else
  info "${JANSSON_TAR} уже есть в /tmp, пропускаем."
fi

# Скачиваем pjproject если ещё нет
if [[ ! -s "/tmp/${PJPROJECT_TAR}" ]]; then
  info "Скачивание ${PJPROJECT_TAR}..."
  curl -fsSL --retry 3 --retry-delay 2 -o "/tmp/${PJPROJECT_TAR}" "$PJPROJECT_URL" \
    && success "${PJPROJECT_TAR} скачан." \
    || warn "${PJPROJECT_TAR} не скачан — configure попробует сам."
else
  info "${PJPROJECT_TAR} уже есть в /tmp, пропускаем."
fi

# ─── Configure ───────────────────────────────────────────────
echo ""
info "Запуск ./configure (это займёт ~1 мин.)..."

./configure \
  --with-jansson-bundled \
  --with-pjproject-bundled \
  2>&1 | tail -10

CONFIGURE_RC=${PIPESTATUS[0]}

if [[ $CONFIGURE_RC -ne 0 ]]; then
  error "configure завершился с ошибкой (код ${CONFIGURE_RC}).\nЗапустите вручную для диагностики:\n  cd ${BUILD_DIR} && NOISY_BUILD=yes ./configure --with-jansson-bundled --with-pjproject-bundled"
fi

# Проверяем что makeopts создался — признак успешного configure
if [[ ! -f makeopts ]]; then
  error "configure завершился, но makeopts не создан.\nЗапустите вручную:\n  cd ${BUILD_DIR} && NOISY_BUILD=yes ./configure --with-jansson-bundled --with-pjproject-bundled"
fi

success "Configure завершён."

# ─── Выбор модулей menuselect ────────────────────────────────
echo ""
info "Генерация конфигурации модулей..."
make menuselect.makeopts
if [[ $? -ne 0 ]]; then
  warn "menuselect.makeopts не сгенерирован — продолжаем с дефолтными модулями."
else
  menuselect/menuselect \
    --enable format_mp3 \
    --enable res_snmp \
    --enable res_http_websocket \
    --enable codec_opus \
    --enable EXTRA-SOUNDS-EN-GSM \
    --enable EXTRA-SOUNDS-RU-GSM \
    --enable MOH-OPSOUND-GSM \
    menuselect.makeopts 2>/dev/null || true
  success "Модули настроены."
fi

# ─── Компиляция ──────────────────────────────────────────────
echo ""
info "Компиляция Asterisk (${NPROC} потоков)... Это займёт 5-15 минут."
make -j"$NPROC" 2>&1 | tee /tmp/asterisk_build.log | tail -5
if [[ ${PIPESTATUS[0]} -ne 0 ]]; then
  error "Компиляция завершилась с ошибкой. Лог: /tmp/asterisk_build.log\n  Последние строки:\n$(tail -20 /tmp/asterisk_build.log)"
fi
success "Компиляция завершена."

# ─── Установка ───────────────────────────────────────────────
echo ""
info "Установка бинарников..."
make install 2>&1 | tail -3
[[ ${PIPESTATUS[0]} -ne 0 ]] && error "make install завершился с ошибкой."

info "Установка конфигов (samples)..."
make samples 2>&1 | tail -3

info "Установка логротейта и init скриптов..."
make config 2>&1 | tail -3

ldconfig 2>/dev/null || true

# Проверяем что бинарник реально появился
if [[ ! -x /usr/sbin/asterisk ]]; then
  error "Бинарник /usr/sbin/asterisk не найден после установки."
fi

success "Asterisk ${AST_VERSION} установлен."

# ─── Создание пользователя asterisk ──────────────────────────
echo ""
info "Настройка системного пользователя..."
if ! id "$AST_USER" &>/dev/null; then
  useradd -r -d /var/lib/asterisk -s /usr/sbin/nologin "$AST_USER"
  success "Пользователь ${AST_USER} создан."
else
  success "Пользователь ${AST_USER} уже существует."
fi

# Создаём нужные директории
for DIR in /etc/asterisk /var/lib/asterisk /var/log/asterisk \
           /var/spool/asterisk /usr/lib/asterisk /var/run/asterisk; do
  mkdir -p "$DIR"
done

# Права на директории
chown -R "$AST_USER":"$AST_USER" \
  /etc/asterisk \
  /var/lib/asterisk \
  /var/log/asterisk \
  /var/spool/asterisk \
  /usr/lib/asterisk \
  /var/run/asterisk 2>/dev/null || true

chmod 750 /var/run/asterisk

# ─── Добавление root в группу asterisk ───────────────────────
echo ""
info "Добавление root в группу asterisk (для доступа к CLI)..."
usermod -aG "$AST_USER" root
success "root добавлен в группу asterisk."

# ─── Настройка asterisk.conf ─────────────────────────────────
info "Настройка asterisk.conf..."
AST_CONF="/etc/asterisk/asterisk.conf"
if [[ -f "$AST_CONF" ]]; then
  # Удаляем старые значения если есть
  sed -i '/^astctlpermissions/d; /^astctlgroup/d; /^runuser/d; /^rungroup/d' "$AST_CONF"
  # Вставляем в секцию [options]
  if grep -q '^\[options\]' "$AST_CONF"; then
    sed -i '/^\[options\]/a astctlpermissions = 0660\nastctlgroup = asterisk\nrunuser = asterisk\nrungroup = asterisk' "$AST_CONF"
  else
    printf '\n[options]\nrunuser = asterisk\nrungroup = asterisk\nastctlpermissions = 0660\nastctlgroup = asterisk\n' >> "$AST_CONF"
  fi
  success "asterisk.conf обновлён."
else
  warn "asterisk.conf не найден — пропускаем."
fi

# ─── Обёртка asterisk-cli для root без newgrp ────────────────
#
# Проблема: root добавлен в группу asterisk, но текущая сессия
# уже запущена — новая группа не активна до переlogина.
# Решение: скрипт-обёртка через 'sg asterisk' активирует группу
# без переlogина прямо сейчас.
#
info "Создание обёртки /usr/local/bin/ast для CLI из-под root..."
cat > /usr/local/bin/ast << 'WRAPPER'
#!/usr/bin/env bash
# Обёртка: запускает asterisk CLI с активной группой asterisk
# Работает сразу, без newgrp / переlogина
exec sg asterisk -c "asterisk -rvvv $*"
WRAPPER
chmod +x /usr/local/bin/ast
success "Обёртка создана: команда 'ast' запускает Asterisk CLI."

# Также добавляем /usr/sbin в PATH для текущей сессии (если ещё нет)
if ! grep -q '/usr/sbin' /root/.bashrc 2>/dev/null; then
  echo 'export PATH="/usr/sbin:$PATH"' >> /root/.bashrc
fi
# Добавляем в /etc/environment для надёжности
if ! grep -q '/usr/sbin' /etc/environment 2>/dev/null; then
  sed -i 's|PATH="\(.*\)"|PATH="/usr/sbin:\1"|' /etc/environment 2>/dev/null || true
fi

# ─── Настройка systemd ────────────────────────────────────────
echo ""
info "Настройка systemd сервиса..."

UNIT_FILE="/etc/systemd/system/asterisk.service"

cat > "$UNIT_FILE" << 'UNIT'
[Unit]
Description=Asterisk PBX and telephony daemon
After=network.target

[Service]
Type=simple
User=asterisk
Group=asterisk
Environment=HOME=/var/lib/asterisk

RuntimeDirectory=asterisk
RuntimeDirectoryMode=0750

ExecStart=/usr/sbin/asterisk -f -C /etc/asterisk/asterisk.conf
ExecReload=/usr/sbin/asterisk -rx "core reload"
ExecStop=/usr/sbin/asterisk -rx "core stop now"

Restart=on-failure
RestartSec=5
TimeoutStopSec=30

StandardOutput=journal
StandardError=journal
SyslogIdentifier=asterisk

[Install]
WantedBy=multi-user.target
UNIT

# Убираем старый drop-in если был, чтобы не было конфликтов
rm -rf /etc/systemd/system/asterisk.service.d 2>/dev/null || true

success "systemd unit настроен."

systemctl daemon-reload
systemctl enable asterisk &>/dev/null

info "Запуск Asterisk..."
systemctl start asterisk

info "Ожидание старта Asterisk (10 сек.)..."
sleep 10

AST_STATUS=$(systemctl is-active asterisk 2>/dev/null || echo "unknown")

if [[ "$AST_STATUS" == "active" ]]; then
  success "Asterisk запущен успешно."
else
  warn "Asterisk статус: ${AST_STATUS}"
  warn "Проверьте: journalctl -xeu asterisk.service | tail -30"
fi

# ─── Версия ──────────────────────────────────────────────────
INSTALLED_VER=$(sg asterisk -c "/usr/sbin/asterisk -V" 2>/dev/null | awk '{print $2}' || echo "$AST_VERSION")

# ─── Итоговая сводка ─────────────────────────────────────────
echo ""
echo -e "${GREEN}${BOLD}╔═══════════════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}${BOLD}║               ✅  Установка завершена!                    ║${NC}"
echo -e "${GREEN}${BOLD}╚═══════════════════════════════════════════════════════════╝${NC}"
echo ""
echo -e "${BOLD}   Система:${NC}"
echo -e "     ОС                  : ${CYAN}${PRETTY_NAME}${NC}"
echo -e "     Asterisk            : ${CYAN}${INSTALLED_VER}${NC}"
echo -e "     Статус сервиса      : ${CYAN}${AST_STATUS}${NC}"
echo -e "     Исходники           : ${CYAN}${AST_DIR}/asterisk-${AST_VERSION}${NC}"
echo ""
echo -e "${BOLD}   Директории:${NC}"
echo -e "     Конфиги             : ${CYAN}/etc/asterisk/${NC}"
echo -e "     Логи                : ${CYAN}/var/log/asterisk/${NC}"
echo -e "     Модули              : ${CYAN}/usr/lib/asterisk/modules/${NC}"
echo -e "     Звуки               : ${CYAN}/var/lib/asterisk/sounds/${NC}"
echo -e "     AGI скрипты         : ${CYAN}/var/lib/asterisk/agi-bin/${NC}"
echo ""
echo -e "${BOLD}    Управление:${NC}"
echo -e "     CLI (сразу, без переlogина) : ${CYAN}ast${NC}"
echo -e "     CLI (стандартный способ)    : ${CYAN}asterisk -rvvv${NC}  (после переlogина)"
echo -e "     Статус              : ${CYAN}systemctl status asterisk${NC}"
echo -e "     Старт               : ${CYAN}systemctl start asterisk${NC}"
echo -e "     Стоп                : ${CYAN}systemctl stop asterisk${NC}"
echo -e "     Перезапуск          : ${CYAN}systemctl restart asterisk${NC}"
echo -e "     Reload конфигов     : ${CYAN}asterisk -rx 'core reload'${NC}"
echo -e "     Логи                : ${CYAN}tail -f /var/log/asterisk/full${NC}"
echo -e "     Логи systemd        : ${CYAN}journalctl -fu asterisk${NC}"
echo ""
echo -e "${BOLD}   Конфигурационные файлы:${NC}"
echo -e "     SIP/PJSIP транки    : ${CYAN}/etc/asterisk/pjsip.conf${NC}"
echo -e "     Диалплан            : ${CYAN}/etc/asterisk/extensions.conf${NC}"
echo -e "     Voicemail           : ${CYAN}/etc/asterisk/voicemail.conf${NC}"
echo -e "     Очереди             : ${CYAN}/etc/asterisk/queues.conf${NC}"
echo ""
echo -e "${YELLOW}    Следующие шаги:${NC}"
echo -e "     1. Войдите в CLI прямо сейчас: ${CYAN}ast${NC}"
echo -e "     2. Настройте /etc/asterisk/pjsip.conf (транки, экстеншены)"
echo -e "     3. Настройте /etc/asterisk/extensions.conf (диалплан)"
echo -e "     4. Откройте порты: ${CYAN}ufw allow 5060/udp && ufw allow 10000:20000/udp${NC}"
echo ""
if [[ "$AST_STATUS" == "active" ]]; then
  echo -e "${GREEN}${BOLD}  ➜  Asterisk готов! Введите: ast${NC}"
fi
echo ""
Сам скрипт Удаления:

#!/usr/bin/env bash
# ============================================================
#  Asterisk — полное удаление со всеми зависимостями
#  ОС: Ubuntu 20.04/22.04/24.04 | Debian 10/11/12
# ============================================================

# ─── Цвета ───────────────────────────────────────────────────
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
BLUE='\033[0;34m'; CYAN='\033[0;36m'; BOLD='\033[1m'; NC='\033[0m'

info()    { echo -e "${CYAN}[INFO]${NC} $*"; }
success() { echo -e "${GREEN}[OK]${NC}   $*"; }
warn()    { echo -e "${YELLOW}[WARN]${NC} $*"; }
error()   { echo -e "${RED}[ERR]${NC}  $*"; exit 1; }
removed() { echo -e "${RED}[-]${NC}    $*"; }

# ─── Root check ──────────────────────────────────────────────
[[ $EUID -ne 0 ]] && error "Запустите от root: sudo bash $0"

# ─── Баннер ──────────────────────────────────────────────────
clear
echo ""
echo -e "${RED}${BOLD}╔══════════════════════════════════════════════════════════╗${NC}"
echo -e "${RED}${BOLD}║        Asterisk PBX  —  Полное удаление                 ║${NC}"
echo -e "${RED}${BOLD}╚══════════════════════════════════════════════════════════╝${NC}"
echo ""
echo -e "${YELLOW}    Будет удалено:${NC}"
echo -e "     • Сервис и бинарники Asterisk"
echo -e "     • Все конфигурационные файлы (/etc/asterisk)"
echo -e "     • Логи (/var/log/asterisk)"
echo -e "     • Данные (/var/lib/asterisk, /var/spool/asterisk)"
echo -e "     • Исходники (/usr/src/asterisk*)"
echo -e "     • Модули (/usr/lib/asterisk)"
echo -e "     • Пользователь и группа asterisk"
echo -e "     • Зависимости сборки (опционально)"
echo ""

# ─── Подтверждение ───────────────────────────────────────────
read -rp "$(echo -e ${RED}${BOLD}"  Вы уверены? Это действие необратимо! [yes/N]: "${NC})" CONFIRM
[[ "$CONFIRM" == "yes" ]] || { echo -e "\n  Отменено."; exit 0; }

echo ""

# ─── Остановка и отключение сервиса ──────────────────────────
info "Остановка сервиса Asterisk..."

if systemctl is-active --quiet asterisk 2>/dev/null; then
  systemctl stop asterisk
  removed "Сервис asterisk остановлен."
fi

if systemctl is-enabled --quiet asterisk 2>/dev/null; then
  systemctl disable asterisk
  removed "Автозапуск asterisk отключён."
fi

# ─── Удаление через make uninstall (если есть исходники) ─────
echo ""
info "Поиск исходников для make uninstall..."

AST_SRC=$(find /usr/src -maxdepth 2 -name "Makefile" -path "*/asterisk-*" 2>/dev/null \
  | head -1 | xargs -I{} dirname {} 2>/dev/null)

if [[ -n "$AST_SRC" && -f "$AST_SRC/Makefile" ]]; then
  info "Найдены исходники: $AST_SRC"
  cd "$AST_SRC"
  make uninstall        &>/dev/null && removed "make uninstall выполнен."
  make uninstall-all    &>/dev/null && removed "make uninstall-all выполнен." || true
  cd /
else
  warn "Исходники не найдены — удаляем файлы вручную."
fi

# ─── Удаление бинарников ─────────────────────────────────────
echo ""
info "Удаление бинарников..."

BINS=(
  /usr/sbin/asterisk
  /usr/sbin/safe_asterisk
  /usr/bin/astgenkey
  /usr/bin/autosupport
  /usr/bin/rasterisk
  /sbin/asterisk
)

for f in "${BINS[@]}"; do
  if [[ -f "$f" ]]; then
    rm -f "$f"
    removed "Удалён: $f"
  fi
done

# ─── Удаление директорий ─────────────────────────────────────
echo ""
info "Удаление директорий..."

DIRS=(
  /etc/asterisk
  /var/log/asterisk
  /var/lib/asterisk
  /var/spool/asterisk
  /var/run/asterisk
  /usr/lib/asterisk
  /usr/share/asterisk
  /usr/include/asterisk
  /usr/include/asterisk.h
)

for d in "${DIRS[@]}"; do
  if [[ -e "$d" ]]; then
    rm -rf "$d"
    removed "Удалено: $d"
  fi
done

# ─── Удаление исходников ─────────────────────────────────────
echo ""
info "Удаление исходников..."

for d in /usr/src/asterisk*; do
  if [[ -e "$d" ]]; then
    rm -rf "$d"
    removed "Удалено: $d"
  fi
done

# ─── Удаление systemd юнитов ─────────────────────────────────
echo ""
info "Удаление systemd юнитов..."

# Файлы юнитов
UNITS=(
  /etc/systemd/system/asterisk.service
  /lib/systemd/system/asterisk.service
  /usr/lib/systemd/system/asterisk.service
  /run/systemd/system/asterisk.service
  /etc/systemd/system/multi-user.target.wants/asterisk.service
  /lib/systemd/system/multi-user.target.wants/asterisk.service
)

for u in "${UNITS[@]}"; do
  if [[ -f "$u" ]]; then
    rm -f "$u"
    removed "Удалён: $u"
  fi
done

# Drop-in директории (asterisk.service.d)
DROPIN_DIRS=(
  /etc/systemd/system/asterisk.service.d
  /lib/systemd/system/asterisk.service.d
  /usr/lib/systemd/system/asterisk.service.d
  /run/systemd/system/asterisk.service.d
)

for d in "${DROPIN_DIRS[@]}"; do
  if [[ -d "$d" ]]; then
    rm -rf "$d"
    removed "Удалена drop-in директория: $d"
  fi
done

# Ищем любые оставшиеся файлы asterisk в systemd через find
while IFS= read -r f; do
  rm -f "$f"
  removed "Удалён (find): $f"
done < <(find /etc/systemd /lib/systemd /usr/lib/systemd /run/systemd \
  -iname "*asterisk*" 2>/dev/null)

systemctl daemon-reload
systemctl reset-failed 2>/dev/null || true
success "systemd обновлён."

# ─── Удаление init.d скриптов ────────────────────────────────
if [[ -f /etc/init.d/asterisk ]]; then
  update-rc.d asterisk remove &>/dev/null || true
  rm -f /etc/init.d/asterisk
  removed "Удалён: /etc/init.d/asterisk"
fi

# ─── Удаление logrotate ──────────────────────────────────────
if [[ -f /etc/logrotate.d/asterisk ]]; then
  rm -f /etc/logrotate.d/asterisk
  removed "Удалён: /etc/logrotate.d/asterisk"
fi

# ─── Удаление cron заданий ───────────────────────────────────
if crontab -l 2>/dev/null | grep -q asterisk; then
  crontab -l 2>/dev/null | grep -v asterisk | crontab -
  removed "Cron задания asterisk удалены."
fi

# ─── Удаление пользователя и группы ─────────────────────────
echo ""
info "Удаление пользователя и группы asterisk..."

if id asterisk &>/dev/null; then
  userdel -r asterisk 2>/dev/null || userdel asterisk 2>/dev/null || true
  removed "Пользователь asterisk удалён."
fi

if getent group asterisk &>/dev/null; then
  groupdel asterisk 2>/dev/null || true
  removed "Группа asterisk удалена."
fi

# ─── Удаление apt-пакетов если Asterisk был установлен через apt ─
echo ""
info "Проверка apt-пакетов Asterisk..."

APT_PKGS=$(dpkg -l | grep -i asterisk | awk '{print $2}' 2>/dev/null || true)
if [[ -n "$APT_PKGS" ]]; then
  info "Найдены apt-пакеты: $APT_PKGS"
  apt-get remove --purge -y $APT_PKGS &>/dev/null
  removed "apt-пакеты Asterisk удалены."
else
  info "apt-пакеты Asterisk не найдены."
fi

# ─── Удаление зависимостей сборки (опционально) ──────────────
echo ""
echo -e "${YELLOW}  Удалить зависимости сборки (build-essential, libssl-dev и др.)?${NC}"
echo -e "  ${YELLOW}  Осторожно: они могут использоваться другими программами!${NC}"
read -rp "$(echo -e ${BOLD}"  Удалить зависимости сборки? [y/N]: "${NC})" DEL_DEPS

if [[ "$DEL_DEPS" =~ ^[Yy]$ ]]; then
  info "Удаление зависимостей сборки..."

  BUILD_DEPS=(
    build-essential
    libssl-dev
    libncurses5-dev
    libnewt-dev
    libxml2-dev
    libsqlite3-dev
    uuid-dev
    libjansson-dev
    libedit-dev
    libxslt1-dev
    libspeex-dev
    libspeexdsp-dev
    libogg-dev
    libvorbis-dev
    libcurl4-openssl-dev
    subversion
    unixodbc-dev
    libiksemel-dev
    sox
    mpg123
    autoconf
    automake
    libtool
    bison
    flex
  )

  for pkg in "${BUILD_DEPS[@]}"; do
    if dpkg -l "$pkg" &>/dev/null 2>&1; then
      apt-get remove --purge -y "$pkg" &>/dev/null && \
        removed "Удалён пакет: $pkg" || true
    fi
  done

  info "Очистка неиспользуемых зависимостей..."
  apt-get autoremove -y &>/dev/null
  apt-get autoclean &>/dev/null
  success "Зависимости сборки удалены."
else
  info "Зависимости сборки сохранены."
  # Всё равно чистим autoremove без агрессивного удаления
  apt-get autoremove -y &>/dev/null || true
fi

# ─── Финальная проверка ───────────────────────────────────────
echo ""
info "Финальная проверка..."

LEFTOVER=0

if command -v asterisk &>/dev/null; then
  warn "asterisk бинарник всё ещё найден: $(which asterisk)"
  LEFTOVER=1
fi

if [[ -d /etc/asterisk ]]; then
  warn "/etc/asterisk всё ещё существует"
  LEFTOVER=1
fi

if [[ -d /var/log/asterisk ]]; then
  warn "/var/log/asterisk всё ещё существует"
  LEFTOVER=1
fi

if systemctl list-units --all 2>/dev/null | grep -q asterisk; then
  warn "systemd юнит asterisk всё ещё виден"
  LEFTOVER=1
fi

# ─── Итог ────────────────────────────────────────────────────
echo ""
if [[ $LEFTOVER -eq 0 ]]; then
  echo -e "${GREEN}${BOLD}╔═══════════════════════════════════════════════════════════╗${NC}"
  echo -e "${GREEN}${BOLD}║             Asterisk полностью удалён!                  ║${NC}"
  echo -e "${GREEN}${BOLD}╚═══════════════════════════════════════════════════════════╝${NC}"
else
  echo -e "${YELLOW}${BOLD}╔═══════════════════════════════════════════════════════════╗${NC}"
  echo -e "${YELLOW}${BOLD}║        Удаление завершено с предупреждениями            ║${NC}"
  echo -e "${YELLOW}${BOLD}╚═══════════════════════════════════════════════════════════╝${NC}"
fi
echo ""
echo -e "${BOLD}  Что было удалено:${NC}"
echo -e "     • Сервис и бинарники Asterisk"
echo -e "     • /etc/asterisk  /var/log/asterisk  /var/lib/asterisk"
echo -e "     • /var/spool/asterisk  /usr/lib/asterisk  /usr/src/asterisk*"
echo -e "     • systemd юниты и init.d скрипты"
echo -e "     • Пользователь и группа asterisk"
[[ "$DEL_DEPS" =~ ^[Yy]$ ]] && \
  echo -e "     • Зависимости сборки"
echo ""

💬 Обсуждение и вопросы

Комментарии и обсуждение — на интерактивной версии статьи.

Перейти к обсуждению →