#!/usr/bin/env bash # ============================================================================== # NexusPBX - Script d'Installation & Configuration Tout-en-Un (Debian / Ubuntu) # ============================================================================== # Utilisation rapide sur une machine vierge : # bash <(curl -sSL https://git.sorcier-research.com/sorcier/NexusPBX/raw/branch/main/install.sh) # Ou après clonage : # cd /var/www/nexus-pbx && bash install.sh # ============================================================================== set -euo pipefail # Couleurs pour l'affichage de l'installation C_GREEN="\033[1;32m" C_CYAN="\033[1;36m" C_YELLOW="\033[1;33m" C_RED="\033[1;31m" C_RESET="\033[0m" echo -e "${C_CYAN}" cat << "BANNER" _ _ ____ ______ __ __ | \ | | _____ ___ _ ___ | _ \| __ ) \ \/ / | \| |/ _ \ \/ / | | / __| | |_) | _ \ \ / | |\ | __/> <| |_| \__ \ | __/| |_) | / \ |_| \_|\___/_/\_\\__,_|___/ |_| |____/ /_/\_\ Installation & Déploiement Automatisé BANNER echo -e "${C_RESET}" # 1. Vérification des droits root if [ "$(id -u)" -ne 0 ]; then echo -e "${C_RED}[ERREUR] Ce script d'installation doit être exécuté en tant que root (sudo).${C_RESET}" exit 1 fi export DEBIAN_FRONTEND=noninteractive # Pré-configuration debconf pour iptables-persistent (évite tout blocage interactif) echo "iptables-persistent iptables-persistent/autosave_v4 boolean true" | debconf-set-selections 2>/dev/null || true echo "iptables-persistent iptables-persistent/autosave_v6 boolean true" | debconf-set-selections 2>/dev/null || true # 2. Mise à jour des dépôts APT et installation des dépendances système echo -e "${C_GREEN}[1/8] Mise à jour des paquets et installation des dépendances...${C_RESET}" apt-get update -y # Outils système essentiels apt-get install -y --no-install-recommends \ curl \ wget \ git \ sudo \ sqlite3 \ cron \ net-tools \ openssl \ ca-certificates \ iptables \ iptables-persistent \ acl \ ffmpeg \ rsync \ sox \ sshpass # Vérification et installation d'Asterisk echo -e "${C_GREEN} -> Installation du moteur Asterisk PBX...${C_RESET}" if ! apt-cache policy asterisk 2>/dev/null | grep -q "Candidate: [0-9]"; then echo -e "${C_YELLOW} -> Configuration du canal Debian pour le paquet Asterisk...${C_RESET}" echo "deb http://deb.debian.org/debian sid main" > /etc/apt/sources.list.d/debian-asterisk.list cat << 'EOF' > /etc/apt/preferences.d/asterisk Package: asterisk* libasterisk* Pin: release a=sid Pin-Priority: 990 Package: * Pin: release a=sid Pin-Priority: 100 EOF apt-get update -y fi if ! apt-get install -y asterisk; then echo -e "${C_YELLOW} -> Installation directe via le canal Sid (-t sid)...${C_RESET}" echo "deb http://deb.debian.org/debian sid main" > /etc/apt/sources.list.d/debian-asterisk.list apt-get update -y apt-get install -y -t sid asterisk fi # Sons Asterisk en français (exacts de la machine de dev) apt-get install -y asterisk-core-sounds-fr asterisk-core-sounds-fr-wav asterisk-core-sounds-fr-gsm 2>/dev/null || true # Nginx, PHP-FPM et extensions requises apt-get install -y --no-install-recommends \ nginx \ php-fpm \ php-sqlite3 \ php-curl \ php-xml \ php-mbstring \ php-zip \ php-cli # Sécurité (Fail2ban & Certbot) apt-get install -y --no-install-recommends \ fail2ban \ certbot \ python3-certbot-nginx # Création défensive et garantie des groupes et utilisateurs système if ! getent group asterisk >/dev/null 2>&1; then groupadd -r asterisk fi if ! getent passwd asterisk >/dev/null 2>&1; then useradd -r -g asterisk -d /var/lib/asterisk -s /usr/sbin/nologin asterisk fi if ! getent group www-data >/dev/null 2>&1; then groupadd -r www-data fi if ! getent passwd www-data >/dev/null 2>&1; then useradd -r -g www-data -d /var/www -s /usr/sbin/nologin www-data fi # 3. Déploiement / Clonage du code source NexusPBX echo -e "${C_GREEN}[2/8] Préparation et déploiement des fichiers NexusPBX...${C_RESET}" TARGET_DIR="/var/www/nexus-pbx" if [ -d "$TARGET_DIR/.git" ]; then echo " -> Dépôt NexusPBX déjà présent dans $TARGET_DIR, mise à jour..." cd "$TARGET_DIR" git config --global --add safe.directory "$TARGET_DIR" 2>/dev/null || true git pull origin main 2>/dev/null || true elif [ -d "$PWD/public" ] && [ -d "$PWD/src" ]; then echo " -> Exécution depuis le dossier source, synchronisation vers $TARGET_DIR..." if [ "$PWD" != "$TARGET_DIR" ]; then mkdir -p "$TARGET_DIR" cp -a . "$TARGET_DIR/" cd "$TARGET_DIR" fi else echo " -> Clonage du dépôt public officiel depuis https://git.sorcier-research.com..." rm -rf "$TARGET_DIR" git clone https://git.sorcier-research.com/sorcier/NexusPBX.git "$TARGET_DIR" cd "$TARGET_DIR" fi # 4. Configuration des utilisateurs, groupes et arborescence de stockage echo -e "${C_GREEN}[3/8] Configuration des permissions et de l'arborescence...${C_RESET}" usermod -aG asterisk www-data 2>/dev/null || true usermod -aG www-data asterisk 2>/dev/null || true # Création de l'ensemble des répertoires requis mkdir -p "$TARGET_DIR/storage/backups" mkdir -p "$TARGET_DIR/storage/system_backups" mkdir -p "$TARGET_DIR/storage/sounds" mkdir -p "$TARGET_DIR/public/avatars" mkdir -p /etc/asterisk/keys mkdir -p /var/lib/asterisk/sounds/custom mkdir -p /var/spool/asterisk/voicemail/default mkdir -p /var/log/asterisk mkdir -p /var/log/nexus-pbx touch /var/log/asterisk/messages /var/log/asterisk/security.log chown asterisk:asterisk /var/log/asterisk/messages /var/log/asterisk/security.log 2>/dev/null || true chmod 0664 /var/log/asterisk/messages /var/log/asterisk/security.log 2>/dev/null || true touch /var/log/nexus_security.log chown www-data:asterisk /var/log/nexus_security.log 2>/dev/null || true chmod 0664 /var/log/nexus_security.log 2>/dev/null || true # Droits applicatifs stricts chown -R www-data:asterisk "$TARGET_DIR" chmod 2775 "$TARGET_DIR/storage" \ "$TARGET_DIR/storage/backups" \ "$TARGET_DIR/storage/system_backups" \ "$TARGET_DIR/storage/sounds" \ "$TARGET_DIR/public/avatars" mkdir -p /var/lib/asterisk/sounds/custom /var/lib/asterisk/moh /var/spool/asterisk/voicemail chown -R asterisk:asterisk /etc/asterisk /var/lib/asterisk /var/spool/asterisk /var/log/asterisk chmod -R 775 /etc/asterisk /var/lib/asterisk/sounds /var/lib/asterisk/moh /var/spool/asterisk chmod 2775 /etc/asterisk /var/lib/asterisk/sounds /var/lib/asterisk/sounds/custom /var/lib/asterisk/moh /var/spool/asterisk chmod 2750 /etc/asterisk/keys setfacl -R -m u:www-data:rwx,g:asterisk:rwx /etc/asterisk /var/lib/asterisk/sounds /var/lib/asterisk/moh /var/spool/asterisk 2>/dev/null || true setfacl -R -d -m u:www-data:rwx,g:asterisk:rwx /etc/asterisk /var/lib/asterisk/sounds /var/lib/asterisk/moh /var/spool/asterisk 2>/dev/null || true # Droits sudoers pour l'interface web (www-data) cat << 'EOF' > /etc/sudoers.d/nexus-pbx # Privilèges spécifiques NexusPBX pour l'utilisateur Web www-data www-data ALL=(ALL) NOPASSWD: /usr/sbin/asterisk, /usr/sbin/nginx, /usr/bin/systemctl, /usr/bin/fail2ban-client, /bin/fail2ban-client, /var/www/nexus-pbx/scripts/nexus-firewall, /usr/bin/certbot, /usr/sbin/nft, /usr/sbin/iptables, /var/www/nexus-pbx/scripts/update.sh, /usr/local/bin/nexus-update EOF chmod 0440 /etc/sudoers.d/nexus-pbx # Autorisation d'écriture systemd pour PHP-FPM (Debian 12/13 ProtectSystem=full) for fpm_svc in /lib/systemd/system/php*-fpm.service /usr/lib/systemd/system/php*-fpm.service; do if [ -f "$fpm_svc" ]; then svc_name=$(basename "$fpm_svc") mkdir -p "/etc/systemd/system/${svc_name}.d" cat << 'EOF_OVERRIDE' > "/etc/systemd/system/${svc_name}.d/override.conf" [Service] ReadWritePaths=/etc/asterisk /etc/fail2ban /etc/nginx /var/log /var/lib/asterisk /var/spool/asterisk EOF_OVERRIDE fi done systemctl daemon-reload # Configuration des limites d'upload PHP (Restauration d'archives 512 Mo & Sons volumineux) for php_dir in /etc/php/*; do if [ -d "$php_dir/fpm/conf.d" ]; then cat << 'EOF_PHP' > "$php_dir/fpm/conf.d/99-nexus.ini" upload_max_filesize = 512M post_max_size = 512M memory_limit = 512M max_execution_time = 300 max_input_time = 300 EOF_PHP fi if [ -d "$php_dir/cli/conf.d" ]; then cat << 'EOF_PHP' > "$php_dir/cli/conf.d/99-nexus.ini" upload_max_filesize = 512M post_max_size = 512M memory_limit = 512M max_execution_time = 300 max_input_time = 300 EOF_PHP fi done # 5. Configuration d'Asterisk & Certificats TLS de secours echo -e "${C_GREEN}[4/8] Configuration du moteur Asterisk PJSIP & AMI...${C_RESET}" # AMI Manager (/etc/asterisk/manager.conf) cat << 'EOF' > /etc/asterisk/manager.conf [general] enabled = yes port = 5038 bindaddr = 127.0.0.1 displayconnects = no timestampevents = yes [pbxgui] secret = AsteriskAmi2026! deny = 0.0.0.0/0.0.0.0 permit = 127.0.0.1/255.255.255.0 permit = 127.0.0.1/32 permit = ::1/128 read = all write = all EOF chown asterisk:asterisk /etc/asterisk/manager.conf chmod 0640 /etc/asterisk/manager.conf # Fichier de logs pour Fail2ban cat << 'EOF' > /etc/asterisk/logger.conf [general] dateformat=%F %T [logfiles] console => notice,warning,error messages => notice,warning,error,security security.log => security EOF chown asterisk:asterisk /etc/asterisk/logger.conf 2>/dev/null || true chmod 0664 /etc/asterisk/logger.conf 2>/dev/null || true # Certificat TLS auto-signé initial pour PJSIP TLS (port 5061) et Nginx HTTPS (port 8443) if [ ! -f /etc/asterisk/keys/asterisk.crt ] || [ ! -f /etc/asterisk/keys/asterisk.key ]; then openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \ -keyout /etc/asterisk/keys/asterisk.key \ -out /etc/asterisk/keys/asterisk.crt \ -subj "/C=FR/ST=IDF/L=Paris/O=NexusPBX/CN=pbx.local" 2>/dev/null fi if [ ! -f /etc/asterisk/keys/active_cert.crt ]; then cp -f /etc/asterisk/keys/asterisk.crt /etc/asterisk/keys/active_cert.crt cp -f /etc/asterisk/keys/asterisk.key /etc/asterisk/keys/active_key.key fi chown asterisk:asterisk /etc/asterisk/keys/* 2>/dev/null || true chmod 0640 /etc/asterisk/keys/* 2>/dev/null || true # Inclusions custom dans Asterisk & initialisation des fichiers cibles touch /etc/asterisk/pjsip.conf \ /etc/asterisk/pjsip.custom.conf \ /etc/asterisk/extensions.conf \ /etc/asterisk/extensions.custom.conf \ /etc/asterisk/musiconhold.custom.conf \ /etc/asterisk/voicemail.custom.conf \ /etc/asterisk/rtp.conf \ /etc/asterisk/features.conf if ! grep -q 'pjsip.custom.conf' /etc/asterisk/pjsip.conf 2>/dev/null; then printf '\n#tryinclude "pjsip.custom.conf"\n' >> /etc/asterisk/pjsip.conf fi if ! grep -q 'extensions.custom.conf' /etc/asterisk/extensions.conf 2>/dev/null; then printf '\n#tryinclude "extensions.custom.conf"\n' >> /etc/asterisk/extensions.conf fi chown -R asterisk:asterisk /etc/asterisk chmod 0664 /etc/asterisk/*.conf /etc/asterisk/*.custom.conf 2>/dev/null || true chmod 2750 /etc/asterisk/keys chmod 2775 /etc/asterisk setfacl -R -m u:www-data:rwx,g:asterisk:rwx /etc/asterisk 2>/dev/null || true setfacl -R -d -m u:www-data:rwx,g:asterisk:rwx /etc/asterisk 2>/dev/null || true # Rechargement Asterisk immédiat pour appliquer AMI et Logger asterisk -rx "core reload" 2>/dev/null || true asterisk -rx "manager reload" 2>/dev/null || true # 6. Initialisation de la Base de données SQLite & Configuration initiale echo -e "${C_GREEN}[5/8] Initialisation de la base SQLite et configuration NexusPBX...${C_RESET}" php -r ' require_once "/var/www/nexus-pbx/src/Database.php"; require_once "/var/www/nexus-pbx/src/ConfigGenerator.php"; require_once "/var/www/nexus-pbx/src/PhonebookManager.php"; require_once "/var/www/nexus-pbx/src/FirewallManager.php"; $db = App\Database::getConnection(); // Détection de l interface et du sous-réseau local primaire $localNet = "192.168.1.0/24"; $ipOut = shell_exec("ip -o -4 route show to default 2>/dev/null | awk \"{print \\\$5}\""); $dev = trim((string)$ipOut); if ($dev !== "") { $cidrOut = shell_exec("ip -o -4 addr show dev " . escapeshellarg($dev) . " | awk \"{print \\\$4}\" | head -n 1"); $cidr = trim((string)$cidrOut); if ($cidr !== "") { $parts = explode("/", $cidr); $ip = $parts[0] ?? ""; $mask = (int)($parts[1] ?? 24); if ($mask >= 16 && $mask <= 24) { $longIp = ip2long($ip); $longMask = ~((1 << (32 - $mask)) - 1); $netIp = long2ip($longIp & $longMask); $localNet = "{$netIp}/{$mask}"; } } } // Mise à jour sécurisée des paramètres initiaux $st = $db->query("SELECT * FROM settings WHERE id = 1")->fetch(PDO::FETCH_ASSOC); if ($st) { $db->prepare("UPDATE settings SET local_net = :net, local_networks_json = :nets WHERE id = 1")->execute([ ":net" => $localNet, ":nets" => json_encode([$localNet, "127.0.0.1/32"]), ]); } // Génération initiale de pjsip.conf et extensions.conf $generator = new App\ConfigGenerator($db); $generator->writeAllConfigs(); // Initialisation de l annuaire et synchronisation App\PhonebookManager::initDirectory(); App\PhonebookManager::syncExtensions($db); ' chown -R www-data:asterisk "$TARGET_DIR/storage" chmod 0660 "$TARGET_DIR"/storage/*.sqlite* 2>/dev/null || true # 7. Configuration de Nginx et Fail2ban echo -e "${C_GREEN}[6/8] Configuration du serveur Web Nginx et de Fail2ban...${C_RESET}" # Détection de la socket PHP-FPM PHP_SOCK=$(find /run/php/ -name "php*-fpm.sock" 2>/dev/null | head -n 1) if [ -z "$PHP_SOCK" ]; then PHP_SOCK="/run/php/php8.4-fpm.sock" fi # Préparation des répertoires Nginx et activation de nexus-pbx mkdir -p /etc/nginx/sites-available /etc/nginx/sites-enabled rm -f /etc/nginx/sites-enabled/default ln -sf /etc/nginx/sites-available/nexus-pbx /etc/nginx/sites-enabled/nexus-pbx # Application de la configuration Nginx complète (Ports 80, 8080, 8443) php -r ' require_once "/var/www/nexus-pbx/src/Database.php"; require_once "/var/www/nexus-pbx/src/FirewallManager.php"; $db = App\Database::getConnection(); $st = $db->query("SELECT admin_https_port, certbot_strict_port80 FROM settings WHERE id = 1")->fetch(PDO::FETCH_ASSOC); App\FirewallManager::applyNginxConfig((int)($st["admin_https_port"] ?? 8443), (int)($st["certbot_strict_port80"] ?? 0)); ' # Filtre Fail2ban pour l'interface Nexus-Web cat << 'EOF' > /etc/fail2ban/filter.d/nexus-web.conf [Definition] failregex = ^.*\[NEXUS-WEB-AUTH-FAIL\]:\s*.*$ ignoreregex = EOF chmod 0644 /etc/fail2ban/filter.d/nexus-web.conf # Génération automatique et centralisée de /etc/fail2ban/jail.local (Source unique FirewallManager) php -r ' require_once "/var/www/nexus-pbx/src/Database.php"; require_once "/var/www/nexus-pbx/src/FirewallManager.php"; $st = App\FirewallManager::getSettings(); App\FirewallManager::generateJailLocal( $st["fail2ban_whitelist_ips"], (int)$st["fail2ban_sip_maxretry"], (int)$st["fail2ban_sip_findtime"], (int)$st["fail2ban_sip_bantime"], (int)$st["fail2ban_web_maxretry"], (int)$st["fail2ban_web_bantime"], (int)$st["admin_https_port"] ); ' chown root:asterisk /etc/fail2ban/jail.local chmod 0664 /etc/fail2ban/jail.local setfacl -m u:www-data:rw /etc/fail2ban/jail.local 2>/dev/null || true chown root:asterisk /etc/nginx/sites-available/nexus-pbx chmod 0664 /etc/nginx/sites-available/nexus-pbx setfacl -m u:www-data:rw /etc/nginx/sites-available/nexus-pbx 2>/dev/null || true # 8. Crontab & Bannière d'accueil Console (Style FreePBX) echo -e "${C_GREEN}[7/8] Mise en place des tâches programmées et de la bannière console...${C_RESET}" # Cron sauvegarde automatique toutes les 10 minutes cat << 'EOF' > /etc/cron.d/nexus-backup # Sauvegardes programmées automatiques NexusPBX */10 * * * * www-data /usr/bin/php /var/www/nexus-pbx/scripts/nexus_autobackup.php >> /var/log/nexus_backup.log 2>&1 EOF chmod 0644 /etc/cron.d/nexus-backup touch /var/log/nexus_backup.log && chown www-data:asterisk /var/log/nexus_backup.log && chmod 664 /var/log/nexus_backup.log # CLI symlinks chmod +x "$TARGET_DIR/scripts/nexus-firewall" "$TARGET_DIR/scripts/nexus-banner.sh" "$TARGET_DIR/scripts/update.sh" ln -sf "$TARGET_DIR/scripts/nexus-firewall" /usr/local/bin/nexus-firewall ln -sf "$TARGET_DIR/scripts/nexus-banner.sh" /usr/local/bin/nexus-banner ln -sf "$TARGET_DIR/scripts/update.sh" /usr/local/bin/nexus-update # Bannière interactive lors de chaque connexion terminal (SSH / Console) cat << 'EOF' > /etc/profile.d/nexus-motd.sh #!/bin/sh if [ -x /usr/local/bin/nexus-banner ]; then /usr/local/bin/nexus-banner fi EOF chmod +x /etc/profile.d/nexus-motd.sh # 9. Activation et redémarrage de tous les services echo -e "${C_GREEN}[8/8] Démarrage et activation des services système...${C_RESET}" systemctl daemon-reload # Redémarrage PHP-FPM (rechargement de l'appartenance au groupe asterisk) systemctl restart php*-fpm 2>/dev/null || true PHP_SVC=$(systemctl list-unit-files --type=service 2>/dev/null | grep -E "php.*-fpm" | awk '{print $1}' | head -n 1 || echo "php8.4-fpm") systemctl restart "$PHP_SVC" 2>/dev/null || true systemctl enable "$PHP_SVC" 2>/dev/null || true # Redémarrage Asterisk, Nginx, Fail2ban, Cron systemctl restart asterisk && systemctl enable asterisk systemctl restart fail2ban && systemctl enable fail2ban nginx -t && systemctl restart nginx && systemctl enable nginx systemctl restart cron && systemctl enable cron # Exécution immédiate de la bannière console clear || true /usr/local/bin/nexus-banner --force || true