#!/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 # 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 # Asterisk et banques de sons françaises apt-get install -y --no-install-recommends \ asterisk \ asterisk-core-sounds-fr-wav \ asterisk-core-sounds-fr-g722 \ asterisk-sounds-main || 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 # 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 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 des dossiers nécessaires 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/nexus-pbx # 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" chown -R asterisk:asterisk /etc/asterisk /var/lib/asterisk /var/spool/asterisk /var/log/asterisk chmod 2775 /etc/asterisk chmod 2750 /etc/asterisk/keys # 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, /var/www/nexus-pbx/scripts/nexus-firewall, /usr/bin/certbot, /usr/sbin/nft, /usr/sbin/iptables EOF chmod 0440 /etc/sudoers.d/nexus-pbx # 5. Configuration d'Asterisk & Certificats TLS de secours echo -e "${C_GREEN}[4/8] Configuration du moteur Asterisk PJSIP & AMI...${C_RESET}" # AMI Manager 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 read = all write = all EOF chown asterisk:asterisk /etc/asterisk/manager.conf chmod 0640 /etc/asterisk/manager.conf # 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/* chmod 0640 /etc/asterisk/keys/* # Inclusions custom dans Asterisk touch /etc/asterisk/pjsip.custom.conf /etc/asterisk/extensions.custom.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 asterisk:asterisk /etc/asterisk/pjsip* /etc/asterisk/extensions* chmod 0664 /etc/asterisk/pjsip.conf /etc/asterisk/extensions.conf 2>/dev/null || true chmod 0660 /etc/asterisk/*.custom.conf 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 App\ConfigGenerator::generateAndApply($db); // 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 # 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)); ' rm -f /etc/nginx/sites-enabled/default ln -sf /etc/nginx/sites-available/nexus-pbx /etc/nginx/sites-enabled/nexus-pbx # Filtre Fail2ban Asterisk cat << 'EOF' > /etc/fail2ban/filter.d/asterisk.conf [Definition] failregex = ^(%(__prefix_line)s|\[\]\s*)*(?:NOTICE|SECURITY)\[\d+\]:? (?:\S+: )?(?:Registration from |Call from |Invalid password for |Sending fake auth challenge to |No matching endpoint found for )?'?(?::\d+)?'? ^(%(__prefix_line)s|\[\]\s*)*SECURITY\[\d+\]:? (?:\S+: )?SecurityEvent="(?:FailedACL|InvalidAccountID|ChallengeResponseFailed|InvalidPassword|AuthFailed)"(?:.*?)RemoteAddress="IPV[46]/(?:UDP|TCP|TLS)//\d+" ignoreregex = EOF # Jails Fail2ban cat << 'EOF' > /etc/fail2ban/jail.local [DEFAULT] bantime = 3600 findtime = 600 maxretry = 3 ignoreip = 127.0.0.1/8 ::1 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 [asterisk] enabled = true port = 5060,5061 protocol = udp filter = asterisk logpath = /var/log/asterisk/messages action = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] maxretry = 3 bantime = 3600 [nginx-http-auth] enabled = true port = http,https,8443 logpath = /var/log/nginx/*error.log maxretry = 5 bantime = 3600 EOF # 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" 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 # 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 PHP_SVC=$(systemctl list-unit-files --type=service | grep -E "php.*-fpm" | awk '{print $1}' | head -n 1 || echo "php8.4-fpm") systemctl restart "$PHP_SVC" && systemctl enable "$PHP_SVC" # Redémarrage Asterisk, Nginx, Fail2ban, Cron systemctl restart asterisk && systemctl enable asterisk nginx -t && systemctl restart nginx && systemctl enable nginx systemctl restart fail2ban && systemctl enable fail2ban systemctl restart cron && systemctl enable cron # Exécution immédiate de la bannière console clear || true /usr/local/bin/nexus-banner