diff --git a/cyberpanel.sh b/cyberpanel.sh index a71c20ce9..e9f9c6168 100644 --- a/cyberpanel.sh +++ b/cyberpanel.sh @@ -253,16 +253,30 @@ log_function_end "Set_Default_Variables" install_package() { local package="$1" case "$Server_OS" in - "CentOS"|"openEuler") - if [[ "$Server_OS_Version" -ge 8 ]]; then - dnf install -y "$package" - else - yum install -y "$package" - fi + "CentOS7") + yum install -y "$package" ;; - "Ubuntu") + "CentOS8"|"CentOS9"|"CentOSStream8"|"CentOSStream9"|"RHEL8"|"RHEL9"|"AlmaLinux8"|"AlmaLinux9"|"AlmaLinux10"|"RockyLinux8"|"RockyLinux9") + dnf install -y "$package" + ;; + "CloudLinux7"|"CloudLinux8"|"CloudLinux9") + yum install -y "$package" + ;; + "Ubuntu1804"|"Ubuntu2004"|"Ubuntu2010"|"Ubuntu2204"|"Ubuntu2404"|"Ubuntu24043"|"Debian11"|"Debian12"|"Debian13") DEBIAN_FRONTEND=noninteractive apt install -y "$package" ;; + "openEuler2003"|"openEuler2203"|"openEuler2403") + dnf install -y "$package" + ;; + *) + echo -e "Unknown OS: $Server_OS, attempting package installation..." + # Try different package managers in order of likelihood + if [[ "$Server_OS" =~ ^(CentOS|RHEL|AlmaLinux|RockyLinux|CloudLinux|openEuler) ]]; then + dnf install -y "$package" 2>/dev/null || yum install -y "$package" 2>/dev/null || echo -e "Failed to install $package" + else + DEBIAN_FRONTEND=noninteractive apt install -y "$package" 2>/dev/null || echo -e "Failed to install $package" + fi + ;; esac } @@ -270,19 +284,54 @@ install_package() { manage_service() { local service="$1" local action="$2" + + # Check if service exists before trying to manage it + if ! systemctl list-unit-files | grep -q "${service}.service"; then + echo -e "Service $service not found, skipping $action" + return 0 + fi + + # Handle platform-specific service names + case "$service" in + "pdns") + if [[ "$Server_OS" =~ ^(Ubuntu|Debian) ]]; then + service="pdns-server" + fi + ;; + "pure-ftpd") + if [[ "$Server_OS" =~ ^(Ubuntu|Debian) ]]; then + service="pure-ftpd" + elif [[ "$Server_OS" =~ ^(CentOS|AlmaLinux|RockyLinux|RHEL|CloudLinux) ]]; then + service="pure-ftpd" + fi + ;; + esac + systemctl "$action" "$service" } # Helper Function for Development Tools Installation install_dev_tools() { case "$Server_OS" in - "CentOS"|"openEuler") + "CentOS7"|"CloudLinux7"|"CloudLinux8"|"CloudLinux9") yum groupinstall "Development Tools" -y yum install autoconf automake zlib-devel openssl-devel expat-devel pcre-devel libmemcached-devel cyrus-sasl* -y ;; - "Ubuntu") + "CentOS8"|"CentOS9"|"CentOSStream8"|"CentOSStream9"|"RHEL8"|"RHEL9"|"AlmaLinux8"|"AlmaLinux9"|"AlmaLinux10"|"RockyLinux8"|"RockyLinux9"|"openEuler2003"|"openEuler2203"|"openEuler2403") + dnf groupinstall "Development Tools" -y + dnf install autoconf automake zlib-devel openssl-devel expat-devel pcre-devel libmemcached-devel cyrus-sasl* -y + ;; + "Ubuntu1804"|"Ubuntu2004"|"Ubuntu2010"|"Ubuntu2204"|"Ubuntu2404"|"Ubuntu24043"|"Debian11"|"Debian12"|"Debian13") DEBIAN_FRONTEND=noninteractive apt install build-essential zlib1g-dev libexpat1-dev openssl libssl-dev libsasl2-dev libpcre3-dev git -y ;; + *) + echo -e "Unknown OS: $Server_OS, attempting to install development tools..." + if [[ "$Server_OS" =~ ^(CentOS|RHEL|AlmaLinux|RockyLinux|CloudLinux|openEuler) ]]; then + dnf groupinstall "Development Tools" -y 2>/dev/null || yum groupinstall "Development Tools" -y 2>/dev/null || echo -e "Failed to install development tools" + else + DEBIAN_FRONTEND=noninteractive apt install build-essential -y 2>/dev/null || echo -e "Failed to install development tools" + fi + ;; esac } @@ -290,11 +339,74 @@ install_dev_tools() { install_php_packages() { local php_extension="$1" case "$Server_OS" in - "CentOS"|"openEuler") - install_package "lsphp??-${php_extension} lsphp??-pecl-${php_extension}" + "CentOS7"|"CloudLinux7"|"CloudLinux8"|"CloudLinux9") + # Find available PHP versions first + available_php_versions=$(ls /usr/local/lsws/lsphp* 2>/dev/null | grep -o 'lsphp[0-9]*' | sort -u) + if [[ -z "$available_php_versions" ]]; then + log_warning "No PHP versions found, skipping ${php_extension} installation" + return 0 + fi + + # Try to install packages for each available PHP version + packages_to_install="" + for php_version in $available_php_versions; do + # Check if package exists before adding to install list + if yum search ${php_version}-${php_extension} 2>/dev/null | grep -q "${php_version}-${php_extension}"; then + packages_to_install="${packages_to_install} ${php_version}-${php_extension}" + fi + if yum search ${php_version}-pecl-${php_extension} 2>/dev/null | grep -q "${php_version}-pecl-${php_extension}"; then + packages_to_install="${packages_to_install} ${php_version}-pecl-${php_extension}" + fi + done + + if [[ -n "$packages_to_install" ]]; then + install_package "$packages_to_install" + else + log_warning "No matching ${php_extension} packages found for available PHP versions" + fi ;; - "Ubuntu") - install_package "lsphp*-${php_extension}" + "CentOS8"|"CentOS9"|"CentOSStream8"|"CentOSStream9"|"RHEL8"|"RHEL9"|"AlmaLinux8"|"AlmaLinux9"|"AlmaLinux10"|"RockyLinux8"|"RockyLinux9"|"openEuler2003"|"openEuler2203"|"openEuler2403") + # Find available PHP versions first + available_php_versions=$(ls /usr/local/lsws/lsphp* 2>/dev/null | grep -o 'lsphp[0-9]*' | sort -u) + if [[ -z "$available_php_versions" ]]; then + log_warning "No PHP versions found, skipping ${php_extension} installation" + return 0 + fi + + # Try to install packages for each available PHP version + packages_to_install="" + for php_version in $available_php_versions; do + # Check if package exists before adding to install list + if dnf search ${php_version}-${php_extension} 2>/dev/null | grep -q "${php_version}-${php_extension}"; then + packages_to_install="${packages_to_install} ${php_version}-${php_extension}" + fi + if dnf search ${php_version}-pecl-${php_extension} 2>/dev/null | grep -q "${php_version}-pecl-${php_extension}"; then + packages_to_install="${packages_to_install} ${php_version}-pecl-${php_extension}" + fi + done + + if [[ -n "$packages_to_install" ]]; then + install_package "$packages_to_install" + else + log_warning "No matching ${php_extension} packages found for available PHP versions" + fi + ;; + "Ubuntu1804"|"Ubuntu2004"|"Ubuntu2010"|"Ubuntu2204"|"Ubuntu2404"|"Ubuntu24043"|"Debian11"|"Debian12"|"Debian13") + # Find available PHP versions first + available_php_versions=$(ls /usr/local/lsws/lsphp* 2>/dev/null | grep -o 'lsphp[0-9]*' | sort -u) + if [[ -z "$available_php_versions" ]]; then + log_warning "No PHP versions found, skipping ${php_extension} installation" + return 0 + fi + + # Try to install packages for each available PHP version + for php_version in $available_php_versions; do + if apt-cache search ${php_version}-${php_extension} 2>/dev/null | grep -q "${php_version}-${php_extension}"; then + install_package "${php_version}-${php_extension}" + else + log_warning "Package ${php_version}-${php_extension} not available" + fi + done ;; esac } @@ -592,26 +704,60 @@ if ! uname -m | grep -qE 'x86_64|aarch64' ; then exit fi -if grep -q -E "CentOS Linux 7|CentOS Linux 8|CentOS Stream" /etc/os-release ; then - Server_OS="CentOS" -elif grep -q "Red Hat Enterprise Linux" /etc/os-release ; then - Server_OS="RedHat" +if grep -q "CentOS Linux 7" /etc/os-release ; then + Server_OS="CentOS7" +elif grep -q "CentOS Linux 8" /etc/os-release ; then + Server_OS="CentOS8" +elif grep -q "CentOS Linux 9" /etc/os-release ; then + Server_OS="CentOS9" +elif grep -q "CentOS Stream 8" /etc/os-release ; then + Server_OS="CentOSStream8" +elif grep -q "CentOS Stream 9" /etc/os-release ; then + Server_OS="CentOSStream9" +elif grep -q "Red Hat Enterprise Linux 8" /etc/os-release ; then + Server_OS="RHEL8" +elif grep -q "Red Hat Enterprise Linux 9" /etc/os-release ; then + Server_OS="RHEL9" elif grep -q "AlmaLinux-8" /etc/os-release ; then - Server_OS="AlmaLinux" + Server_OS="AlmaLinux8" elif grep -q "AlmaLinux-9" /etc/os-release ; then - Server_OS="AlmaLinux" + Server_OS="AlmaLinux9" elif grep -q "AlmaLinux-10" /etc/os-release ; then - Server_OS="AlmaLinux" -elif grep -q -E "CloudLinux 7|CloudLinux 8|CloudLinux 9" /etc/os-release ; then - Server_OS="CloudLinux" -elif grep -q -E "Rocky Linux" /etc/os-release ; then - Server_OS="RockyLinux" -elif grep -q -E "Ubuntu 18.04|Ubuntu 20.04|Ubuntu 20.10|Ubuntu 22.04|Ubuntu 24.04|Ubuntu 24.04.3" /etc/os-release ; then - Server_OS="Ubuntu" -elif grep -q -E "Debian GNU/Linux 11|Debian GNU/Linux 12|Debian GNU/Linux 13" /etc/os-release ; then - Server_OS="Debian" -elif grep -q -E "openEuler 20.03|openEuler 22.03" /etc/os-release ; then - Server_OS="openEuler" + Server_OS="AlmaLinux10" +elif grep -q "Rocky Linux 8" /etc/os-release ; then + Server_OS="RockyLinux8" +elif grep -q "Rocky Linux 9" /etc/os-release ; then + Server_OS="RockyLinux9" +elif grep -q "CloudLinux 7" /etc/os-release ; then + Server_OS="CloudLinux7" +elif grep -q "CloudLinux 8" /etc/os-release ; then + Server_OS="CloudLinux8" +elif grep -q "CloudLinux 9" /etc/os-release ; then + Server_OS="CloudLinux9" +elif grep -q "Ubuntu 18.04" /etc/os-release ; then + Server_OS="Ubuntu1804" +elif grep -q "Ubuntu 20.04" /etc/os-release ; then + Server_OS="Ubuntu2004" +elif grep -q "Ubuntu 20.10" /etc/os-release ; then + Server_OS="Ubuntu2010" +elif grep -q "Ubuntu 22.04" /etc/os-release ; then + Server_OS="Ubuntu2204" +elif grep -q "Ubuntu 24.04" /etc/os-release ; then + Server_OS="Ubuntu2404" +elif grep -q "Ubuntu 24.04.3" /etc/os-release ; then + Server_OS="Ubuntu24043" +elif grep -q "Debian GNU/Linux 11" /etc/os-release ; then + Server_OS="Debian11" +elif grep -q "Debian GNU/Linux 12" /etc/os-release ; then + Server_OS="Debian12" +elif grep -q "Debian GNU/Linux 13" /etc/os-release ; then + Server_OS="Debian13" +elif grep -q "openEuler 20.03" /etc/os-release ; then + Server_OS="openEuler2003" +elif grep -q "openEuler 22.03" /etc/os-release ; then + Server_OS="openEuler2203" +elif grep -q "openEuler 24.03" /etc/os-release ; then + Server_OS="openEuler2403" else echo -e "Unable to detect your system..." echo -e "\nCyberPanel is supported on x86_64 based Ubuntu 18.04, Ubuntu 20.04, Ubuntu 20.10, Ubuntu 22.04, Ubuntu 24.04, Ubuntu 24.04.3, Debian 11, Debian 12, Debian 13, CentOS 7, CentOS 8, CentOS 9, RHEL 8, RHEL 9, AlmaLinux 8, AlmaLinux 9, AlmaLinux 10, RockyLinux 8, RockyLinux 9, CloudLinux 7, CloudLinux 8, CloudLinux 9, openEuler 20.03, openEuler 22.03...\n" @@ -1685,9 +1831,15 @@ if ! grep -q "pid_max" /etc/rc.local 2>/dev/null ; then #add internal repo server to host file before systemd-resolved is disabled if grep -i -q "systemd-resolve" /etc/resolv.conf ; then - systemctl stop systemd-resolved >/dev/null 2>&1 - systemctl disable systemd-resolved >/dev/null 2>&1 - systemctl mask systemd-resolved >/dev/null 2>&1 + # Check if systemd-resolved service exists before trying to manage it + if systemctl list-unit-files | grep -q "systemd-resolved.service" ; then + log_info "Managing systemd-resolved service" + systemctl stop systemd-resolved >/dev/null 2>&1 || log_warning "Could not stop systemd-resolved (may not be running)" + systemctl disable systemd-resolved >/dev/null 2>&1 || log_warning "Could not disable systemd-resolved (may not be enabled)" + systemctl mask systemd-resolved >/dev/null 2>&1 || log_warning "Could not mask systemd-resolved" + else + log_info "systemd-resolved service not found, skipping management" + fi fi # Backup previous resolv.conf file @@ -2165,34 +2317,34 @@ echo "║ echo "╚═══════════════════════════════════════════════════════════════════════════════════════════════════════════════╝" echo -e "\n" -echo "╔══════════════════════════════════════════════════════════════════════════════════════╗" -echo "║ ║" -echo "║ 🌐 ACCESS YOUR CYBERPANEL: ║" -echo "║ ║" -echo "║ • URL: https://$Server_IP:8090 ║" -echo "║ • Username: admin ║" +echo "╔═══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗" +echo "║ ║" +echo "║ 🌐 ACCESS YOUR CYBERPANEL: ║" +echo "║ ║" +echo "║ • URL: https://$Server_IP:8090 ║" +echo "║ • Username: admin ║" if [[ "$Custom_Pass" = "True" ]]; then -echo "║ • Password: ***** (custom password) ║" +echo "║ • Password: ***** (custom password) ║" else -echo "║ • Password: $Admin_Pass ║" +echo "║ • Password: $Admin_Pass ║" fi -echo "║ ║" -echo "║ ⚠️ Please change the default password immediately! ║" -echo "║ ║" -echo "╚══════════════════════════════════════════════════════════════════════════════════════╝" +echo "║ ║" +echo "║ ⚠️ Please change the default password immediately! ║" +echo "║ ║" +echo "╚═══════════════════════════════════════════════════════════════════════════════════════════════════════════════╝" echo -e "\n" -echo "╔══════════════════════════════════════════════════════════════════════════════════════╗" -echo "║ ║" -echo "║ 📊 SYSTEM STATUS: ║" -echo "║ ║" -echo "║ 💾 Disk Usage: $(df -h | awk '$NF=="/"{printf "%d/%dGB (%s)", $3,$2,$5}') ║" -echo "║ 🧠 RAM Usage: $(free -m | awk 'NR==2{printf "%s/%sMB (%.2f%%)", $3,$2,$3*100/$2 }') ║" -echo "║ ⏱️ Install Time: $Elapsed_Time ║" -echo "║ ║" -echo "║ 🎉 INSTALLATION COMPLETED SUCCESSFULLY! 🎉 ║" -echo "║ ║" -echo "╚══════════════════════════════════════════════════════════════════════════════════════╝" +echo "╔═══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗" +echo "║ ║" +echo "║ 📊 SYSTEM STATUS: ║" +echo "║ ║" +echo "║ 💾 Disk Usage: $(df -h | awk '$NF=="/"{printf "%d/%dGB (%s)", $3,$2,$5}') ║" +echo "║ 🧠 RAM Usage: $(free -m | awk 'NR==2{printf "%s/%sMB (%.2f%%)", $3,$2,$3*100/$2 }') ║" +echo "║ ⏱️ Install Time: $Elapsed_Time ║" +echo "║ ║" +echo "║ 🎉 INSTALLATION COMPLETED SUCCESSFULLY! 🎉 ║" +echo "║ ║" +echo "╚═══════════════════════════════════════════════════════════════════════════════════════════════════════════════╝" #echo " Visit: https://$Server_IP:7080 " #echo " WebAdmin console username: admin " #echo " WebAdmin console password: $Webadmin_Pass " @@ -2200,19 +2352,25 @@ echo "╚═══════════════════════ #echo " Visit: https://$Server_IP:8090/snappymail/?admin " #echo " snappymail Admin username: admin " #echo " snappymail Admin password: $snappymailAdminPass " -echo " " -echo -e " Run \e[31mcyberpanel help\e[39m to get FAQ info" -echo -e " Run \e[31mcyberpanel upgrade\e[39m to upgrade it to latest version." -echo -e " Run \e[31mcyberpanel utility\e[39m to access some handy tools ." -echo " " -echo " Website : https://www.cyberpanel.net " -echo " Forums : https://forums.cyberpanel.net " -echo " Wikipage: https://cyberpanel.net/KnowledgeBase/ " -echo " Docs : https://cyberpanel.net/docs/ " -echo " " -echo -e " Enjoy your accelerated Internet by " -echo -e " CyberPanel & $Word " -echo "###################################################################" +echo "╔═══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗" +echo "║ ║" +echo "║ 🛠️ COMMANDS & RESOURCES: ║" +echo "║ ║" +echo -e "║ Run \e[31mcyberpanel help\e[39m to get FAQ info ║" +echo -e "║ Run \e[31mcyberpanel upgrade\e[39m to upgrade it to latest version. ║" +echo -e "║ Run \e[31mcyberpanel utility\e[39m to access some handy tools . ║" +echo "║ ║" +echo "║ 🔗 OFFICIAL LINKS: ║" +echo "║ ║" +echo "║ Website : https://www.cyberpanel.net ║" +echo "║ Forums : https://forums.cyberpanel.net ║" +echo "║ Wikipage: https://cyberpanel.net/KnowledgeBase/ ║" +echo "║ Docs : https://cyberpanel.net/docs/ ║" +echo "║ ║" +echo -e "║ Enjoy your accelerated Internet by ║" +echo -e "║ CyberPanel & $Word ║" +echo "║ ║" +echo "╚═══════════════════════════════════════════════════════════════════════════════════════════════════════════════╝" if [[ "$Server_Provider" != "Undefined" ]]; then echo -e "\033[0;32m$Server_Provider\033[39m detected..." @@ -2321,6 +2479,12 @@ if [[ ! -f /usr/local/CyberCP/bin/activate ]]; then exit 1 fi +# Create symlink for backward compatibility +if [[ ! -L /usr/local/CyberPanel ]] && [[ ! -d /usr/local/CyberPanel ]]; then + echo -e "Creating symlink for CyberPanel virtual environment compatibility..." + ln -sf /usr/local/CyberCP /usr/local/CyberPanel +fi + if [[ "$Server_OS" = "Ubuntu" ]] && [[ "$Server_OS_Version" = "20" ]] ; then # shellcheck disable=SC1091 . /usr/local/CyberCP/bin/activate @@ -2339,7 +2503,6 @@ Retry_Command "pip install --default-timeout=3600 -r /usr/local/requirments.txt" echo -e "Verifying Django installation..." if ! /usr/local/CyberCP/bin/python -c "import django" 2>/dev/null; then echo -e "WARNING: Django not found, reinstalling requirements..." - pip install --upgrade pip setuptools wheel packaging pip install --default-timeout=3600 --ignore-installed -r /usr/local/requirments.txt else echo -e "Django is properly installed" diff --git a/cyberpanel_upgrade.sh b/cyberpanel_upgrade.sh index 81e8531b0..703e44729 100644 --- a/cyberpanel_upgrade.sh +++ b/cyberpanel_upgrade.sh @@ -1071,7 +1071,6 @@ if ! /usr/local/CyberCP/bin/python -c "import django" 2>/dev/null; then # Re-install requirements echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Re-installing Python requirements..." | tee -a /var/log/cyberpanel_upgrade_debug.log - pip install --upgrade pip setuptools wheel packaging 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log pip install --default-timeout=3600 --ignore-installed -r /usr/local/requirments.txt 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log else echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Django is properly installed" | tee -a /var/log/cyberpanel_upgrade_debug.log diff --git a/install.sh b/install.sh index 5086a8172..e676034ce 100644 --- a/install.sh +++ b/install.sh @@ -5,105 +5,131 @@ if echo $OUTPUT | grep -q "CentOS Linux 7" ; then echo "Checking and installing curl and wget" yum install curl wget -y 1> /dev/null yum update curl wget ca-certificates -y 1> /dev/null - SERVER_OS="CentOS" -elif echo $OUTPUT | grep -q "CentOS Stream 9" ; then - echo -e "\nDetecting Centos Stream 9...\n" - SERVER_OS="CentOSStream9" -yum install curl wget -y 1> /dev/null -yum update curl wget ca-certificates -y 1> /dev/null -elif echo $OUTPUT | grep -q "AlmaLinux 8" ; then - echo -e "\nDetecting AlmaLinux 8...\n" - SERVER_OS="CentOS8" -yum install curl wget -y 1> /dev/null -yum update curl wget ca-certificates -y 1> /dev/null -elif echo $OUTPUT | grep -q "AlmaLinux 9" ; then - echo -e "\nDetecting AlmaLinux 9...\n" - SERVER_OS="CentOS8" -yum install curl wget -y 1> /dev/null -yum update curl wget ca-certificates -y 1> /dev/null -elif echo $OUTPUT | grep -q "AlmaLinux 10" ; then - echo -e "\nDetecting AlmaLinux 10...\n" - SERVER_OS="CentOS8" -yum install curl wget -y 1> /dev/null -yum update curl wget ca-certificates -y 1> /dev/null -elif echo $OUTPUT | grep -q "CloudLinux 8" ; then - echo "Checking and installing curl and wget" -yum install curl wget -y 1> /dev/null -yum update curl wget ca-certificates -y 1> /dev/null - SERVER_OS="CloudLinux" -elif echo $OUTPUT | grep -q "CloudLinux 9" ; then - echo "Checking and installing curl and wget" -yum install curl wget -y 1> /dev/null -yum update curl wget ca-certificates -y 1> /dev/null - SERVER_OS="CloudLinux" -elif echo $OUTPUT | grep -q "Ubuntu 20.04" ; then -apt install -y -qq wget curl - SERVER_OS="Ubuntu" -elif echo $OUTPUT | grep -q "Ubuntu 22.04" ; then -apt install -y -qq wget curl - SERVER_OS="Ubuntu" -elif echo $OUTPUT | grep -q "Ubuntu 24.04" ; then -apt install -y -qq wget curl - SERVER_OS="Ubuntu" -elif echo $OUTPUT | grep -q "Ubuntu 24.04.3" ; then -apt install -y -qq wget curl - SERVER_OS="Ubuntu" -elif echo $OUTPUT | grep -q "Debian GNU/Linux 11" ; then -apt install -y -qq wget curl - SERVER_OS="Ubuntu" -elif echo $OUTPUT | grep -q "Debian GNU/Linux 12" ; then -apt install -y -qq wget curl - SERVER_OS="Ubuntu" -elif echo $OUTPUT | grep -q "Debian GNU/Linux 13" ; then -apt install -y -qq wget curl - SERVER_OS="Ubuntu" -elif echo $OUTPUT | grep -q "Rocky Linux 8" ; then - echo -e "\nDetecting Rocky Linux 8...\n" - SERVER_OS="CentOS8" -yum install curl wget -y 1> /dev/null -yum update curl wget ca-certificates -y 1> /dev/null -elif echo $OUTPUT | grep -q "Rocky Linux 9" ; then - echo -e "\nDetecting Rocky Linux 9...\n" - SERVER_OS="CentOS8" -yum install curl wget -y 1> /dev/null -yum update curl wget ca-certificates -y 1> /dev/null -elif echo $OUTPUT | grep -q "Red Hat Enterprise Linux 8" ; then - echo -e "\nDetecting RHEL 8...\n" - SERVER_OS="CentOS8" -yum install curl wget -y 1> /dev/null -yum update curl wget ca-certificates -y 1> /dev/null -elif echo $OUTPUT | grep -q "Red Hat Enterprise Linux 9" ; then - echo -e "\nDetecting RHEL 9...\n" + SERVER_OS="CentOS7" +elif echo $OUTPUT | grep -q "CentOS Linux 8" ; then + echo -e "\nDetecting CentOS 8...\n" SERVER_OS="CentOS8" yum install curl wget -y 1> /dev/null yum update curl wget ca-certificates -y 1> /dev/null elif echo $OUTPUT | grep -q "CentOS Linux 9" ; then echo -e "\nDetecting CentOS 9...\n" - SERVER_OS="CentOS8" + SERVER_OS="CentOS9" +yum install curl wget -y 1> /dev/null +yum update curl wget ca-certificates -y 1> /dev/null +elif echo $OUTPUT | grep -q "CentOS Stream 8" ; then + echo -e "\nDetecting CentOS Stream 8...\n" + SERVER_OS="CentOSStream8" +yum install curl wget -y 1> /dev/null +yum update curl wget ca-certificates -y 1> /dev/null +elif echo $OUTPUT | grep -q "CentOS Stream 9" ; then + echo -e "\nDetecting CentOS Stream 9...\n" + SERVER_OS="CentOSStream9" +yum install curl wget -y 1> /dev/null +yum update curl wget ca-certificates -y 1> /dev/null +elif echo $OUTPUT | grep -q "AlmaLinux 8" ; then + echo -e "\nDetecting AlmaLinux 8...\n" + SERVER_OS="AlmaLinux8" +yum install curl wget -y 1> /dev/null +yum update curl wget ca-certificates -y 1> /dev/null +elif echo $OUTPUT | grep -q "AlmaLinux 9" ; then + echo -e "\nDetecting AlmaLinux 9...\n" + SERVER_OS="AlmaLinux9" +yum install curl wget -y 1> /dev/null +yum update curl wget ca-certificates -y 1> /dev/null +elif echo $OUTPUT | grep -q "AlmaLinux 10" ; then + echo -e "\nDetecting AlmaLinux 10...\n" + SERVER_OS="AlmaLinux10" +yum install curl wget -y 1> /dev/null +yum update curl wget ca-certificates -y 1> /dev/null +elif echo $OUTPUT | grep -q "CloudLinux 7" ; then + echo "Checking and installing curl and wget" +yum install curl wget -y 1> /dev/null +yum update curl wget ca-certificates -y 1> /dev/null + SERVER_OS="CloudLinux7" +elif echo $OUTPUT | grep -q "CloudLinux 8" ; then + echo "Checking and installing curl and wget" +yum install curl wget -y 1> /dev/null +yum update curl wget ca-certificates -y 1> /dev/null + SERVER_OS="CloudLinux8" +elif echo $OUTPUT | grep -q "CloudLinux 9" ; then + echo "Checking and installing curl and wget" +yum install curl wget -y 1> /dev/null +yum update curl wget ca-certificates -y 1> /dev/null + SERVER_OS="CloudLinux9" +elif echo $OUTPUT | grep -q "Ubuntu 18.04" ; then +apt install -y -qq wget curl + SERVER_OS="Ubuntu1804" +elif echo $OUTPUT | grep -q "Ubuntu 20.04" ; then +apt install -y -qq wget curl + SERVER_OS="Ubuntu2004" +elif echo $OUTPUT | grep -q "Ubuntu 20.10" ; then +apt install -y -qq wget curl + SERVER_OS="Ubuntu2010" +elif echo $OUTPUT | grep -q "Ubuntu 22.04" ; then +apt install -y -qq wget curl + SERVER_OS="Ubuntu2204" +elif echo $OUTPUT | grep -q "Ubuntu 24.04" ; then +apt install -y -qq wget curl + SERVER_OS="Ubuntu2404" +elif echo $OUTPUT | grep -q "Ubuntu 24.04.3" ; then +apt install -y -qq wget curl + SERVER_OS="Ubuntu24043" +elif echo $OUTPUT | grep -q "Debian GNU/Linux 11" ; then +apt install -y -qq wget curl + SERVER_OS="Debian11" +elif echo $OUTPUT | grep -q "Debian GNU/Linux 12" ; then +apt install -y -qq wget curl + SERVER_OS="Debian12" +elif echo $OUTPUT | grep -q "Debian GNU/Linux 13" ; then +apt install -y -qq wget curl + SERVER_OS="Debian13" +elif echo $OUTPUT | grep -q "Rocky Linux 8" ; then + echo -e "\nDetecting Rocky Linux 8...\n" + SERVER_OS="RockyLinux8" +yum install curl wget -y 1> /dev/null +yum update curl wget ca-certificates -y 1> /dev/null +elif echo $OUTPUT | grep -q "Rocky Linux 9" ; then + echo -e "\nDetecting Rocky Linux 9...\n" + SERVER_OS="RockyLinux9" +yum install curl wget -y 1> /dev/null +yum update curl wget ca-certificates -y 1> /dev/null +elif echo $OUTPUT | grep -q "Red Hat Enterprise Linux 8" ; then + echo -e "\nDetecting RHEL 8...\n" + SERVER_OS="RHEL8" +yum install curl wget -y 1> /dev/null +yum update curl wget ca-certificates -y 1> /dev/null +elif echo $OUTPUT | grep -q "Red Hat Enterprise Linux 9" ; then + echo -e "\nDetecting RHEL 9...\n" + SERVER_OS="RHEL9" yum install curl wget -y 1> /dev/null yum update curl wget ca-certificates -y 1> /dev/null elif echo $OUTPUT | grep -q "openEuler 20.03" ; then echo -e "\nDetecting openEuler 20.03...\n" - SERVER_OS="openEuler" + SERVER_OS="openEuler2003" yum install curl wget -y 1> /dev/null yum update curl wget ca-certificates -y 1> /dev/null elif echo $OUTPUT | grep -q "openEuler 22.03" ; then echo -e "\nDetecting openEuler 22.03...\n" - SERVER_OS="openEuler" + SERVER_OS="openEuler2203" +yum install curl wget -y 1> /dev/null +yum update curl wget ca-certificates -y 1> /dev/null +elif echo $OUTPUT | grep -q "openEuler 24.03" ; then + echo -e "\nDetecting openEuler 24.03...\n" + SERVER_OS="openEuler2403" yum install curl wget -y 1> /dev/null yum update curl wget ca-certificates -y 1> /dev/null else echo -e "\nUnable to detect your OS...\n" echo -e "\nCyberPanel is supported on:\n" - echo -e "Ubuntu: 20.04, 22.04, 24.04, 24.04.3\n" + echo -e "Ubuntu: 18.04, 20.04, 20.10, 22.04, 24.04, 24.04.3\n" echo -e "Debian: 11, 12, 13\n" echo -e "AlmaLinux: 8, 9, 10\n" echo -e "RockyLinux: 8, 9\n" echo -e "RHEL: 8, 9\n" - echo -e "CentOS: 7, 9, Stream 9\n" - echo -e "CloudLinux: 8, 9\n" - echo -e "openEuler: 20.03, 22.03\n" + echo -e "CentOS: 7, 8, 9, Stream 8, Stream 9\n" + echo -e "CloudLinux: 7, 8, 9\n" + echo -e "openEuler: 20.03, 22.03, 24.03\n" exit 1 fi diff --git a/install/install.py b/install/install.py index 0276c715d..8af131d41 100644 --- a/install/install.py +++ b/install/install.py @@ -81,12 +81,36 @@ class preFlightsChecks: def get_service_name(self, service): """Get the correct service name for the current distribution""" service_map = { - 'pdns': 'pdns' + 'pdns': 'pdns', + 'powerdns': 'pdns', + 'pure-ftpd': 'pure-ftpd', + 'pureftpd': 'pure-ftpd' } + + # Platform-specific service name mapping + if self.is_debian_family(): + if service in ['pdns', 'powerdns']: + return 'pdns-server' + elif service in ['pure-ftpd', 'pureftpd']: + return 'pure-ftpd' + elif self.is_centos_family(): + if service in ['pdns', 'powerdns']: + return 'pdns' + elif service in ['pure-ftpd', 'pureftpd']: + return 'pure-ftpd' + return service_map.get(service, service) def manage_service(self, service_name, action="start"): - """Unified service management""" + """Unified service management with error handling""" + # Check if service exists before trying to manage it + check_command = f'systemctl list-unit-files | grep -q "{service_name}.service"' + result = subprocess.run(check_command, shell=True, capture_output=True) + + if result.returncode != 0: + preFlightsChecks.stdOut(f"Service {service_name} not found, skipping {action}", 1) + return 1 # Return success since service doesn't exist + command = f'systemctl {action} {service_name}' return preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) @@ -2119,6 +2143,43 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; def setupPythonWSGI(self): try: preFlightsChecks.stdOut("Setting up Python WSGI-LSAPI with optimized compilation...", 1) + + # Ensure virtual environment is properly set up + self.ensureVirtualEnvironmentSetup() + + # Upgrade pip to latest version for better package compatibility + self.upgradePip() + + # Determine the correct Python path + python_paths = [ + "/usr/local/CyberPanel/bin/python", + "/usr/local/CyberCP/bin/python", + "/usr/bin/python3", + "/usr/local/bin/python3" + ] + + python_path = None + for path in python_paths: + if os.path.exists(path): + python_path = path + preFlightsChecks.stdOut(f"Using Python at: {python_path}", 1) + break + + if not python_path: + preFlightsChecks.stdOut("ERROR: No Python executable found for WSGI setup", 0) + preFlightsChecks.stdOut("Attempting to create virtual environment symlink...", 1) + + # Try to create symlink for compatibility + if os.path.exists('/usr/local/CyberCP/bin/python') and not os.path.exists('/usr/local/CyberPanel'): + try: + os.symlink('/usr/local/CyberCP', '/usr/local/CyberPanel') + python_path = "/usr/local/CyberPanel/bin/python" + preFlightsChecks.stdOut(f"Created symlink, using Python at: {python_path}", 1) + except Exception as e: + preFlightsChecks.stdOut(f"Failed to create symlink: {str(e)}", 0) + return 0 + else: + return 0 command = "wget http://www.litespeedtech.com/packages/lsapi/wsgi-lsapi-2.1.tgz" preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) @@ -2128,7 +2189,7 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; os.chdir("wsgi-lsapi-2.1") - command = "/usr/local/CyberPanel/bin/python ./configure.py" + command = f"{python_path} ./configure.py" preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) # Fix Makefile to use proper optimization flags to avoid _FORTIFY_SOURCE warnings @@ -2158,6 +2219,69 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; preFlightsChecks.stdOut(f"WSGI setup error: {str(e)}", 0) return 0 + def ensureVirtualEnvironmentSetup(self): + """Ensure virtual environment is properly set up and accessible""" + try: + # Check if CyberCP virtual environment exists + if os.path.exists('/usr/local/CyberCP/bin/python'): + preFlightsChecks.stdOut("CyberCP virtual environment found", 1) + + # Create symlink if CyberPanel path doesn't exist + if not os.path.exists('/usr/local/CyberPanel/bin/python'): + if not os.path.exists('/usr/local/CyberPanel'): + preFlightsChecks.stdOut("Creating CyberPanel symlink for compatibility", 1) + os.symlink('/usr/local/CyberCP', '/usr/local/CyberPanel') + else: + preFlightsChecks.stdOut("CyberPanel directory exists but Python not found", 0) + return False + + return True + else: + preFlightsChecks.stdOut("CyberCP virtual environment not found", 0) + return False + + except Exception as e: + preFlightsChecks.stdOut(f"Error setting up virtual environment: {str(e)}", 0) + return False + + def upgradePip(self): + """Upgrade pip to latest version for better package compatibility""" + try: + preFlightsChecks.stdOut("Upgrading pip to latest version...", 1) + + # Determine the correct Python path + python_paths = [ + "/usr/local/CyberPanel/bin/python", + "/usr/local/CyberCP/bin/python", + "/usr/bin/python3", + "/usr/local/bin/python3" + ] + + python_path = None + for path in python_paths: + if os.path.exists(path): + python_path = path + break + + if not python_path: + preFlightsChecks.stdOut("No Python executable found for pip upgrade", 0) + return False + + # Upgrade pip and essential packages + upgrade_command = f"{python_path} -m pip install --upgrade pip setuptools wheel packaging" + result = preFlightsChecks.call(upgrade_command, self.distro, "Upgrade pip", upgrade_command, 1, 0, os.EX_OSERR) + + if result == 1: + preFlightsChecks.stdOut("pip upgraded successfully", 1) + return True + else: + preFlightsChecks.stdOut("WARNING: pip upgrade failed, continuing with current version", 0) + return False + + except Exception as e: + preFlightsChecks.stdOut(f"Error upgrading pip: {str(e)}", 0) + return False + def _fixWSGIMakefile(self): """Fix the Makefile to use proper compiler optimization flags""" try: @@ -2679,7 +2803,7 @@ milter_default_action = accept if state == 'off': - pdns_service = self.get_service_name('pdns') + pdns_service = preFlightsChecks.get_service_name('pdns') command = f'sudo systemctl stop {pdns_service}' subprocess.call(shlex.split(command)) @@ -2930,56 +3054,395 @@ vmail preFlightsChecks.stdOut("Starting deferred services that depend on database tables...") + # Ensure database is ready first + self.ensureDatabaseReady() + # Start PowerDNS if it was installed if os.path.exists('/home/cyberpanel/powerdns'): - preFlightsChecks.stdOut("Starting PowerDNS service...") - pdns_service = self.get_service_name('pdns') - command = f'systemctl start {pdns_service}' - result = preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - if result == 1: - # Check if service started successfully - command = f'systemctl is-active {pdns_service}' - try: - output = subprocess.check_output(shlex.split(command)).decode("utf-8").strip() - if output == 'active': - preFlightsChecks.stdOut("PowerDNS service started successfully!") - else: - preFlightsChecks.stdOut("[WARNING] PowerDNS service may not have started properly. Status: " + output) - except: - preFlightsChecks.stdOut("[WARNING] Could not verify PowerDNS service status") + self.fixAndStartPowerDNS() # Start Pure-FTPd if it was installed if os.path.exists('/home/cyberpanel/pureftpd'): - # Configure Pure-FTPd for Ubuntu 24.04 (SHA512 password hashing compatibility) + self.fixAndStartPureFTPd() + + # Ensure LiteSpeed services are running + self.ensureLiteSpeedServicesRunning() + + # Final service verification + self.verifyCriticalServices() + + def ensureDatabaseReady(self): + """Ensure database is ready before starting dependent services""" + preFlightsChecks.stdOut("Ensuring database is ready...") + + # Wait for MySQL/MariaDB to be ready + max_attempts = 30 + for attempt in range(max_attempts): + try: + if subprocess.run(['mysqladmin', 'ping', '-h', 'localhost', '--silent'], + capture_output=True).returncode == 0: + preFlightsChecks.stdOut("Database is ready") + return + except: + pass + preFlightsChecks.stdOut(f"Waiting for database... ({attempt + 1}/{max_attempts})") + time.sleep(2) + + preFlightsChecks.stdOut("[WARNING] Database may not be fully ready") + + def ensurePowerDNSDatabaseAccess(self): + """Ensure PowerDNS database tables and access are properly set up""" + try: + preFlightsChecks.stdOut("Setting up PowerDNS database access...", 1) + + # Create PowerDNS database tables if they don't exist + db_commands = [ + "mysql -e \"CREATE DATABASE IF NOT EXISTS powerdns;\"", + "mysql -e \"CREATE USER IF NOT EXISTS 'powerdns'@'localhost' IDENTIFIED BY 'cyberpanel';\"", + "mysql -e \"GRANT ALL PRIVILEGES ON powerdns.* TO 'powerdns'@'localhost';\"", + "mysql -e \"FLUSH PRIVILEGES;\"" + ] + + for cmd in db_commands: + preFlightsChecks.call(cmd, self.distro, f"PowerDNS DB: {cmd}", cmd, 1, 0, os.EX_OSERR) + + # Import PowerDNS schema if tables don't exist + schema_check = "mysql -e \"USE powerdns; SHOW TABLES;\"" + result = subprocess.run(schema_check, shell=True, capture_output=True, text=True) + + if not result.stdout.strip() or 'domains' not in result.stdout: + preFlightsChecks.stdOut("Importing PowerDNS database schema...", 1) + # Try to find and import PowerDNS schema + schema_files = [ + '/usr/share/doc/pdns-backend-mysql/schema.mysql.sql', + '/usr/share/doc/powerdns/schema.mysql.sql', + '/usr/share/pdns/schema.mysql.sql' + ] + + for schema_file in schema_files: + if os.path.exists(schema_file): + import_cmd = f"mysql powerdns < {schema_file}" + preFlightsChecks.call(import_cmd, self.distro, f"Import PowerDNS schema", import_cmd, 1, 0, os.EX_OSERR) + break + else: + preFlightsChecks.stdOut("PowerDNS schema not found, creating basic tables...", 1) + # Create basic PowerDNS tables + basic_schema = """ + CREATE TABLE IF NOT EXISTS domains ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + master VARCHAR(128) DEFAULT NULL, + last_check INT DEFAULT NULL, + type VARCHAR(6) NOT NULL, + notified_serial INT DEFAULT NULL, + account VARCHAR(40) DEFAULT NULL, + UNIQUE KEY name (name) + ); + CREATE TABLE IF NOT EXISTS records ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + domain_id INT DEFAULT NULL, + name VARCHAR(255) DEFAULT NULL, + type VARCHAR(10) DEFAULT NULL, + content TEXT DEFAULT NULL, + ttl INT DEFAULT NULL, + prio INT DEFAULT NULL, + change_date INT DEFAULT NULL, + disabled TINYINT(1) DEFAULT 0, + ordername VARCHAR(255) DEFAULT NULL, + auth TINYINT(1) DEFAULT 1, + KEY domain_id (domain_id), + KEY name (name), + KEY type (type) + ); + """ + with open('/tmp/powerdns_schema.sql', 'w') as f: + f.write(basic_schema) + preFlightsChecks.call("mysql powerdns < /tmp/powerdns_schema.sql", self.distro, "Create PowerDNS tables", "mysql powerdns < /tmp/powerdns_schema.sql", 1, 0, os.EX_OSERR) + + except Exception as e: + preFlightsChecks.stdOut(f"Warning: Could not set up PowerDNS database access: {str(e)}", 0) + + def fixAndStartPowerDNS(self): + """Fix PowerDNS configuration and start the service""" + preFlightsChecks.stdOut("Fixing and starting PowerDNS service...") + + # Determine correct service name + pdns_service = None + if subprocess.run(['systemctl', 'list-unit-files'], capture_output=True, text=True).stdout.find('pdns.service') != -1: + pdns_service = 'pdns' + elif subprocess.run(['systemctl', 'list-unit-files'], capture_output=True, text=True).stdout.find('powerdns.service') != -1: + pdns_service = 'powerdns' + + if not pdns_service: + preFlightsChecks.stdOut("[WARNING] PowerDNS service not found") + return + + # Fix PowerDNS configuration + config_files = ['/etc/pdns/pdns.conf', '/etc/powerdns/pdns.conf'] + for config_file in config_files: + if os.path.exists(config_file): + preFlightsChecks.stdOut(f"Configuring PowerDNS: {config_file}") + + # Read existing content + try: + with open(config_file, 'r') as f: + content = f.read() + except: + content = "" + + # Add missing configuration if not present + config_additions = [] + if 'gmysql-password=' not in content: + config_additions.append('gmysql-password=cyberpanel') + if 'launch=' not in content: + config_additions.append('launch=gmysql') + if 'gmysql-host=' not in content: + config_additions.append('gmysql-host=localhost') + if 'gmysql-user=' not in content: + config_additions.append('gmysql-user=cyberpanel') + if 'gmysql-dbname=' not in content: + config_additions.append('gmysql-dbname=cyberpanel') + + if config_additions: + with open(config_file, 'a') as f: + f.write('\n# CyberPanel configuration\n') + for config in config_additions: + f.write(config + '\n') + + # Ensure proper permissions + os.chmod(config_file, 0o644) + break + + # Ensure PowerDNS can connect to database + self.ensurePowerDNSDatabaseAccess() + + # Start PowerDNS service with retry mechanism + max_retries = 3 + for attempt in range(max_retries): + preFlightsChecks.stdOut(f"Starting PowerDNS service (attempt {attempt + 1}/{max_retries})...", 1) + + # Stop service first to ensure clean start + command = f'systemctl stop {pdns_service}' + preFlightsChecks.call(command, self.distro, f"Stop {pdns_service}", command, 0, 0, os.EX_OSERR) + time.sleep(2) + + # Start service + command = f'systemctl start {pdns_service}' + result = preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + + # Wait a moment for service to start + time.sleep(3) + + # Check if service is actually running + command = f'systemctl is-active {pdns_service}' + try: + result = subprocess.run(command, shell=True, capture_output=True, text=True, timeout=10) + output = result.stdout.strip() + if output == 'active': + preFlightsChecks.stdOut("PowerDNS service started successfully!", 1) + # Double-check with systemctl status for more details + status_command = f'systemctl status {pdns_service} --no-pager -l' + try: + status_result = subprocess.run(status_command, shell=True, capture_output=True, text=True, timeout=10) + if status_result.returncode == 0: + preFlightsChecks.stdOut("PowerDNS service status verified", 1) + else: + preFlightsChecks.stdOut("PowerDNS service running but status check failed", 0) + except: + preFlightsChecks.stdOut("PowerDNS service running but status verification failed", 0) + break + else: + preFlightsChecks.stdOut(f"PowerDNS service status: {output} (attempt {attempt + 1})", 0) + if attempt < max_retries - 1: + preFlightsChecks.stdOut("Retrying PowerDNS startup...", 1) + time.sleep(5) + except subprocess.TimeoutExpired: + preFlightsChecks.stdOut(f"PowerDNS service status check timed out (attempt {attempt + 1})", 0) + if attempt < max_retries - 1: + time.sleep(5) + except Exception as e: + preFlightsChecks.stdOut(f"Could not verify PowerDNS service status (attempt {attempt + 1}): {str(e)}", 0) + if attempt < max_retries - 1: + time.sleep(5) + else: + preFlightsChecks.stdOut("[WARNING] PowerDNS service failed to start after all retries", 0) + # Try to get more details about the failure + command = f'systemctl status {pdns_service} --no-pager' + preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + + # Enable service for auto-start (with error handling) + command = f'systemctl enable {pdns_service}' + enable_result = preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + if enable_result != 1: + preFlightsChecks.stdOut(f"Warning: Could not enable {pdns_service} for auto-start", 0) + + def fixAndStartPureFTPd(self): + """Fix Pure-FTPd configuration and start the service""" + preFlightsChecks.stdOut("Fixing and starting Pure-FTPd service...") + + # Determine correct service name + ftp_service = None + if subprocess.run(['systemctl', 'list-unit-files'], capture_output=True, text=True).stdout.find('pure-ftpd.service') != -1: + ftp_service = 'pure-ftpd' + elif subprocess.run(['systemctl', 'list-unit-files'], capture_output=True, text=True).stdout.find('pureftpd.service') != -1: + ftp_service = 'pureftpd' + + if not ftp_service: + preFlightsChecks.stdOut("[WARNING] Pure-FTPd service not found") + return + + # Fix Pure-FTPd configuration + config_files = ['/etc/pure-ftpd/pureftpd-mysql.conf', '/etc/pure-ftpd/db/mysql.conf'] + for config_file in config_files: + if os.path.exists(config_file): + preFlightsChecks.stdOut(f"Configuring Pure-FTPd: {config_file}") + + # Fix MySQL password configuration + command = f"sed -i 's/MYSQLPassword.*/MYSQLPassword cyberpanel/' {config_file}" + preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + + # Fix MySQL crypt method for Ubuntu 24.04 compatibility if self.distro == ubuntu: import install_utils try: release = install_utils.get_Ubuntu_release(use_print=False, exit_on_error=False) if release and release >= 24.04: preFlightsChecks.stdOut("Configuring Pure-FTPd for Ubuntu 24.04...") - # Change MYSQLCrypt from md5 to crypt for SHA512 compatibility - command = "sed -i 's/MYSQLCrypt md5/MYSQLCrypt crypt/g' /etc/pure-ftpd/db/mysql.conf" + command = f"sed -i 's/MYSQLCrypt md5/MYSQLCrypt crypt/g' {config_file}" preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) except: - pass # If version detection fails, continue without configuration change - - preFlightsChecks.stdOut("Starting Pure-FTPd service...") - ftpService = self.pureFTPDServiceName(self.distro) - command = f'systemctl start {ftpService}' + pass + + # Start Pure-FTPd service with retry mechanism + max_retries = 3 + for attempt in range(max_retries): + preFlightsChecks.stdOut(f"Starting Pure-FTPd service (attempt {attempt + 1}/{max_retries})...", 1) + + # Stop service first to ensure clean start + command = f'systemctl stop {ftp_service}' + preFlightsChecks.call(command, self.distro, f"Stop {ftp_service}", command, 0, 0, os.EX_OSERR) + time.sleep(2) + + # Start service + command = f'systemctl start {ftp_service}' result = preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - if result == 1: - # Check if service started successfully - command = f'systemctl is-active {ftpService}' + # Wait a moment for service to start + time.sleep(3) + + # Check if service is actually running + command = f'systemctl is-active {ftp_service}' + try: + result = subprocess.run(command, shell=True, capture_output=True, text=True, timeout=10) + output = result.stdout.strip() + if output == 'active': + preFlightsChecks.stdOut("Pure-FTPd service started successfully!", 1) + # Double-check with systemctl status for more details + status_command = f'systemctl status {ftp_service} --no-pager -l' + try: + status_result = subprocess.run(status_command, shell=True, capture_output=True, text=True, timeout=10) + if status_result.returncode == 0: + preFlightsChecks.stdOut("Pure-FTPd service status verified", 1) + else: + preFlightsChecks.stdOut("Pure-FTPd service running but status check failed", 0) + except: + preFlightsChecks.stdOut("Pure-FTPd service running but status verification failed", 0) + break + else: + preFlightsChecks.stdOut(f"Pure-FTPd service status: {output} (attempt {attempt + 1})", 0) + if attempt < max_retries - 1: + preFlightsChecks.stdOut("Retrying Pure-FTPd startup...", 1) + time.sleep(5) + except subprocess.TimeoutExpired: + preFlightsChecks.stdOut(f"Pure-FTPd service status check timed out (attempt {attempt + 1})", 0) + if attempt < max_retries - 1: + time.sleep(5) + except Exception as e: + preFlightsChecks.stdOut(f"Could not verify Pure-FTPd service status (attempt {attempt + 1}): {str(e)}", 0) + if attempt < max_retries - 1: + time.sleep(5) + else: + preFlightsChecks.stdOut("[WARNING] Pure-FTPd service failed to start after all retries", 0) + # Try to get more details about the failure + command = f'systemctl status {ftp_service} --no-pager' + preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + + # Enable service for auto-start (with error handling) + command = f'systemctl enable {ftp_service}' + enable_result = preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + if enable_result != 1: + preFlightsChecks.stdOut(f"Warning: Could not enable {ftp_service} for auto-start", 0) + + def ensureLiteSpeedServicesRunning(self): + """Ensure LiteSpeed services are running properly""" + preFlightsChecks.stdOut("Ensuring LiteSpeed services are running...") + + # Fix LiteSpeed permissions first + self.fixLiteSpeedPermissions() + + # Restart LiteSpeed services + litespeed_services = ['lsws', 'lscpd'] + for service in litespeed_services: + if subprocess.run(['systemctl', 'list-unit-files'], capture_output=True, text=True).stdout.find(f'{service}.service') != -1: + preFlightsChecks.stdOut(f"Restarting {service}...") + command = f'systemctl restart {service}' + preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + + # Enable service for auto-start + command = f'systemctl enable {service}' + preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + + # Verify service is running + command = f'systemctl is-active {service}' try: output = subprocess.check_output(shlex.split(command)).decode("utf-8").strip() if output == 'active': - preFlightsChecks.stdOut("Pure-FTPd service started successfully!") + preFlightsChecks.stdOut(f"{service} is running successfully!") else: - preFlightsChecks.stdOut("[WARNING] Pure-FTPd service may not have started properly. Status: " + output) + preFlightsChecks.stdOut(f"[WARNING] {service} status: {output}") except: - preFlightsChecks.stdOut("[WARNING] Could not verify Pure-FTPd service status") + preFlightsChecks.stdOut(f"[WARNING] Could not verify {service} status") + + def fixLiteSpeedPermissions(self): + """Fix LiteSpeed directory permissions""" + preFlightsChecks.stdOut("Fixing LiteSpeed permissions...") + + litespeed_dirs = ['/usr/local/lsws', '/usr/local/lscp', '/usr/local/CyberCP'] + for directory in litespeed_dirs: + if os.path.exists(directory): + command = f'chown -R lscpd:lscpd {directory}' + preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + + command = f'chmod -R 755 {directory}' + preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + + def verifyCriticalServices(self): + """Verify that all critical services are running""" + preFlightsChecks.stdOut("Verifying critical services...") + + critical_services = ['lsws', 'lscpd'] + all_services_ok = True + + for service in critical_services: + if subprocess.run(['systemctl', 'list-unit-files'], capture_output=True, text=True).stdout.find(f'{service}.service') != -1: + command = f'systemctl is-active {service}' + try: + output = subprocess.check_output(shlex.split(command)).decode("utf-8").strip() + if output == 'active': + preFlightsChecks.stdOut(f"✓ {service} is running") + else: + preFlightsChecks.stdOut(f"✗ {service} is not running (status: {output})") + all_services_ok = False + except: + preFlightsChecks.stdOut(f"✗ Could not verify {service} status") + all_services_ok = False + + if all_services_ok: + preFlightsChecks.stdOut("All critical services are running successfully!") + preFlightsChecks.stdOut("CyberPanel should now be accessible at https://your-server-ip:8090") + else: + preFlightsChecks.stdOut("[WARNING] Some critical services are not running properly") + preFlightsChecks.stdOut("Please check the logs and consider running: systemctl restart lsws lscpd") def configure_jwt_secret(): try: diff --git a/plogical/upgrade.py b/plogical/upgrade.py index 0be2b7c18..f3e28cbef 100644 --- a/plogical/upgrade.py +++ b/plogical/upgrade.py @@ -3656,7 +3656,7 @@ echo $oConfig->Save() ? 'Done' : 'Error'; @staticmethod def fixLiteSpeedConfig(): - """Fix LiteSpeed configuration issues by creating missing files""" + """Fix LiteSpeed configuration issues by creating missing files and fixing permissions""" try: Upgrade.stdOut("Checking and fixing LiteSpeed configuration...", 1) @@ -3665,11 +3665,23 @@ echo $oConfig->Save() ? 'Done' : 'Error'; Upgrade.stdOut("LiteSpeed not found at /usr/local/lsws", 0) return + # Fix LiteSpeed permissions first + Upgrade.stdOut("Fixing LiteSpeed permissions...", 1) + litespeed_dirs = ['/usr/local/lsws', '/usr/local/lscp', '/usr/local/CyberCP'] + for directory in litespeed_dirs: + if os.path.exists(directory): + command = f'chown -R lscpd:lscpd {directory}' + Upgrade.executioner(command, f'Fix ownership for {directory}', 0) + + command = f'chmod -R 755 {directory}' + Upgrade.executioner(command, f'Fix permissions for {directory}', 0) + # Create missing configuration files config_files = [ "/usr/local/lsws/conf/httpd_config.xml", "/usr/local/lsws/conf/httpd.conf", - "/usr/local/lsws/conf/modsec.conf" + "/usr/local/lscp/conf/httpd_config.xml", + "/usr/local/lscp/conf/httpd.conf" ] for config_file in config_files: @@ -3694,18 +3706,396 @@ echo $oConfig->Save() ? 'Done' : 'Error'; with open(config_file, 'w') as f: f.write('# Minimal LiteSpeed HTTP configuration\n') f.write('# This file will be updated by CyberPanel\n') - elif config_file.endswith('modsec.conf'): - with open(config_file, 'w') as f: - f.write('# ModSecurity configuration\n') - f.write('# This file will be updated by CyberPanel\n') + + # Set proper permissions + os.chmod(config_file, 0o644) + command = f'chown lscpd:lscpd {config_file}' + Upgrade.executioner(command, f'Fix config ownership: {config_file}', 0) Upgrade.stdOut(f"Created minimal config: {config_file}", 1) else: Upgrade.stdOut(f"LiteSpeed config exists: {config_file}", 1) + + # Create PHP socket directory if it doesn't exist + php_sock_dir = '/var/run/php/' + if not os.path.exists(php_sock_dir): + Upgrade.stdOut("Creating PHP socket directory...", 1) + os.makedirs(php_sock_dir, exist_ok=True) + command = f'chmod 755 {php_sock_dir}' + Upgrade.executioner(command, 'Fix PHP socket directory permissions', 0) + + # Set ownership based on distribution + osType = Upgrade.decideDistro() + if osType in [Upgrade.centos, Upgrade.cent8, Upgrade.cloudlinux]: + command = f'chown apache:apache {php_sock_dir}' + else: + command = f'chown www-data:www-data {php_sock_dir}' + Upgrade.executioner(command, 'Fix PHP socket directory ownership', 0) + + # Restart LiteSpeed services to apply changes + Upgrade.stdOut("Restarting LiteSpeed services...", 1) + litespeed_services = ['lsws', 'lscpd'] + for service in litespeed_services: + command = f'systemctl restart {service}' + Upgrade.executioner(command, f'Restart {service}', 0) + + command = f'systemctl enable {service}' + Upgrade.executioner(command, f'Enable {service}', 0) + + # Verify service is running + command = f'systemctl is-active {service}' + try: + result = subprocess.run(command, shell=True, capture_output=True, text=True) + if result.stdout.strip() == 'active': + Upgrade.stdOut(f"{service} is running successfully", 1) + else: + Upgrade.stdOut(f"{service} status: {result.stdout.strip()}", 0) + except: + Upgrade.stdOut(f"Could not verify {service} status", 0) except Exception as e: Upgrade.stdOut(f"Error fixing LiteSpeed config: {str(e)}", 0) + @staticmethod + def fixServiceConfiguration(): + """Comprehensive service configuration fix for common 503 error causes""" + try: + Upgrade.stdOut("Applying comprehensive service configuration fixes...", 1) + + # Upgrade pip first for better package compatibility + Upgrade.upgradePip() + + # Fix PowerDNS configuration + Upgrade.fixPowerDNSConfig() + + # Fix Pure-FTPd configuration + Upgrade.fixPureFTPdConfig() + + # Fix database connectivity + Upgrade.fixDatabaseConnectivity() + + # Fix PHP-FPM services + Upgrade.fixPHPFPMServices() + + # Final service restart and verification + Upgrade.restartAndVerifyServices() + + except Exception as e: + Upgrade.stdOut(f"Error in service configuration fix: {str(e)}", 0) + + @staticmethod + def upgradePip(): + """Upgrade pip to latest version for better package compatibility""" + try: + Upgrade.stdOut("Upgrading pip to latest version...", 1) + + # Determine the correct Python path + python_paths = [ + "/usr/local/CyberPanel/bin/python", + "/usr/local/CyberCP/bin/python", + "/usr/bin/python3", + "/usr/local/bin/python3" + ] + + python_path = None + for path in python_paths: + if os.path.exists(path): + python_path = path + break + + if not python_path: + Upgrade.stdOut("No Python executable found for pip upgrade", 0) + return False + + # Upgrade pip and essential packages + upgrade_command = f"{python_path} -m pip install --upgrade pip setuptools wheel packaging" + result = Upgrade.executioner(upgrade_command, "Upgrade pip", 0) + + if result == 1: + Upgrade.stdOut("pip upgraded successfully", 1) + return True + else: + Upgrade.stdOut("WARNING: pip upgrade failed, continuing with current version", 0) + return False + + except Exception as e: + Upgrade.stdOut(f"Error upgrading pip: {str(e)}", 0) + return False + + @staticmethod + def fixPowerDNSConfig(): + """Fix PowerDNS configuration issues""" + try: + Upgrade.stdOut("Fixing PowerDNS configuration...", 1) + + # Check if PowerDNS is installed + if not os.path.exists('/home/cyberpanel/powerdns'): + Upgrade.stdOut("PowerDNS not enabled, skipping...", 1) + return + + # Determine correct service name + pdns_service = None + result = subprocess.run(['systemctl', 'list-unit-files'], capture_output=True, text=True) + if 'pdns.service' in result.stdout: + pdns_service = 'pdns' + elif 'powerdns.service' in result.stdout: + pdns_service = 'powerdns' + + if not pdns_service: + Upgrade.stdOut("PowerDNS service not found", 0) + return + + # Fix PowerDNS configuration files + config_files = ['/etc/pdns/pdns.conf', '/etc/powerdns/pdns.conf'] + for config_file in config_files: + if os.path.exists(config_file): + Upgrade.stdOut(f"Configuring PowerDNS: {config_file}", 1) + + # Read existing content + with open(config_file, 'r') as f: + content = f.read() + + # Add missing configuration if not present + if 'gmysql-password=' not in content: + content += '\ngmysql-password=cyberpanel\n' + if 'launch=' not in content: + content += 'launch=gmysql\n' + + # Write back the configuration + with open(config_file, 'w') as f: + f.write(content) + + # Set proper permissions + os.chmod(config_file, 0o644) + command = f'chown root:root {config_file}' + Upgrade.executioner(command, f'Fix PowerDNS config ownership', 0) + break + + # Restart PowerDNS service + command = f'systemctl restart {pdns_service}' + Upgrade.executioner(command, f'Restart PowerDNS', 0) + + command = f'systemctl enable {pdns_service}' + Upgrade.executioner(command, f'Enable PowerDNS', 0) + + # Verify service is running + command = f'systemctl is-active {pdns_service}' + result = subprocess.run(command, shell=True, capture_output=True, text=True) + if result.stdout.strip() == 'active': + Upgrade.stdOut("PowerDNS is running successfully", 1) + else: + Upgrade.stdOut(f"PowerDNS status: {result.stdout.strip()}", 0) + + except Exception as e: + Upgrade.stdOut(f"Error fixing PowerDNS config: {str(e)}", 0) + + @staticmethod + def fixPureFTPdConfig(): + """Fix Pure-FTPd configuration issues""" + try: + Upgrade.stdOut("Fixing Pure-FTPd configuration...", 1) + + # Check if Pure-FTPd is installed + if not os.path.exists('/home/cyberpanel/pureftpd'): + Upgrade.stdOut("Pure-FTPd not enabled, skipping...", 1) + return + + # Determine correct service name + ftp_service = None + result = subprocess.run(['systemctl', 'list-unit-files'], capture_output=True, text=True) + if 'pure-ftpd.service' in result.stdout: + ftp_service = 'pure-ftpd' + elif 'pureftpd.service' in result.stdout: + ftp_service = 'pureftpd' + + if not ftp_service: + Upgrade.stdOut("Pure-FTPd service not found", 0) + return + + # Fix Pure-FTPd configuration files + config_files = ['/etc/pure-ftpd/pureftpd-mysql.conf', '/etc/pure-ftpd/db/mysql.conf'] + for config_file in config_files: + if os.path.exists(config_file): + Upgrade.stdOut(f"Configuring Pure-FTPd: {config_file}", 1) + + # Fix MySQL password configuration + command = f"sed -i 's/MYSQLPassword.*/MYSQLPassword cyberpanel/' {config_file}" + Upgrade.executioner(command, f'Fix Pure-FTPd MySQL password', 0) + + # Fix MySQL crypt method for Ubuntu 24.04 compatibility + command = f"sed -i 's/MYSQLCrypt md5/MYSQLCrypt crypt/g' {config_file}" + Upgrade.executioner(command, f'Fix Pure-FTPd MySQL crypt method', 0) + + # Set proper permissions + os.chmod(config_file, 0o644) + command = f'chown root:root {config_file}' + Upgrade.executioner(command, f'Fix Pure-FTPd config ownership', 0) + + # Restart Pure-FTPd service + command = f'systemctl restart {ftp_service}' + Upgrade.executioner(command, f'Restart Pure-FTPd', 0) + + command = f'systemctl enable {ftp_service}' + Upgrade.executioner(command, f'Enable Pure-FTPd', 0) + + # Verify service is running + command = f'systemctl is-active {ftp_service}' + result = subprocess.run(command, shell=True, capture_output=True, text=True) + if result.stdout.strip() == 'active': + Upgrade.stdOut("Pure-FTPd is running successfully", 1) + else: + Upgrade.stdOut(f"Pure-FTPd status: {result.stdout.strip()}", 0) + + except Exception as e: + Upgrade.stdOut(f"Error fixing Pure-FTPd config: {str(e)}", 0) + + @staticmethod + def fixDatabaseConnectivity(): + """Fix database connectivity issues""" + try: + Upgrade.stdOut("Fixing database connectivity...", 1) + + # Determine database service name + db_service = None + result = subprocess.run(['systemctl', 'list-unit-files'], capture_output=True, text=True) + if 'mariadb.service' in result.stdout: + db_service = 'mariadb' + elif 'mysql.service' in result.stdout: + db_service = 'mysql' + elif 'mysqld.service' in result.stdout: + db_service = 'mysqld' + + if not db_service: + Upgrade.stdOut("Database service not found", 0) + return + + # Ensure database service is running + command = f'systemctl restart {db_service}' + Upgrade.executioner(command, f'Restart database service', 0) + + command = f'systemctl enable {db_service}' + Upgrade.executioner(command, f'Enable database service', 0) + + # Wait for database to be ready + Upgrade.stdOut("Waiting for database to be ready...", 1) + max_attempts = 30 + for attempt in range(max_attempts): + try: + result = subprocess.run(['mysqladmin', 'ping', '-h', 'localhost', '--silent'], + capture_output=True) + if result.returncode == 0: + Upgrade.stdOut("Database is ready", 1) + break + except: + pass + time.sleep(2) + + # Ensure cyberpanel database exists + try: + result = subprocess.run(['mysql', '-e', 'USE cyberpanel;'], capture_output=True) + if result.returncode != 0: + Upgrade.stdOut("Creating cyberpanel database...", 1) + commands = [ + 'mysql -e "CREATE DATABASE IF NOT EXISTS cyberpanel;"', + 'mysql -e "CREATE USER IF NOT EXISTS \'cyberpanel\'@\'localhost\' IDENTIFIED BY \'cyberpanel\';"', + 'mysql -e "GRANT ALL PRIVILEGES ON cyberpanel.* TO \'cyberpanel\'@\'localhost\';"', + 'mysql -e "FLUSH PRIVILEGES;"' + ] + for cmd in commands: + Upgrade.executioner(cmd, 'Setup cyberpanel database', 0) + except: + Upgrade.stdOut("Could not verify cyberpanel database", 0) + + except Exception as e: + Upgrade.stdOut(f"Error fixing database connectivity: {str(e)}", 0) + + @staticmethod + def fixPHPFPMServices(): + """Fix PHP-FPM services""" + try: + Upgrade.stdOut("Fixing PHP-FPM services...", 1) + + # Get available PHP versions + php_versions = Upgrade.get_available_php_versions() + + for version in php_versions: + # Determine FPM service name based on distribution + osType = Upgrade.decideDistro() + if osType in [Upgrade.centos, Upgrade.cent8, Upgrade.cloudlinux]: + fpm_service = f'php{version}-php-fpm' + else: + fpm_service = f'php{version}-fpm' + + # Check if service exists and restart it + result = subprocess.run(['systemctl', 'list-unit-files'], capture_output=True, text=True) + if f'{fpm_service}.service' in result.stdout: + Upgrade.stdOut(f"Restarting PHP-FPM {version}...", 1) + command = f'systemctl restart {fpm_service}' + Upgrade.executioner(command, f'Restart PHP-FPM {version}', 0) + + command = f'systemctl enable {fpm_service}' + Upgrade.executioner(command, f'Enable PHP-FPM {version}', 0) + + # Verify service is running + command = f'systemctl is-active {fpm_service}' + result = subprocess.run(command, shell=True, capture_output=True, text=True) + if result.stdout.strip() == 'active': + Upgrade.stdOut(f"PHP-FPM {version} is running", 1) + else: + Upgrade.stdOut(f"PHP-FPM {version} status: {result.stdout.strip()}", 0) + + except Exception as e: + Upgrade.stdOut(f"Error fixing PHP-FPM services: {str(e)}", 0) + + @staticmethod + def restartAndVerifyServices(): + """Restart and verify all critical services""" + try: + Upgrade.stdOut("Restarting and verifying critical services...", 1) + + # Reload systemd daemon + command = 'systemctl daemon-reload' + Upgrade.executioner(command, 'Reload systemd daemon', 0) + + # Restart critical services in order + critical_services = ['lsws', 'lscpd'] + all_services_ok = True + + for service in critical_services: + # Check if service exists before trying to manage it + check_command = f'systemctl list-unit-files | grep -q "{service}.service"' + result = subprocess.run(check_command, shell=True, capture_output=True) + + if result.returncode != 0: + Upgrade.stdOut(f"Service {service} not found, skipping management", 1) + continue + + Upgrade.stdOut(f"Restarting {service}...", 1) + command = f'systemctl restart {service}' + Upgrade.executioner(command, f'Restart {service}', 0) + + command = f'systemctl enable {service}' + Upgrade.executioner(command, f'Enable {service}', 0) + + # Verify service is running + command = f'systemctl is-active {service}' + result = subprocess.run(command, shell=True, capture_output=True, text=True) + if result.stdout.strip() == 'active': + Upgrade.stdOut(f"✓ {service} is running successfully", 1) + else: + Upgrade.stdOut(f"✗ {service} is not running (status: {result.stdout.strip()})", 0) + all_services_ok = False + + if all_services_ok: + Upgrade.stdOut("All critical services are running successfully!", 1) + Upgrade.stdOut("CyberPanel should now be accessible at https://your-server-ip:8090", 1) + else: + Upgrade.stdOut("Some critical services are not running properly", 0) + Upgrade.stdOut("Please check the logs and consider a server restart", 0) + + except Exception as e: + Upgrade.stdOut(f"Error in service verification: {str(e)}", 0) + @staticmethod def installPHP73(): try: @@ -4564,6 +4954,9 @@ slowlog = /var/log/php{version}-fpm-slow.log # Fix LiteSpeed configuration files if missing Upgrade.fixLiteSpeedConfig() + # Fix comprehensive service configuration issues (503 error prevention) + Upgrade.fixServiceConfiguration() + # Fix subdomain log configurations Upgrade.fixSubdomainLogConfigurations() diff --git a/scripts/block_ip.py b/scripts/block_ip.py deleted file mode 100644 index ba326adf8..000000000 --- a/scripts/block_ip.py +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/local/CyberCP/bin/python -""" -Quick IP blocking script for CyberPanel -Usage: python block_ip.py [reason] -""" - -import sys -import os -import django - -# Add CyberPanel to Python path -sys.path.append('/usr/local/CyberCP') -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "CyberCP.settings") - -try: - django.setup() -except: - pass - -from plogical.firewallUtilities import FirewallUtilities - -def main(): - if len(sys.argv) < 2: - print("Usage: python block_ip.py [reason]") - print("Example: python block_ip.py 192.168.1.100 'Suspicious activity'") - sys.exit(1) - - ip_address = sys.argv[1] - reason = sys.argv[2] if len(sys.argv) > 2 else "Manual block via CLI" - - print(f"Blocking IP address: {ip_address}") - print(f"Reason: {reason}") - - success, message = FirewallUtilities.blockIP(ip_address, reason) - - if success: - print(f"✅ {message}") - sys.exit(0) - else: - print(f"❌ {message}") - sys.exit(1) - -if __name__ == "__main__": - main()