2025-08-01 14:56:30 +05:00
import sys
import subprocess
import shutil
import installLog as logging
import argparse
import os
import shlex
from firewallUtilities import FirewallUtilities
import time
import string
import random
import socket
from os . path import *
from stat import *
import stat
import secrets
import install_utils
VERSION = ' 2.4 '
2025-09-01 13:11:42 +05:00
BUILD = 4
2025-08-01 14:56:30 +05:00
# Using shared char_set from install_utils
char_set = install_utils . char_set
# Using shared function from install_utils
generate_pass = install_utils . generate_pass
# There can not be peace without first a great suffering.
# distros - using from install_utils
centos = install_utils . centos
ubuntu = install_utils . ubuntu
cent8 = install_utils . cent8
openeuler = install_utils . openeuler
2025-09-18 01:58:24 +05:00
debian12 = install_utils . debian12
2025-08-01 14:56:30 +05:00
cent9 = 4 # Not in install_utils yet
CloudLinux8 = 0 # Not in install_utils yet
# Using shared function from install_utils
FetchCloudLinuxAlmaVersionVersion = install_utils . FetchCloudLinuxAlmaVersionVersion
# Using shared function from install_utils
get_distro = install_utils . get_distro
def get_Ubuntu_release ( ) :
release = install_utils . get_Ubuntu_release ( use_print = False , exit_on_error = True )
if release == - 1 :
preFlightsChecks . stdOut ( " Can ' t find distro release name in /etc/lsb-release - fatal error " , 1 , 1 ,
os . EX_UNAVAILABLE )
return release
class preFlightsChecks :
debug = 1
cyberPanelMirror = " mirror.cyberpanel.net/pip "
cdn = ' cyberpanel.sh '
SnappyVersion = ' 2.38.2 '
apt_updated = False # Track if apt update has been run
def install_package ( self , package_name , options = " " , silent = False ) :
""" Unified package installation across distributions """
command , shell = install_utils . get_package_install_command ( self . distro , package_name , options )
if not silent :
return preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR , shell )
else :
return preFlightsChecks . call ( command , self . distro , command , command , 0 , 0 , os . EX_OSERR , shell )
def is_centos_family ( self ) :
""" Check if distro is CentOS, CentOS 8, or OpenEuler """
return self . distro in [ centos , cent8 , openeuler ]
2025-09-18 01:58:24 +05:00
def is_debian_family ( self ) :
""" Check if distro is Ubuntu or Debian 12 """
return self . distro in [ ubuntu , debian12 ]
2025-09-24 17:29:33 +02:00
def detect_os_info ( self ) :
""" Detect OS information for all supported platforms """
os_info = {
' name ' : ' unknown ' ,
' version ' : ' unknown ' ,
' major_version ' : 0 ,
' family ' : ' unknown '
}
# Check for Ubuntu
if os . path . exists ( ' /etc/os-release ' ) :
with open ( ' /etc/os-release ' , ' r ' ) as f :
content = f . read ( )
if ' Ubuntu ' in content :
os_info [ ' family ' ] = ' ubuntu '
os_info [ ' name ' ] = ' ubuntu '
# Extract version
for line in content . split ( ' \n ' ) :
if line . startswith ( ' VERSION_ID= ' ) :
version = line . split ( ' = ' ) [ 1 ] . strip ( ' " ' )
os_info [ ' version ' ] = version
os_info [ ' major_version ' ] = int ( version . split ( ' . ' ) [ 0 ] )
break
elif ' Debian ' in content :
os_info [ ' family ' ] = ' debian '
os_info [ ' name ' ] = ' debian '
for line in content . split ( ' \n ' ) :
if line . startswith ( ' VERSION_ID= ' ) :
version = line . split ( ' = ' ) [ 1 ] . strip ( ' " ' )
os_info [ ' version ' ] = version
os_info [ ' major_version ' ] = int ( version )
break
elif ' AlmaLinux ' in content :
os_info [ ' family ' ] = ' rhel '
os_info [ ' name ' ] = ' almalinux '
for line in content . split ( ' \n ' ) :
if line . startswith ( ' VERSION_ID= ' ) :
version = line . split ( ' = ' ) [ 1 ] . strip ( ' " ' )
os_info [ ' version ' ] = version
os_info [ ' major_version ' ] = int ( version . split ( ' . ' ) [ 0 ] )
break
elif ' Rocky Linux ' in content :
os_info [ ' family ' ] = ' rhel '
os_info [ ' name ' ] = ' rocky '
for line in content . split ( ' \n ' ) :
if line . startswith ( ' VERSION_ID= ' ) :
version = line . split ( ' = ' ) [ 1 ] . strip ( ' " ' )
os_info [ ' version ' ] = version
os_info [ ' major_version ' ] = int ( version . split ( ' . ' ) [ 0 ] )
break
elif ' Red Hat Enterprise Linux ' in content :
os_info [ ' family ' ] = ' rhel '
os_info [ ' name ' ] = ' rhel '
for line in content . split ( ' \n ' ) :
if line . startswith ( ' VERSION_ID= ' ) :
version = line . split ( ' = ' ) [ 1 ] . strip ( ' " ' )
os_info [ ' version ' ] = version
os_info [ ' major_version ' ] = int ( version . split ( ' . ' ) [ 0 ] )
break
elif ' CloudLinux ' in content :
os_info [ ' family ' ] = ' rhel '
os_info [ ' name ' ] = ' cloudlinux '
for line in content . split ( ' \n ' ) :
if line . startswith ( ' VERSION_ID= ' ) :
version = line . split ( ' = ' ) [ 1 ] . strip ( ' " ' )
os_info [ ' version ' ] = version
os_info [ ' major_version ' ] = int ( version . split ( ' . ' ) [ 0 ] )
break
# Check for CentOS (legacy)
if os . path . exists ( ' /etc/redhat-release ' ) :
with open ( ' /etc/redhat-release ' , ' r ' ) as f :
content = f . read ( )
if ' CentOS ' in content :
os_info [ ' family ' ] = ' rhel '
os_info [ ' name ' ] = ' centos '
# Extract version from CentOS release
import re
match = re . search ( r ' CentOS.*?( \ d+) ' , content )
if match :
os_info [ ' major_version ' ] = int ( match . group ( 1 ) )
os_info [ ' version ' ] = match . group ( 1 )
return os_info
def is_almalinux9 ( self ) :
""" Check if running on AlmaLinux 9 """
os_info = self . detect_os_info ( )
return os_info [ ' name ' ] == ' almalinux ' and os_info [ ' major_version ' ] == 9
def is_ubuntu ( self ) :
""" Check if running on Ubuntu """
os_info = self . detect_os_info ( )
return os_info [ ' family ' ] == ' ubuntu '
def is_debian ( self ) :
""" Check if running on Debian """
os_info = self . detect_os_info ( )
return os_info [ ' family ' ] == ' debian '
def is_rhel_family ( self ) :
""" Check if running on RHEL family (RHEL, AlmaLinux, Rocky, CloudLinux, CentOS) """
os_info = self . detect_os_info ( )
return os_info [ ' family ' ] == ' rhel '
def get_os_specific_fixes_needed ( self ) :
""" Determine which fixes are needed for the current OS """
os_info = self . detect_os_info ( )
fixes = [ ]
if os_info [ ' name ' ] == ' almalinux ' and os_info [ ' major_version ' ] == 9 :
fixes . extend ( [ ' mariadb ' , ' services ' , ' litespeed ' , ' mysql_gpg ' ] )
elif os_info [ ' name ' ] == ' almalinux ' and os_info [ ' major_version ' ] == 10 :
fixes . extend ( [ ' mariadb ' , ' services ' , ' litespeed ' ] )
elif os_info [ ' name ' ] == ' rocky ' and os_info [ ' major_version ' ] > = 8 :
fixes . extend ( [ ' mariadb ' , ' services ' ] )
elif os_info [ ' name ' ] == ' rhel ' and os_info [ ' major_version ' ] > = 8 :
fixes . extend ( [ ' mariadb ' , ' services ' ] )
elif os_info [ ' name ' ] == ' cloudlinux ' and os_info [ ' major_version ' ] > = 8 :
fixes . extend ( [ ' mariadb ' , ' services ' ] )
elif os_info [ ' name ' ] == ' centos ' and os_info [ ' major_version ' ] == 7 :
fixes . extend ( [ ' legacy_centos ' ] )
elif os_info [ ' family ' ] == ' ubuntu ' :
fixes . extend ( [ ' ubuntu_specific ' ] )
elif os_info [ ' family ' ] == ' debian ' :
fixes . extend ( [ ' debian_specific ' ] )
return fixes
2025-09-24 20:51:46 +02:00
def fix_almalinux9_comprehensive ( self ) :
""" Apply comprehensive AlmaLinux 9 fixes """
2025-09-24 17:29:33 +02:00
if not self . is_almalinux9 ( ) :
return
2025-09-24 20:51:46 +02:00
self . stdOut ( " Applying comprehensive AlmaLinux 9 fixes... " , 1 )
2025-09-24 17:29:33 +02:00
try :
2025-09-24 20:51:46 +02:00
# Update system packages
self . stdOut ( " Updating system packages... " , 1 )
command = " dnf update -y "
2025-09-24 17:29:33 +02:00
self . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-09-24 20:51:46 +02:00
# Install essential build tools and dependencies
self . stdOut ( " Installing essential build tools... " , 1 )
command = " dnf groupinstall -y ' Development Tools ' "
2025-09-24 17:29:33 +02:00
self . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-09-24 20:51:46 +02:00
command = " dnf install -y epel-release "
2025-09-24 17:29:33 +02:00
self . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-09-25 00:56:00 +02:00
# Install AlmaLinux 9 compatibility packages
self . stdOut ( " Installing AlmaLinux 9 compatibility packages... " , 1 )
compat_packages = [
" libxcrypt-compat " ,
" libnsl " ,
" compat-openssl11 " ,
" compat-openssl11-devel "
]
for package in compat_packages :
command = f " dnf install -y { package } "
2025-09-25 02:12:33 +02:00
self . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-09-25 00:56:00 +02:00
# Install PHP dependencies that are missing (with AlmaLinux 9 compatibility)
2025-09-24 20:51:46 +02:00
self . stdOut ( " Installing PHP dependencies... " , 1 )
2025-09-25 00:56:00 +02:00
# Base packages that should work on all systems
base_deps = [
2025-09-24 20:51:46 +02:00
" ImageMagick " , " ImageMagick-devel " ,
" gd " , " gd-devel " ,
" libicu " , " libicu-devel " ,
" oniguruma " , " oniguruma-devel " ,
" aspell " , " aspell-devel " ,
" freetype-devel " ,
" libjpeg-turbo-devel " ,
" libpng-devel " ,
" libwebp-devel " ,
" libXpm-devel " ,
" libzip-devel " ,
" openssl-devel " ,
" sqlite-devel " ,
" libxml2-devel " ,
" libxslt-devel " ,
" curl-devel " ,
" libedit-devel " ,
" readline-devel " ,
" pkgconfig " ,
" cmake " ,
" gcc-c++ "
2025-09-24 17:29:33 +02:00
]
2025-09-24 20:51:46 +02:00
2025-09-25 00:56:00 +02:00
# Install base packages
for dep in base_deps :
2025-09-24 20:51:46 +02:00
command = f " dnf install -y { dep } "
self . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-09-25 00:56:00 +02:00
# Install AlmaLinux 9 specific packages with fallbacks
alma9_specific = [
( " libc-client " , " libc-client-devel " ) ,
( " libmemcached " , " libmemcached-devel " )
]
for package , dev_package in alma9_specific :
2025-09-25 02:12:33 +02:00
installed = False
2025-09-25 00:56:00 +02:00
2025-09-25 02:12:33 +02:00
# Try to install both packages together first
try :
command = f " dnf install -y { package } { dev_package } "
result = self . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
if result == 1 :
self . stdOut ( f " Successfully installed { package } and { dev_package } " , 1 )
installed = True
except :
pass
if not installed :
# Try to install packages individually
try :
command = f " dnf install -y { package } "
result = self . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
if result == 1 :
self . stdOut ( f " Successfully installed { package } " , 1 )
except :
pass
try :
dev_command = f " dnf install -y { dev_package } "
result = self . call ( dev_command , self . distro , dev_command , dev_command , 1 , 0 , os . EX_OSERR )
if result == 1 :
self . stdOut ( f " Successfully installed { dev_package } " , 1 )
installed = True
except :
pass
if not installed :
2025-09-25 00:56:00 +02:00
self . stdOut ( f " Package { package } not available, trying alternatives... " , 1 )
2025-09-25 02:12:33 +02:00
# For AlmaLinux 9, try enabling PowerTools repository first
if self . distro == openeuler and os_info [ ' name ' ] == ' almalinux ' and os_info [ ' major_version ' ] == ' 9 ' :
try :
self . stdOut ( " Enabling AlmaLinux 9 PowerTools repository... " , 1 )
self . call ( " dnf config-manager --set-enabled powertools " , self . distro , " Enable PowerTools " , " Enable PowerTools " , 1 , 0 , os . EX_OSERR )
# Try installing again with PowerTools enabled
command = f " dnf install -y { package } { dev_package } "
result = self . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-09-25 00:56:00 +02:00
if result == 1 :
2025-09-25 02:12:33 +02:00
self . stdOut ( f " Successfully installed { package } and { dev_package } from PowerTools " , 1 )
installed = True
except :
self . stdOut ( " PowerTools repository not available, trying alternatives... " , 1 )
if not installed :
# Try alternative package names for AlmaLinux 9
alternatives = {
" libc-client " : [ " libc-client-devel " , " uw-imap-devel " ] ,
" libmemcached " : [ " libmemcached-devel " , " memcached-devel " ]
}
if package in alternatives :
for alt_package in alternatives [ package ] :
alt_command = f " dnf install -y { alt_package } "
result = self . call ( alt_command , self . distro , alt_command , alt_command , 1 , 0 , os . EX_OSERR )
if result == 1 :
self . stdOut ( f " Successfully installed alternative: { alt_package } " , 1 )
break
2025-09-25 00:56:00 +02:00
# Install MariaDB with enhanced AlmaLinux 9.6 support
self . stdOut ( " Installing MariaDB for AlmaLinux 9.6... " , 1 )
# Try multiple installation methods for maximum compatibility
mariadb_commands = [
" dnf install -y mariadb-server mariadb-devel mariadb-client --skip-broken --nobest " ,
" dnf install -y mariadb-server mariadb-devel mariadb-client --allowerasing " ,
" dnf install -y mariadb-server mariadb-devel --skip-broken --nobest --allowerasing " ,
" dnf install -y mariadb-server --skip-broken --nobest --allowerasing "
]
mariadb_installed = False
for cmd in mariadb_commands :
try :
result = subprocess . run ( cmd , shell = True , capture_output = True , text = True , timeout = 300 )
if result . returncode == 0 :
mariadb_installed = True
self . stdOut ( f " MariaDB installed successfully with command: { cmd } " , 1 )
break
except subprocess . TimeoutExpired :
self . stdOut ( f " Timeout installing MariaDB with command: { cmd } " , 0 )
continue
except Exception as e :
self . stdOut ( f " Error installing MariaDB with command: { cmd } - { str ( e ) } " , 0 )
continue
if not mariadb_installed :
self . stdOut ( " MariaDB installation failed, trying MySQL as fallback... " , 0 )
try :
command = " dnf install -y mysql-server mysql-devel --skip-broken --nobest --allowerasing "
self . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
self . stdOut ( " MySQL installed as fallback for MariaDB " , 1 )
except :
self . stdOut ( " Both MariaDB and MySQL installation failed " , 0 )
2025-09-24 17:29:33 +02:00
2025-09-24 20:51:46 +02:00
# Install additional required packages
self . stdOut ( " Installing additional required packages... " , 1 )
additional_packages = [
" wget " , " curl " , " unzip " , " zip " , " rsync " ,
" firewalld " , " psmisc " , " git " , " python3 " ,
" python3-pip " , " python3-devel "
]
2025-09-24 17:29:33 +02:00
2025-09-24 20:51:46 +02:00
for package in additional_packages :
command = f " dnf install -y { package } "
self . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-09-24 17:29:33 +02:00
2025-09-24 20:51:46 +02:00
# Configure firewall
self . stdOut ( " Configuring firewall... " , 1 )
command = " systemctl enable firewalld "
self . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-09-24 17:29:33 +02:00
2025-09-24 20:51:46 +02:00
command = " systemctl start firewalld "
self . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
# Add required firewall ports
self . stdOut ( " Adding firewall ports... " , 1 )
ports = [
" 8090/tcp " , " 7080/tcp " , " 80/tcp " , " 443/tcp " ,
" 21/tcp " , " 25/tcp " , " 587/tcp " , " 465/tcp " ,
" 110/tcp " , " 143/tcp " , " 993/tcp " , " 995/tcp " ,
" 53/tcp " , " 53/udp " , " 8888/tcp " , " 40110-40210/tcp "
]
2025-09-24 17:29:33 +02:00
2025-09-24 20:51:46 +02:00
for port in ports :
command = f " firewall-cmd --permanent --add-port= { port } "
self . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = " firewall-cmd --reload "
self . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
self . stdOut ( " AlmaLinux 9 comprehensive fixes completed successfully! " , 1 )
2025-09-24 17:29:33 +02:00
except Exception as e :
2025-09-24 20:51:46 +02:00
self . stdOut ( f " Error applying AlmaLinux 9 comprehensive fixes: { str ( e ) } " , 0 )
2025-09-24 17:29:33 +02:00
def fix_rhel_family_common ( self ) :
""" Fix common RHEL family (AlmaLinux, Rocky, RHEL, CloudLinux) issues """
try :
self . stdOut ( " Applying RHEL family common fixes... " , 1 )
# Install EPEL repository
self . stdOut ( " Installing EPEL repository... " , 1 )
try :
self . call ( ' dnf install -y epel-release ' , self . distro , ' Installing EPEL ' , ' Installing EPEL ' , 1 , 1 , os . EX_OSERR )
except :
try :
self . call ( ' yum install -y epel-release ' , self . distro , ' Installing EPEL (yum) ' , ' Installing EPEL (yum) ' , 1 , 1 , os . EX_OSERR )
except :
self . stdOut ( " Warning: Could not install EPEL " , 1 )
# Apply graphics library fixes for RHEL 9+ systems
os_info = self . detect_os_info ( )
if os_info [ ' major_version ' ] > = 9 :
self . stdOut ( " Applying RHEL 9+ graphics library fixes... " , 1 )
try :
command = " dnf install -y --allowerasing mesa-dri-drivers mesa-filesystem mesa-libEGL mesa-libGL mesa-libgbm mesa-libglapi libdrm libglvnd libglvnd-glx libglvnd-egl "
self . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
self . stdOut ( " RHEL 9+ graphics library fixes applied successfully " , 1 )
except Exception as e :
self . stdOut ( f " Warning: Graphics library fixes failed: { str ( e ) } " , 1 )
# Install common dependencies
self . stdOut ( " Installing common RHEL dependencies... " , 1 )
common_deps = [
' curl ' ,
' wget ' ,
' git ' ,
' python3 ' ,
' python3-pip ' ,
' gcc ' ,
' gcc-c++ ' ,
' make ' ,
' cmake ' ,
' pcre2-devel ' ,
' openssl-devel ' ,
' zlib-devel '
]
for dep in common_deps :
try :
self . call ( f ' dnf install -y { dep } ' , self . distro , f ' Installing { dep } ' , f ' Installing { dep } ' , 1 , 0 , os . EX_OSERR )
except :
try :
self . call ( f ' yum install -y { dep } ' , self . distro , f ' Installing { dep } (yum) ' , f ' Installing { dep } (yum) ' , 1 , 0 , os . EX_OSERR )
except :
self . stdOut ( f " Warning: Could not install { dep } " , 1 )
return True
except Exception as e :
self . stdOut ( f " Error in fix_rhel_family_common: { str ( e ) } " , 0 )
return False
2025-09-25 01:34:57 +02:00
def fix_almalinux9_mariadb ( self ) :
""" Apply AlmaLinux 9 MariaDB fixes """
try :
self . stdOut ( " Applying AlmaLinux 9 MariaDB fixes... " , 1 )
2025-09-25 02:12:33 +02:00
# Get OS information for AlmaLinux 9 specific handling
os_info = self . detect_os_info ( )
2025-09-25 01:34:57 +02:00
# Install AlmaLinux 9 compatibility packages
self . stdOut ( " Installing AlmaLinux 9 compatibility packages... " , 1 )
compat_packages = [
" libxcrypt-compat " ,
" libnsl " ,
" compat-openssl11 " ,
" compat-openssl11-devel "
]
for package in compat_packages :
command = f " dnf install -y { package } "
self . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-09-25 02:12:33 +02:00
# Install problematic packages with enhanced fallback logic
self . stdOut ( " Installing AlmaLinux 9 specific packages with fallbacks... " , 1 )
alma9_specific = [
( " libc-client " , " libc-client-devel " ) ,
( " libmemcached " , " libmemcached-devel " )
]
for package , dev_package in alma9_specific :
installed = False
# Try to install both packages together first
try :
command = f " dnf install -y { package } { dev_package } "
result = self . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
if result == 1 :
self . stdOut ( f " Successfully installed { package } and { dev_package } " , 1 )
installed = True
except :
pass
if not installed :
# Try enabling PowerTools repository for AlmaLinux 9
try :
self . stdOut ( " Enabling AlmaLinux 9 PowerTools repository... " , 1 )
self . call ( " dnf config-manager --set-enabled powertools " , self . distro , " Enable PowerTools " , " Enable PowerTools " , 1 , 0 , os . EX_OSERR )
# Try installing again with PowerTools enabled
command = f " dnf install -y { package } { dev_package } "
result = self . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
if result == 1 :
self . stdOut ( f " Successfully installed { package } and { dev_package } from PowerTools " , 1 )
installed = True
except :
self . stdOut ( " PowerTools repository not available, trying alternatives... " , 1 )
if not installed :
# Try alternative package names and repositories for AlmaLinux 9.6+
alternatives = {
" libc-client " : [ " libc-client-devel " , " uw-imap-devel " ] ,
" libmemcached " : [ " libmemcached-devel " , " memcached-devel " ]
}
if package in alternatives :
for alt_package in alternatives [ package ] :
# Try standard repository first
alt_command = f " dnf install -y { alt_package } "
result = self . call ( alt_command , self . distro , alt_command , alt_command , 1 , 0 , os . EX_OSERR )
if result == 1 :
self . stdOut ( f " Successfully installed alternative: { alt_package } " , 1 )
break
# Try remi repository for uw-imap-devel (AlmaLinux 9.6+)
if alt_package == " uw-imap-devel " :
try :
self . stdOut ( " Trying remi repository for uw-imap-devel... " , 1 )
# Enable remi repository
self . call ( " dnf install -y https://rpms.remirepo.net/enterprise/remi-release-9.rpm " , self . distro , " Install remi repo " , " Install remi repo " , 1 , 0 , os . EX_OSERR )
# Try installing from remi
remi_command = f " dnf install -y --enablerepo=remi { alt_package } "
result = self . call ( remi_command , self . distro , remi_command , remi_command , 1 , 0 , os . EX_OSERR )
if result == 1 :
self . stdOut ( f " Successfully installed { alt_package } from remi repository " , 1 )
break
except :
self . stdOut ( f " Remi repository installation failed for { alt_package } " , 1 )
# Try direct RPM download as last resort
if result != 1 :
try :
self . stdOut ( f " Trying direct RPM download for { alt_package } ... " , 1 )
rpm_urls = {
" uw-imap-devel " : " https://rhel.pkgs.org/9/remi-x86_64/uw-imap-devel-2007f-30.el9.remi.x86_64.rpm " ,
" libc-client-devel " : " https://pkgs.org/download/libc-client-devel "
}
if alt_package in rpm_urls :
# Download and install RPM directly
download_command = f " curl -L { rpm_urls [ alt_package ] } -o /tmp/ { alt_package } .rpm "
self . call ( download_command , self . distro , f " Download { alt_package } " , f " Download { alt_package } " , 1 , 0 , os . EX_OSERR )
install_command = f " rpm -ivh /tmp/ { alt_package } .rpm --force "
result = self . call ( install_command , self . distro , f " Install { alt_package } " , f " Install { alt_package } " , 1 , 0 , os . EX_OSERR )
if result == 1 :
self . stdOut ( f " Successfully installed { alt_package } via direct RPM download " , 1 )
# Clean up downloaded file
self . call ( f " rm -f /tmp/ { alt_package } .rpm " , self . distro , f " Cleanup { alt_package } " , f " Cleanup { alt_package } " , 1 , 0 , os . EX_OSERR )
break
except :
self . stdOut ( f " Direct RPM download failed for { alt_package } " , 1 )
2025-09-25 01:34:57 +02:00
self . stdOut ( " AlmaLinux 9 MariaDB fixes applied successfully " , 1 )
except Exception as e :
self . stdOut ( f " Error applying AlmaLinux 9 MariaDB fixes: { str ( e ) } " , 0 )
2025-09-25 02:12:33 +02:00
def install_package_with_fallbacks ( self , package_name , dev_package_name = None ) :
""" Install package with comprehensive fallback methods for AlmaLinux 9.6+ """
try :
installed = False
# Method 1: Try standard repository
if dev_package_name :
command = f " dnf install -y { package_name } { dev_package_name } "
else :
command = f " dnf install -y { package_name } "
result = self . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
if result == 1 :
self . stdOut ( f " Successfully installed { package_name } from standard repository " , 1 )
return True
# Method 2: Try PowerTools repository
try :
self . stdOut ( " Trying PowerTools repository... " , 1 )
self . call ( " dnf config-manager --set-enabled powertools " , self . distro , " Enable PowerTools " , " Enable PowerTools " , 1 , 0 , os . EX_OSERR )
result = self . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
if result == 1 :
self . stdOut ( f " Successfully installed { package_name } from PowerTools " , 1 )
return True
except :
pass
# Method 3: Try remi repository
try :
self . stdOut ( " Trying remi repository... " , 1 )
self . call ( " dnf install -y https://rpms.remirepo.net/enterprise/remi-release-9.rpm " , self . distro , " Install remi repo " , " Install remi repo " , 1 , 0 , os . EX_OSERR )
remi_command = f " dnf install -y --enablerepo=remi { package_name } "
result = self . call ( remi_command , self . distro , remi_command , remi_command , 1 , 0 , os . EX_OSERR )
if result == 1 :
self . stdOut ( f " Successfully installed { package_name } from remi repository " , 1 )
return True
except :
pass
# Method 4: Try direct RPM download
rpm_sources = {
" libc-client-devel " : " https://pkgs.org/download/libc-client-devel " ,
" uw-imap-devel " : " https://rhel.pkgs.org/9/remi-x86_64/uw-imap-devel-2007f-30.el9.remi.x86_64.rpm " ,
" libmemcached-devel " : " https://mirror.mariadb.org/yum/12.1/rhel9-amd64/rpms/libmemcached-devel-1.0.18-17.el8.x86_64.rpm "
}
for package in [ package_name , dev_package_name ] :
if package and package in rpm_sources :
try :
self . stdOut ( f " Trying direct RPM download for { package } ... " , 1 )
download_command = f " curl -L { rpm_sources [ package ] } -o /tmp/ { package } .rpm "
self . call ( download_command , self . distro , f " Download { package } " , f " Download { package } " , 1 , 0 , os . EX_OSERR )
install_command = f " rpm -ivh /tmp/ { package } .rpm --force "
result = self . call ( install_command , self . distro , f " Install { package } " , f " Install { package } " , 1 , 0 , os . EX_OSERR )
if result == 1 :
self . stdOut ( f " Successfully installed { package } via direct RPM download " , 1 )
# Clean up downloaded file
self . call ( f " rm -f /tmp/ { package } .rpm " , self . distro , f " Cleanup { package } " , f " Cleanup { package } " , 1 , 0 , os . EX_OSERR )
installed = True
except :
self . stdOut ( f " Direct RPM download failed for { package } " , 1 )
return installed
except Exception as e :
self . stdOut ( f " Error in package installation fallback: { str ( e ) } " , 0 )
return False
2025-09-24 17:29:33 +02:00
def fix_ubuntu_specific ( self ) :
""" Fix Ubuntu-specific installation issues """
try :
self . stdOut ( " Applying Ubuntu-specific fixes... " , 1 )
# Install required dependencies
self . stdOut ( " Installing Ubuntu dependencies... " , 1 )
ubuntu_deps = [
' software-properties-common ' ,
' apt-transport-https ' ,
' curl ' ,
' wget ' ,
' gnupg ' ,
' lsb-release '
]
for dep in ubuntu_deps :
try :
self . call ( f ' apt-get install -y { dep } ' , self . distro , f ' Installing { dep } ' , f ' Installing { dep } ' , 1 , 0 , os . EX_OSERR )
except :
self . stdOut ( f " Warning: Could not install { dep } " , 1 )
# Ubuntu 24.04 specific fixes
os_info = self . detect_os_info ( )
if os_info [ ' name ' ] == ' ubuntu ' and os_info [ ' major_version ' ] > = 24 :
self . stdOut ( " Applying Ubuntu 24.04 specific fixes... " , 1 )
try :
command = " DEBIAN_FRONTEND=noninteractive apt-get install -y python3-venv python3-dev "
self . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
self . stdOut ( " Ubuntu 24.04 specific fixes applied successfully " , 1 )
except Exception as e :
self . stdOut ( f " Warning: Ubuntu 24.04 fixes failed: { str ( e ) } " , 1 )
# Update package lists
self . call ( ' apt-get update ' , self . distro , ' Updating package lists ' , ' Updating package lists ' , 1 , 1 , os . EX_OSERR )
return True
except Exception as e :
self . stdOut ( f " Error in fix_ubuntu_specific: { str ( e ) } " , 0 )
return False
def fix_debian_specific ( self ) :
""" Fix Debian-specific installation issues """
try :
self . stdOut ( " Applying Debian-specific fixes... " , 1 )
# Install required dependencies
self . stdOut ( " Installing Debian dependencies... " , 1 )
debian_deps = [
' software-properties-common ' ,
' apt-transport-https ' ,
' curl ' ,
' wget ' ,
' gnupg ' ,
' lsb-release '
]
for dep in debian_deps :
try :
self . call ( f ' apt-get install -y { dep } ' , self . distro , f ' Installing { dep } ' , f ' Installing { dep } ' , 1 , 0 , os . EX_OSERR )
except :
self . stdOut ( f " Warning: Could not install { dep } " , 1 )
# Debian 13 specific fixes
os_info = self . detect_os_info ( )
if os_info [ ' name ' ] == ' debian ' and os_info [ ' major_version ' ] > = 13 :
self . stdOut ( " Applying Debian 13 specific fixes... " , 1 )
try :
command = " DEBIAN_FRONTEND=noninteractive apt-get install -y python3-venv python3-dev build-essential "
self . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
self . stdOut ( " Debian 13 specific fixes applied successfully " , 1 )
except Exception as e :
self . stdOut ( f " Warning: Debian 13 fixes failed: { str ( e ) } " , 1 )
# Update package lists
self . call ( ' apt-get update ' , self . distro , ' Updating package lists ' , ' Updating package lists ' , 1 , 1 , os . EX_OSERR )
return True
except Exception as e :
self . stdOut ( f " Error in fix_debian_specific: { str ( e ) } " , 0 )
return False
def apply_os_specific_fixes ( self ) :
""" Apply OS-specific fixes based on detected OS """
try :
os_info = self . detect_os_info ( )
fixes_needed = self . get_os_specific_fixes_needed ( )
self . stdOut ( f " Detected OS: { os_info [ ' name ' ] } { os_info [ ' version ' ] } (family: { os_info [ ' family ' ] } ) " , 1 )
self . stdOut ( f " Applying fixes: { ' , ' . join ( fixes_needed ) } " , 1 )
2025-09-25 09:35:42 +02:00
# Try universal OS fixes first
try :
import sys
import os
sys . path . append ( os . path . dirname ( __file__ ) )
from universal_os_fixes import UniversalOSFixes
self . stdOut ( " Applying universal OS compatibility fixes... " , 1 )
universal_fixes = UniversalOSFixes ( )
if universal_fixes . run_comprehensive_setup ( ) :
self . stdOut ( " Universal OS fixes applied successfully " , 1 )
return True
else :
self . stdOut ( " Universal OS fixes failed, falling back to legacy fixes... " , 1 )
except ImportError :
self . stdOut ( " Universal OS fixes not available, using legacy fixes... " , 1 )
except Exception as e :
self . stdOut ( f " Universal OS fixes error: { str ( e ) } , falling back to legacy fixes... " , 1 )
2025-09-24 17:29:33 +02:00
# Apply common RHEL family fixes first
if self . is_rhel_family ( ) :
self . fix_rhel_family_common ( )
# Apply specific fixes
for fix in fixes_needed :
if fix == ' mariadb ' and self . is_almalinux9 ( ) :
self . fix_almalinux9_mariadb ( )
elif fix == ' ubuntu_specific ' and self . is_ubuntu ( ) :
self . fix_ubuntu_specific ( )
elif fix == ' debian_specific ' and self . is_debian ( ) :
self . fix_debian_specific ( )
self . stdOut ( " OS-specific fixes completed successfully " , 1 )
return True
except Exception as e :
self . stdOut ( f " Error applying OS-specific fixes: { str ( e ) } " , 0 )
return False
def installLiteSpeed ( self , ent , serial ) :
""" Install LiteSpeed Web Server (OpenLiteSpeed or Enterprise) """
try :
self . stdOut ( " Installing LiteSpeed Web Server... " , 1 )
if ent == 0 :
# Install OpenLiteSpeed
self . stdOut ( " Installing OpenLiteSpeed... " , 1 )
if self . distro == ubuntu :
self . install_package ( ' openlitespeed ' )
else :
self . install_package ( ' openlitespeed ' )
# Configure OpenLiteSpeed
self . fix_ols_configs ( )
self . changePortTo80 ( )
else :
# Install LiteSpeed Enterprise
self . stdOut ( " Installing LiteSpeed Enterprise... " , 1 )
self . installLiteSpeedEnterprise ( serial )
self . stdOut ( " LiteSpeed Web Server installed successfully " , 1 )
return True
except Exception as e :
self . stdOut ( f " Error installing LiteSpeed: { str ( e ) } " , 0 )
return False
def installLiteSpeedEnterprise ( self , serial ) :
""" Install LiteSpeed Enterprise """
try :
# Get the latest LSWS Enterprise version
lsws_version = self . getLatestLSWSVersion ( )
# Download and install LiteSpeed Enterprise
if self . ISARM ( ) :
command = f ' wget https://www.litespeedtech.com/packages/6.0/lsws- { lsws_version } -ent-aarch64-linux.tar.gz '
else :
command = f ' wget https://www.litespeedtech.com/packages/6.0/lsws- { lsws_version } -ent-x86_64-linux.tar.gz '
self . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
if self . ISARM ( ) :
command = f ' tar zxf lsws- { lsws_version } -ent-aarch64-linux.tar.gz '
else :
command = f ' tar zxf lsws- { lsws_version } -ent-x86_64-linux.tar.gz '
self . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
# Handle license
if str . lower ( serial ) == ' trial ' :
command = f ' wget -q --output-document=lsws- { lsws_version } /trial.key http://license.litespeedtech.com/reseller/trial.key '
elif serial == ' 1111-2222-3333-4444 ' :
command = f ' wget -q --output-document=/root/cyberpanel/install/lsws- { lsws_version } /trial.key http://license.litespeedtech.com/reseller/trial.key '
self . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
else :
writeSerial = open ( f ' lsws- { lsws_version } /serial.no ' , ' w ' )
writeSerial . writelines ( serial )
writeSerial . close ( )
# Install LiteSpeed Enterprise
os . chdir ( f ' lsws- { lsws_version } ' )
command = ' chmod +x install.sh '
self . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
command = ' chmod +x functions.sh '
self . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
command = ' ./install.sh '
self . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
os . chdir ( self . cwd )
return True
except Exception as e :
self . stdOut ( f " Error installing LiteSpeed Enterprise: { str ( e ) } " , 0 )
return False
def getLatestLSWSVersion ( self ) :
""" Fetch the latest LSWS Enterprise version """
try :
import urllib . request
import re
url = " https://www.litespeedtech.com/products/litespeed-web-server/download "
req = urllib . request . Request ( url , headers = { ' User-Agent ' : ' Mozilla/5.0 ' } )
with urllib . request . urlopen ( req , timeout = 10 ) as response :
html = response . read ( ) . decode ( ' utf-8 ' )
version_pattern = r ' lsws-( \ d+ \ . \ d+ \ . \ d+)-ent '
versions = re . findall ( version_pattern , html )
if versions :
latest_version = sorted ( versions , key = lambda v : [ int ( x ) for x in v . split ( ' . ' ) ] ) [ - 1 ]
return latest_version
except :
pass
return " 6.3.4 " # Fallback version
def ISARM ( self ) :
""" Check if running on ARM architecture """
try :
command = ' uname -a '
result = subprocess . run ( command , capture_output = True , universal_newlines = True , shell = True )
return ' aarch64 ' in result . stdout
except :
return False
def installMySQL ( self , mysql ) :
""" Install MySQL/MariaDB """
try :
self . stdOut ( " Installing MySQL/MariaDB... " , 1 )
if self . distro == ubuntu :
# Ubuntu MariaDB installation
command = ' DEBIAN_FRONTEND=noninteractive apt-get install software-properties-common apt-transport-https curl -y '
self . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR , True )
command = " mkdir -p /etc/apt/keyrings "
self . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
command = " curl -o /etc/apt/keyrings/mariadb-keyring.pgp ' https://mariadb.org/mariadb_release_signing_key.pgp ' "
self . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
# Setup MariaDB repository
2025-09-24 23:45:28 +02:00
command = ' curl -LsS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | sudo bash -s -- --mariadb-server-version=12.1 '
2025-09-24 17:29:33 +02:00
self . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR , True )
command = ' DEBIAN_FRONTEND=noninteractive apt-get update -y '
self . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR , True )
command = " DEBIAN_FRONTEND=noninteractive apt-get install mariadb-server -y "
self . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR , True )
else :
# RHEL-based MariaDB installation
2025-09-24 23:45:28 +02:00
command = ' curl -LsS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | sudo bash -s -- --mariadb-server-version=12.1 '
2025-09-24 17:29:33 +02:00
self . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR , True )
command = ' dnf install mariadb-server mariadb-devel mariadb-client-utils -y '
self . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR , True )
# Start and enable MariaDB
self . startMariaDB ( )
self . changeMYSQLRootPassword ( )
self . fixMariaDB ( )
self . stdOut ( " MySQL/MariaDB installed successfully " , 1 )
return True
except Exception as e :
self . stdOut ( f " Error installing MySQL/MariaDB: { str ( e ) } " , 0 )
return False
def startMariaDB ( self ) :
""" Start MariaDB service """
try :
self . stdOut ( " Starting MariaDB service... " , 1 )
2025-09-24 20:51:46 +02:00
# Try different service names
service_names = [ ' mariadb ' , ' mysql ' , ' mysqld ' ]
started = False
for service_name in service_names :
try :
self . manage_service ( service_name , ' start ' )
self . manage_service ( service_name , ' enable ' )
self . stdOut ( f " Successfully started { service_name } service " , 1 )
started = True
break
except Exception as e :
self . stdOut ( f " Could not start { service_name } : { str ( e ) } " , 0 )
continue
if not started :
self . stdOut ( " Warning: Could not start MariaDB service " , 0 )
return False
2025-09-24 17:29:33 +02:00
return True
except Exception as e :
self . stdOut ( f " Error starting MariaDB: { str ( e ) } " , 0 )
return False
def changeMYSQLRootPassword ( self ) :
""" Change MySQL root password """
try :
if self . remotemysql == ' OFF ' :
passwordCMD = " use mysql;DROP DATABASE IF EXISTS test;DELETE FROM mysql.db WHERE Db= ' test ' OR Db= ' test \\ _ %% ' ;GRANT ALL PRIVILEGES ON *.* TO ' root ' @ ' localhost ' IDENTIFIED BY ' %s ' ;flush privileges; " % ( self . mysql_Root_password )
2025-09-28 13:19:30 +05:00
# Try socket authentication first (for fresh MariaDB installations)
socket_commands = [ ' sudo mysql ' , ' sudo mariadb ' , ' sudo /usr/bin/mysql ' , ' sudo /usr/bin/mariadb ' ]
password_commands = [ ' mysql -u root ' , ' mariadb -u root ' , ' /usr/bin/mysql -u root ' , ' /usr/bin/mariadb -u root ' ]
success = False
# First try socket authentication (common for fresh MariaDB installs)
self . stdOut ( " Attempting to set MySQL root password using socket authentication... " , 1 )
for cmd in socket_commands :
try :
if self . command_exists ( cmd . split ( ) [ - 1 ] ) : # Check if the mysql/mariadb command exists
command = f ' { cmd } -e " { passwordCMD } " '
result = subprocess . run ( command , shell = True , capture_output = True , text = True , timeout = 30 )
if result . returncode == 0 :
self . stdOut ( f " Successfully set MySQL root password using: { cmd } " , 1 )
success = True
break
else :
self . stdOut ( f " Socket auth failed with { cmd } : { result . stderr } " , 0 )
except Exception as e :
self . stdOut ( f " Error with socket auth { cmd } : { str ( e ) } " , 0 )
continue
# If socket auth failed, try traditional password-based connection
if not success :
self . stdOut ( " Socket authentication failed, trying traditional connection... " , 1 )
for cmd in password_commands :
try :
if self . command_exists ( cmd . split ( ) [ 0 ] ) : # Check if command exists
command = f ' { cmd } -e " { passwordCMD } " '
result = subprocess . run ( command , shell = True , capture_output = True , text = True , timeout = 30 )
if result . returncode == 0 :
self . stdOut ( f " Successfully set MySQL root password using: { cmd } " , 1 )
success = True
break
else :
self . stdOut ( f " Traditional auth failed with { cmd } : { result . stderr } " , 0 )
except Exception as e :
self . stdOut ( f " Error with traditional auth { cmd } : { str ( e ) } " , 0 )
continue
if not success :
self . stdOut ( " Failed to set MySQL root password with all methods. Database may need manual configuration. " , 0 )
# Still save the password file so manual fix is possible
self . ensure_mysql_password_file ( )
return False
2025-09-24 20:23:49 +02:00
# Save MySQL password to file for later use
2025-09-25 00:56:00 +02:00
self . ensure_mysql_password_file ( )
2025-09-28 13:19:30 +05:00
self . stdOut ( " MySQL root password set successfully " , 1 )
return True
2025-09-24 17:29:33 +02:00
except Exception as e :
self . stdOut ( f " Error changing MySQL root password: { str ( e ) } " , 0 )
2025-09-28 13:19:30 +05:00
return False
2025-09-24 17:29:33 +02:00
2025-09-29 12:18:03 +05:00
def execute_mysql_command ( self , sql_command , description = " MySQL command " ) :
""" Execute MySQL command with proper authentication fallback """
try :
# Try password-based authentication first if password file exists
try :
passFile = " /etc/cyberpanel/mysqlPassword "
if os . path . exists ( passFile ) :
with open ( passFile , ' r ' ) as f :
password = f . read ( ) . split ( ' \n ' , 1 ) [ 0 ]
# Try mariadb first, then mysql
for cmd_base in [ ' mariadb ' , ' mysql ' ] :
if self . command_exists ( cmd_base ) :
command = f ' { cmd_base } -u root -p { password } -e " { sql_command } " '
result = subprocess . run ( command , shell = True , capture_output = True , text = True , timeout = 30 )
if result . returncode == 0 :
self . stdOut ( f " ✓ { description } executed successfully with password auth " , 1 )
return True
except :
pass
# Fallback to socket authentication
for cmd_base in [ ' sudo mariadb ' , ' sudo mysql ' ] :
try :
if self . command_exists ( cmd_base . split ( ) [ - 1 ] ) :
command = f ' { cmd_base } -e " { sql_command } " '
result = subprocess . run ( command , shell = True , capture_output = True , text = True , timeout = 30 )
if result . returncode == 0 :
self . stdOut ( f " ✓ { description } executed successfully with socket auth " , 1 )
return True
except :
continue
self . stdOut ( f " ✗ Failed to execute { description } : { sql_command } " , 0 )
return False
except Exception as e :
self . stdOut ( f " Error executing MySQL command: { str ( e ) } " , 0 )
return False
2025-09-25 00:56:00 +02:00
def ensure_mysql_password_file ( self ) :
""" Ensure MySQL password file exists and is properly configured """
try :
os . makedirs ( ' /etc/cyberpanel ' , exist_ok = True )
# Check if password file already exists
passFile = ' /etc/cyberpanel/mysqlPassword '
if os . path . exists ( passFile ) :
# Verify the file has content
with open ( passFile , ' r ' ) as f :
content = f . read ( ) . strip ( )
if content :
self . stdOut ( " MySQL password file already exists and has content " , 1 )
return
# Create or update the password file
if hasattr ( self , ' mysql_Root_password ' ) and self . mysql_Root_password :
with open ( passFile , ' w ' ) as f :
f . write ( self . mysql_Root_password )
os . chmod ( passFile , 0o600 )
self . stdOut ( " MySQL password saved to /etc/cyberpanel/mysqlPassword " , 1 )
logging . InstallLog . writeToFile ( " MySQL password file created successfully " )
else :
raise Exception ( " No MySQL root password available to save " )
except Exception as e :
error_msg = f " Critical: Could not save MySQL password to file: { str ( e ) } "
self . stdOut ( error_msg , 0 )
logging . InstallLog . writeToFile ( error_msg )
raise Exception ( error_msg )
2025-09-24 17:29:33 +02:00
def command_exists ( self , command ) :
""" Check if a command exists in PATH """
try :
result = subprocess . run ( [ ' which ' , command ] , capture_output = True , text = True )
return result . returncode == 0
except :
return False
def fixMariaDB ( self ) :
""" Configure MariaDB for CyberPanel """
try :
self . stdOut ( " Configuring MariaDB for CyberPanel... " , 1 )
# Connect to MySQL and configure
import MySQLdb as mariadb
conn = mariadb . connect ( user = ' root ' , passwd = self . mysql_Root_password )
cursor = conn . cursor ( )
cursor . execute ( ' set global innodb_file_per_table = on; ' )
try :
cursor . execute ( ' set global innodb_file_format = Barracuda; ' )
cursor . execute ( ' set global innodb_large_prefix = on; ' )
except :
pass
cursor . close ( )
conn . close ( )
# Update MariaDB configuration
try :
fileName = ' /etc/mysql/mariadb.conf.d/50-server.cnf '
if os . path . exists ( fileName ) :
with open ( fileName , ' r ' ) as f :
data = f . readlines ( )
with open ( fileName , ' w ' ) as f :
for line in data :
f . write ( line . replace ( ' utf8mb4 ' , ' utf8 ' ) )
except :
pass
# Restart MariaDB
self . manage_service ( ' mariadb ' , ' restart ' )
self . stdOut ( " MariaDB configured successfully " , 1 )
return True
except Exception as e :
self . stdOut ( f " Error configuring MariaDB: { str ( e ) } " , 0 )
return False
def installPowerDNS ( self ) :
""" Install PowerDNS """
try :
self . stdOut ( " Installing PowerDNS... " , 1 )
if self . distro == ubuntu :
# Stop and disable systemd-resolved
self . manage_service ( ' systemd-resolved ' , ' stop ' )
self . manage_service ( ' systemd-resolved.service ' , ' disable ' )
# Create temporary resolv.conf
try :
os . rename ( ' /etc/resolv.conf ' , ' /etc/resolv.conf.bak ' )
except :
pass
with open ( ' /etc/resolv.conf ' , ' w ' ) as f :
f . write ( ' nameserver 8.8.8.8 \n ' )
f . write ( ' nameserver 8.8.4.4 \n ' )
# Install PowerDNS
command = " DEBIAN_FRONTEND=noninteractive apt-get update "
self . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR , True )
command = " DEBIAN_FRONTEND=noninteractive apt-get -y install pdns-server pdns-backend-mysql "
self . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR , True )
command = ' systemctl stop pdns || true '
self . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR , True )
else :
# RHEL-based PowerDNS installation
self . install_package ( ' pdns pdns-backend-mysql ' )
self . stdOut ( " PowerDNS installed successfully " , 1 )
return True
except Exception as e :
self . stdOut ( f " Error installing PowerDNS: { str ( e ) } " , 0 )
return False
def installPureFTPD ( self ) :
""" Install Pure-FTPd """
try :
self . stdOut ( " Installing Pure-FTPd... " , 1 )
if self . distro == ubuntu :
self . install_package ( ' pure-ftpd-mysql ' )
else :
self . install_package ( ' pure-ftpd ' )
# Enable service
service_name = self . pureFTPDServiceName ( self . distro )
command = f " systemctl enable { service_name } "
self . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
# Create FTP groups and users
command = ' groupadd -g 2001 ftpgroup '
self . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
command = ' useradd -u 2001 -s /bin/false -d /bin/null -c " pureftpd user " -g ftpgroup ftpuser '
self . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
self . stdOut ( " Pure-FTPd installed successfully " , 1 )
return True
except Exception as e :
self . stdOut ( f " Error installing Pure-FTPd: { str ( e ) } " , 0 )
return False
def fix_ols_configs ( self ) :
""" Fix OpenLiteSpeed configurations """
try :
self . stdOut ( " Fixing OpenLiteSpeed configurations... " , 1 )
2025-09-25 00:56:00 +02:00
# Check if OpenLiteSpeed configuration file exists
config_file = self . server_root_path + " conf/httpd_config.conf "
if not os . path . exists ( config_file ) :
self . stdOut ( " OpenLiteSpeed configuration file not found, creating default configuration... " , 1 )
# Create the configuration directory if it doesn't exist
os . makedirs ( os . path . dirname ( config_file ) , exist_ok = True )
# Create a basic configuration file
with open ( config_file , ' w ' ) as f :
f . write ( " # OpenLiteSpeed Configuration \n " )
f . write ( " serverName localhost \n " )
f . write ( " listener *:8088 { \n " )
f . write ( " address *:8088 \n " )
f . write ( " secure 0 \n " )
f . write ( " map *:8088 * \n " )
f . write ( " } \n " )
f . write ( " listener *:80 { \n " )
f . write ( " address *:80 \n " )
f . write ( " secure 0 \n " )
f . write ( " map *:80 * \n " )
f . write ( " } \n " )
self . stdOut ( " Default OpenLiteSpeed configuration created " , 1 )
2025-09-24 17:29:33 +02:00
# Remove example virtual host
2025-09-25 00:56:00 +02:00
data = open ( config_file , ' r ' ) . readlines ( )
writeDataToFile = open ( config_file , ' w ' )
2025-09-24 17:29:33 +02:00
for items in data :
if items . find ( " map " ) > - 1 and items . find ( " Example " ) > - 1 :
continue
else :
writeDataToFile . writelines ( items )
writeDataToFile . close ( )
self . stdOut ( " OpenLiteSpeed configurations fixed " , 1 )
return True
except Exception as e :
self . stdOut ( f " Error fixing OpenLiteSpeed configs: { str ( e ) } " , 0 )
return False
def changePortTo80 ( self ) :
""" Change OpenLiteSpeed port to 80 """
try :
self . stdOut ( " Changing OpenLiteSpeed port to 80... " , 1 )
file_path = self . server_root_path + " conf/httpd_config.conf "
2025-09-25 00:56:00 +02:00
if os . path . exists ( file_path ) :
2025-09-25 02:49:14 +02:00
if self . modify_file_content ( file_path , { " *:8088 " : " *:80 " } ) :
self . stdOut ( " OpenLiteSpeed port changed to 80 " , 1 )
self . reStartLiteSpeed ( )
return True
else :
2025-09-25 00:56:00 +02:00
return False
2025-09-24 17:29:33 +02:00
else :
2025-09-25 00:56:00 +02:00
self . stdOut ( " OpenLiteSpeed configuration file not found, skipping port change " , 1 )
2025-09-24 17:29:33 +02:00
return False
except Exception as e :
self . stdOut ( f " Error changing port to 80: { str ( e ) } " , 0 )
return False
def modify_file_content ( self , file_path , replacements ) :
""" Generic file content modification """
try :
with open ( file_path , ' r ' ) as f :
data = f . readlines ( )
with open ( file_path , ' w ' ) as f :
for line in data :
modified_line = line
for old , new in replacements . items ( ) :
if old in line :
modified_line = line . replace ( old , new )
break
f . write ( modified_line )
return True
except Exception as e :
self . stdOut ( f " Error modifying file { file_path } : { str ( e ) } " , 0 )
return False
def reStartLiteSpeed ( self ) :
""" Restart LiteSpeed """
try :
2025-09-25 02:12:33 +02:00
# Try multiple possible paths for lswsctrl
possible_paths = [
f " { self . server_root_path } bin/lswsctrl " ,
" /usr/local/lsws/bin/lswsctrl " ,
" /usr/local/lsws/bin/lswsctrl " ,
" /opt/lsws/bin/lswsctrl "
]
command = None
for path in possible_paths :
if os . path . exists ( path ) :
command = f " { path } restart "
break
if not command :
self . stdOut ( " Warning: lswsctrl not found, trying systemctl instead... " , 1 )
command = " systemctl restart lsws "
2025-09-24 17:29:33 +02:00
self . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
return True
except Exception as e :
self . stdOut ( f " Error restarting LiteSpeed: { str ( e ) } " , 0 )
return False
2025-09-18 12:30:22 +05:00
def get_service_name ( self , service ) :
""" Get the correct service name for the current distribution """
service_map = {
2025-09-23 23:33:05 +02:00
' pdns ' : ' pdns ' ,
' powerdns ' : ' pdns ' ,
' pure-ftpd ' : ' pure-ftpd ' ,
' pureftpd ' : ' pure-ftpd '
2025-09-18 12:30:22 +05:00
}
2025-09-23 23:33:05 +02:00
# 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 '
2025-09-18 12:30:22 +05:00
return service_map . get ( service , service )
2025-08-01 14:56:30 +05:00
def manage_service ( self , service_name , action = " start " ) :
2025-09-23 23:16:36 +02:00
""" 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
2025-08-01 14:56:30 +05:00
command = f ' systemctl { action } { service_name } '
return preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
def remove_package ( self , package_name , silent = False ) :
""" Unified package removal across distributions """
command , shell = install_utils . get_package_remove_command ( self . distro , package_name )
if not silent :
return preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR , shell )
else :
return preFlightsChecks . call ( command , self . distro , command , command , 0 , 0 , os . EX_OSERR , shell )
def __init__ ( self , rootPath , ip , path , cwd , cyberPanelPath , distro , remotemysql = None , mysqlhost = None , mysqldb = None ,
mysqluser = None , mysqlpassword = None , mysqlport = None ) :
self . ipAddr = ip
self . path = path
self . cwd = cwd
self . server_root_path = rootPath
self . cyberPanelPath = cyberPanelPath
self . distro = distro
self . remotemysql = remotemysql
self . mysqlhost = mysqlhost
self . mysqluser = mysqluser
self . mysqlpassword = mysqlpassword
self . mysqlport = mysqlport
self . mysqldb = mysqldb
2025-09-24 17:29:33 +02:00
self . cyberpanel_db_password = None # Will be set during password generation
self . mysql_Root_password = install_utils . generate_pass ( ) # Generate MySQL root password
2025-08-01 14:56:30 +05:00
def installQuota ( self , ) :
try :
if self . is_centos_family ( ) :
self . install_package ( " quota " , silent = True )
if self . edit_fstab ( ' / ' , ' / ' ) == 0 :
preFlightsChecks . stdOut ( " Quotas will not be abled as we failed to modify fstab file. " )
return 0
command = ' mount -o remount / '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = ' mount -o remount / '
try :
mResult = subprocess . run ( command , capture_output = True , universal_newlines = True , shell = True )
except :
mResult = subprocess . run ( command , stdout = subprocess . PIPE , stderr = subprocess . PIPE , universal_newlines = True , shell = True )
if mResult . returncode != 0 :
fstab_path = ' /etc/fstab '
backup_path = fstab_path + ' .bak '
if os . path . exists ( fstab_path ) :
os . remove ( fstab_path )
shutil . copy ( backup_path , fstab_path )
preFlightsChecks . stdOut ( " Re-mount failed, restoring original FSTab and existing quota setup. " )
return 0
##
if self . distro == ubuntu :
self . stdOut ( " Install Quota on Ubuntu " )
# Skip apt update as it was already done in cyberpanel.sh
self . install_package ( " quota " , silent = True )
command = " find /lib/modules/ -type f -name ' *quota_v*.ko* ' "
if subprocess . check_output ( command , shell = True ) . decode ( " utf-8 " ) . find ( " quota/ " ) == - 1 :
self . install_package ( " linux-image-extra-virtual " , silent = True )
if self . edit_fstab ( ' / ' , ' / ' ) == 0 :
preFlightsChecks . stdOut ( " Quotas will not be abled as we are are failed to modify fstab file. " )
return 0
command = ' mount -o remount / '
try :
mResult = subprocess . run ( command , capture_output = True , universal_newlines = True , shell = True )
except :
mResult = subprocess . run ( command , stdout = subprocess . PIPE , stderr = subprocess . PIPE ,
universal_newlines = True , shell = True )
if mResult . returncode != 0 :
fstab_path = ' /etc/fstab '
backup_path = fstab_path + ' .bak '
if os . path . exists ( fstab_path ) :
os . remove ( fstab_path )
shutil . copy ( backup_path , fstab_path )
preFlightsChecks . stdOut ( " Re-mount failed, restoring original FSTab and existing quota setup. " )
return 0
command = ' quotacheck -ugm / '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
####
command = " find /lib/modules/ -type f -name ' *quota_v*.ko* ' "
try :
iResult = subprocess . run ( command , capture_output = True , universal_newlines = True , shell = True )
except :
iResult = subprocess . run ( command , stdout = subprocess . PIPE , stderr = subprocess . PIPE ,
universal_newlines = True , shell = True )
print ( repr ( iResult . stdout ) )
# Only if the first command works, run the rest
if iResult . returncode == 0 :
command = " echo ' {} ' | sed -n ' s|/lib/modules/ \\ ([^/]* \\ )/.*| \\ 1|p ' | sort -u " . format ( iResult . stdout )
try :
result = subprocess . run ( command , capture_output = True , universal_newlines = True , shell = True )
except :
result = subprocess . run ( command , stdout = subprocess . PIPE , stderr = subprocess . PIPE , universal_newlines = True , shell = True )
fResult = result . stdout . rstrip ( ' \n ' )
print ( repr ( result . stdout . rstrip ( ' \n ' ) ) )
command = ' uname -r '
try :
ffResult = subprocess . run ( command , capture_output = True , universal_newlines = True , shell = True )
except :
ffResult = subprocess . run ( command , stdout = subprocess . PIPE , stderr = subprocess . PIPE , universal_newlines = True , shell = True )
ffResult = ffResult . stdout . rstrip ( ' \n ' )
command = f " DEBIAN_FRONTEND=noninteractive apt-get install linux-modules-extra- { ffResult } "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR , True )
###
command = f ' modprobe quota_v1 -S { ffResult } '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = f ' modprobe quota_v2 -S { ffResult } '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = f ' quotacheck -ugm / '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = f ' quotaon -v / '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
except BaseException as msg :
logging . InstallLog . writeToFile ( " [ERROR] installQuota. " + str ( msg ) )
def edit_fstab ( self , mount_point , options_to_add ) :
try :
retValue = 1
# Backup the original fstab file
fstab_path = ' /etc/fstab '
backup_path = fstab_path + ' .bak '
rData = open ( fstab_path , ' r ' ) . read ( )
if rData . find ( ' xfs ' ) > - 1 :
options_to_add = ' uquota '
else :
options_to_add = ' usrquota,grpquota '
if not os . path . exists ( backup_path ) :
shutil . copy ( fstab_path , backup_path )
# Read the fstab file
with open ( fstab_path , ' r ' ) as file :
lines = file . readlines ( )
# Modify the appropriate line
WriteToFile = open ( fstab_path , ' w ' )
for i , line in enumerate ( lines ) :
if line . find ( ' \t ' ) > - 1 :
parts = line . split ( ' \t ' )
else :
parts = line . split ( ' ' )
print ( parts )
try :
if parts [ 1 ] == ' / ' and parts [ 3 ] . find ( options_to_add ) == - 1 and len ( parts [ 3 ] ) > 4 :
parts [ 3 ] = f ' { parts [ 3 ] } , { options_to_add } '
tempParts = [ item for item in parts if item . strip ( ) ]
finalString = ' \t ' . join ( tempParts )
print ( finalString )
WriteToFile . write ( finalString )
elif parts [ 1 ] == ' / ' :
for ii , p in enumerate ( parts ) :
if p . find ( ' defaults ' ) > - 1 or p . find ( ' discard ' ) > - 1 or p . find ( ' errors= ' ) > - 1 :
parts [ ii ] = f ' { parts [ ii ] } , { options_to_add } '
tempParts = [ item for item in parts if item . strip ( ) ]
finalString = ' \t ' . join ( tempParts )
print ( finalString )
WriteToFile . write ( finalString )
else :
WriteToFile . write ( line )
except :
WriteToFile . write ( line )
WriteToFile . close ( )
return retValue
except :
return 0
@staticmethod
def stdOut ( message , log = 0 , do_exit = 0 , code = os . EX_OK ) :
install_utils . stdOut ( message , log , do_exit , code )
def mountTemp ( self ) :
try :
try :
result = subprocess . run ( ' systemd-detect-virt ' , capture_output = True , universal_newlines = True , shell = True )
except :
result = subprocess . run ( ' systemd-detect-virt ' , stdout = subprocess . PIPE , stderr = subprocess . PIPE , universal_newlines = True , shell = True )
if result . stdout . find ( ' openvz ' ) > - 1 :
if self . distro == ubuntu :
self . install_package ( " inetutils-inetd " )
# ## On OpenVZ there is an issue using .tempdisk for /tmp as it breaks network on container after reboot.
#
# if subprocess.check_output('systemd-detect-virt').decode("utf-8").find("openvz") > -1:
#
# varTmp = "/var/tmp /tmp none bind 0 0\n"
#
# fstab = "/etc/fstab"
# writeToFile = open(fstab, "a")
# writeToFile.writelines(varTmp)
# writeToFile.close()
#
# else:
#
# command = "dd if=/dev/zero of=/usr/.tempdisk bs=100M count=15"
# preFlightsChecks.call(command, self.distro, command,
# command,
# 1, 0, os.EX_OSERR)
#
# command = "mkfs.ext4 -F /usr/.tempdisk"
# preFlightsChecks.call(command, self.distro, command,
# command,
# 1, 0, os.EX_OSERR)
#
# command = "mkdir -p /usr/.tmpbak/"
# preFlightsChecks.call(command, self.distro, command,
# command,
# 1, 0, os.EX_OSERR)
#
# command = "cp -pr /tmp/* /usr/.tmpbak/"
# subprocess.call(command, shell=True)
#
# command = "mount -o loop,rw,nodev,nosuid,noexec,nofail /usr/.tempdisk /tmp"
# preFlightsChecks.call(command, self.distro, command,
# command,
# 1, 0, os.EX_OSERR)
#
# command = "chmod 1777 /tmp"
# preFlightsChecks.call(command, self.distro, command,
# command,
# 1, 0, os.EX_OSERR)
#
# command = "cp -pr /usr/.tmpbak/* /tmp/"
# subprocess.call(command, shell=True)
#
# command = "rm -rf /usr/.tmpbak"
# preFlightsChecks.call(command, self.distro, command,
# command,
# 1, 0, os.EX_OSERR)
#
# command = "mount --bind /tmp /var/tmp"
# preFlightsChecks.call(command, self.distro, command,
# command,
# 1, 0, os.EX_OSERR)
#
# tmp = "/usr/.tempdisk /tmp ext4 loop,rw,noexec,nosuid,nodev,nofail 0 0\n"
# varTmp = "/tmp /var/tmp none bind 0 0\n"
#
# fstab = "/etc/fstab"
# writeToFile = open(fstab, "a")
# writeToFile.writelines(tmp)
# writeToFile.writelines(varTmp)
# writeToFile.close()
pass
except BaseException as msg :
preFlightsChecks . stdOut ( ' [ERROR] ' + str ( msg ) )
return 0
@staticmethod
def pureFTPDServiceName ( distro ) :
if distro == ubuntu :
return ' pure-ftpd-mysql '
return ' pure-ftpd '
# Using shared function from install_utils
@staticmethod
def resFailed ( distro , res ) :
return install_utils . resFailed ( distro , res )
# Using shared function from install_utils
@staticmethod
def call ( command , distro , bracket , message , log = 0 , do_exit = 0 , code = os . EX_OK , shell = False ) :
return install_utils . call ( command , distro , bracket , message , log , do_exit , code , shell )
def checkIfSeLinuxDisabled ( self ) :
try :
command = " sestatus "
output = subprocess . check_output ( shlex . split ( command ) ) . decode ( " utf-8 " )
if output . find ( " disabled " ) > - 1 or output . find ( " permissive " ) > - 1 :
logging . InstallLog . writeToFile ( " SELinux Check OK. [checkIfSeLinuxDisabled] " )
preFlightsChecks . stdOut ( " SELinux Check OK. " )
return 1
else :
logging . InstallLog . writeToFile (
" SELinux is enabled, please disable SELinux and restart the installation! " )
preFlightsChecks . stdOut ( " Installation failed, consult: /var/log/installLogs.txt " )
os . _exit ( 0 )
except BaseException as msg :
logging . InstallLog . writeToFile ( ' [ERROR] ' + str ( msg ) + " [checkIfSeLinuxDisabled] " )
logging . InstallLog . writeToFile ( ' [ERROR] ' + " SELinux Check OK. [checkIfSeLinuxDisabled] " )
preFlightsChecks . stdOut ( ' [ERROR] ' + " SELinux Check OK. " )
return 1
def checkPythonVersion ( self ) :
if sys . version_info [ 0 ] == 3 :
return 1
else :
preFlightsChecks . stdOut ( " You are running Unsupported python version, please install python 3.x " )
os . _exit ( 0 )
def setup_account_cyberpanel ( self ) :
try :
if self . is_centos_family ( ) :
self . install_package ( " sudo " , silent = True )
##
if self . distro == ubuntu :
self . stdOut ( " Add Cyberpanel user " )
command = ' adduser --disabled-login --gecos " " cyberpanel '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
else :
command = " useradd -s /bin/false cyberpanel "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
###############################
### Docker User/group
2025-09-18 23:20:05 +05:00
if self . distro == ubuntu or self . distro == debian12 :
2025-08-01 14:56:30 +05:00
command = ' adduser --disabled-login --gecos " " docker '
else :
2025-09-18 23:20:05 +05:00
# For CentOS/RHEL, use useradd which is non-interactive
command = " useradd -r -s /bin/false docker "
2025-08-01 14:56:30 +05:00
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = ' groupadd docker '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = ' usermod -aG docker docker '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = ' usermod -aG docker cyberpanel '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
###
command = " mkdir -p /etc/letsencrypt/live/ "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
except BaseException as msg :
logging . InstallLog . writeToFile ( " [ERROR] setup_account_cyberpanel. " + str ( msg ) )
def installCyberPanelRepo ( self ) :
self . stdOut ( " Install Cyberpanel repo " )
if self . distro == ubuntu :
try :
2025-09-18 01:15:38 +05:00
# Use the new LiteSpeed repository setup method
2025-09-18 01:29:38 +05:00
command = " bash -c ' wget -O - https://repo.litespeed.sh | bash ' "
2025-08-01 14:56:30 +05:00
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
except :
logging . InstallLog . writeToFile ( " [ERROR] Exception during CyberPanel install " )
preFlightsChecks . stdOut ( " [ERROR] Exception during CyberPanel install " )
os . _exit ( os . EX_SOFTWARE )
2025-09-18 01:58:24 +05:00
elif self . distro == debian12 :
try :
# Use the official LiteSpeed repository setup method for Debian 12
command = " bash -c ' wget -O - https://repo.litespeed.sh | bash ' "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
except :
logging . InstallLog . writeToFile ( " [ERROR] Exception during CyberPanel install - Debian 12 repository setup " )
preFlightsChecks . stdOut ( " [ERROR] Exception during CyberPanel install - Debian 12 repository setup " )
os . _exit ( os . EX_SOFTWARE )
2025-08-01 14:56:30 +05:00
elif self . distro == centos :
command = ' rpm -ivh http://rpms.litespeedtech.com/centos/litespeed-repo-1.2-1.el7.noarch.rpm '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
elif self . distro == cent8 :
2025-09-25 00:56:00 +02:00
# Use compatible repository version for RHEL-based systems
# AlmaLinux 9 is compatible with el8 repositories
2025-09-25 01:34:57 +02:00
os_info = self . detect_os_info ( )
2025-09-25 00:56:00 +02:00
if os_info [ ' name ' ] in [ ' almalinux ' , ' rocky ' , ' rhel ' ] and os_info [ ' major_version ' ] in [ ' 8 ' , ' 9 ' ] :
command = ' rpm -Uvh http://rpms.litespeedtech.com/centos/litespeed-repo-1.1-1.el8.noarch.rpm '
else :
2025-09-25 02:49:14 +02:00
command = ' rpm -Uvh http://rpms.litespeedtech.com/centos/litespeed-repo-1.1-1.el8.noarch.rpm '
2025-08-01 14:56:30 +05:00
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
def fix_selinux_issue ( self ) :
try :
cmd = [ ]
cmd . append ( " setsebool " )
cmd . append ( " -P " )
cmd . append ( " httpd_can_network_connect " )
cmd . append ( " 1 " )
res = subprocess . call ( cmd )
if preFlightsChecks . resFailed ( self . distro , res ) :
logging . InstallLog . writeToFile ( " fix_selinux_issue problem " )
else :
pass
except :
logging . InstallLog . writeToFile ( " [ERROR] fix_selinux_issue problem " )
def install_psmisc ( self ) :
self . stdOut ( " Install psmisc " )
self . install_package ( " psmisc " )
2025-09-24 20:23:49 +02:00
2025-09-27 14:13:33 +05:00
def update_settings_file ( self , mysqlPassword , cyberpanel_password , mysql ) :
2025-09-13 19:07:03 +02:00
"""
2025-09-27 14:13:33 +05:00
Update settings . py file with correct passwords
mysqlPassword : Root MySQL password
cyberpanel_password : CyberPanel database user password
2025-09-13 19:07:03 +02:00
"""
2025-09-25 22:29:53 +02:00
logging . InstallLog . writeToFile ( " Updating settings.py! " )
2025-09-27 14:13:33 +05:00
# Validate passwords are not empty
if not mysqlPassword or not cyberpanel_password :
logging . InstallLog . writeToFile ( " ERROR: Empty passwords provided to update_settings_file " )
raise Exception ( " Cannot update settings with empty passwords " )
2025-09-13 19:07:03 +02:00
path = self . cyberPanelPath + " /CyberCP/settings.py "
2025-09-27 14:13:33 +05:00
2025-09-13 19:07:03 +02:00
data = open ( path , " r " ) . readlines ( )
2025-09-27 14:13:33 +05:00
2025-09-13 19:07:03 +02:00
writeDataToFile = open ( path , " w " )
2025-09-27 14:13:33 +05:00
default_db_found = False
rootdb_found = False
in_default_db = False
in_rootdb = False
2025-09-13 19:07:03 +02:00
for items in data :
2025-09-27 14:13:33 +05:00
# Handle SECRET_KEY generation
2025-09-13 19:07:03 +02:00
if items . find ( ' SECRET_KEY ' ) > - 1 :
2025-09-25 22:29:53 +02:00
SK = " SECRET_KEY = ' %s ' \n " % ( install_utils . generate_pass ( 50 ) )
2025-09-13 19:07:03 +02:00
writeDataToFile . writelines ( SK )
continue
2025-09-27 14:13:33 +05:00
2025-09-28 00:05:35 +05:00
# Track which database section we're in - more robust detection
stripped_line = items . strip ( )
# Detect database section start
if " ' default ' " in stripped_line and " : " in stripped_line :
2025-09-27 14:13:33 +05:00
in_default_db = True
in_rootdb = False
2025-09-28 00:05:35 +05:00
logging . InstallLog . writeToFile ( " Detected ' default ' database section " )
elif " ' rootdb ' " in stripped_line and " : " in stripped_line :
2025-09-27 14:13:33 +05:00
in_default_db = False
in_rootdb = True
2025-09-28 00:05:35 +05:00
logging . InstallLog . writeToFile ( " Detected ' rootdb ' database section " )
elif stripped_line in [ " }, " , " } " ] or ( stripped_line . startswith ( " } " ) and len ( stripped_line ) < = 2 ) :
# End of database section
if in_default_db or in_rootdb :
logging . InstallLog . writeToFile ( f " End of database section (default: { in_default_db } , rootdb: { in_rootdb } ) " )
2025-09-27 14:13:33 +05:00
in_default_db = False
in_rootdb = False
# Handle password replacement based on current database section
2025-09-28 00:05:35 +05:00
if " ' PASSWORD ' : " in items :
2025-09-27 14:13:33 +05:00
if in_default_db and not default_db_found :
# This is the cyberpanel database password
2025-09-28 00:05:35 +05:00
new_line = " ' PASSWORD ' : ' " + cyberpanel_password + " ' , \n "
writeDataToFile . writelines ( new_line )
2025-09-27 14:13:33 +05:00
default_db_found = True
2025-09-28 00:05:35 +05:00
logging . InstallLog . writeToFile ( f " ✓ Set cyberpanel database password (length: { len ( cyberpanel_password ) } ) " )
2025-09-27 14:13:33 +05:00
elif in_rootdb and not rootdb_found :
# This is the root database password
2025-09-28 00:05:35 +05:00
new_line = " ' PASSWORD ' : ' " + mysqlPassword + " ' , \n "
writeDataToFile . writelines ( new_line )
2025-09-27 14:13:33 +05:00
rootdb_found = True
2025-09-28 00:05:35 +05:00
logging . InstallLog . writeToFile ( f " ✓ Set root database password (length: { len ( mysqlPassword ) } ) " )
2025-09-13 19:07:03 +02:00
else :
2025-09-27 14:13:33 +05:00
# Fallback - write original line
2025-09-28 00:05:35 +05:00
logging . InstallLog . writeToFile ( f " ⚠ Password line found but not in expected section (default: { in_default_db } , rootdb: { in_rootdb } ) " )
2025-09-25 22:29:53 +02:00
writeDataToFile . writelines ( items )
2025-09-27 14:13:33 +05:00
elif mysql == ' Two ' :
# Handle special MySQL Two configuration
writeDataToFile . writelines ( items )
2025-09-13 19:07:03 +02:00
else :
2025-09-27 14:13:33 +05:00
# Handle host/port replacements for standard MySQL
if items . find ( ' 127.0.0.1 ' ) > - 1 :
2025-09-25 22:29:53 +02:00
writeDataToFile . writelines ( " ' HOST ' : ' localhost ' , \n " )
elif items . find ( " ' PORT ' : ' 3307 ' " ) > - 1 :
writeDataToFile . writelines ( " ' PORT ' : ' ' , \n " )
else :
writeDataToFile . writelines ( items )
2025-09-27 14:13:33 +05:00
2025-09-25 22:29:53 +02:00
if self . distro == install_utils . ubuntu :
2025-09-13 19:07:03 +02:00
os . fchmod ( writeDataToFile . fileno ( ) , stat . S_IRUSR | stat . S_IWUSR )
2025-09-27 14:13:33 +05:00
2025-09-13 19:07:03 +02:00
writeDataToFile . close ( )
2025-09-27 14:13:33 +05:00
# Verify both passwords were set
if not default_db_found or not rootdb_found :
error_msg = f " ERROR: Failed to update all database passwords. Default: { default_db_found } , Root: { rootdb_found } "
logging . InstallLog . writeToFile ( error_msg )
raise Exception ( error_msg )
2025-09-25 22:29:53 +02:00
if self . remotemysql == ' ON ' :
command = " sed -i ' s|localhost| %s |g ' %s " % ( self . mysqlhost , path )
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
2025-09-27 14:13:33 +05:00
2025-09-25 22:29:53 +02:00
command = " sed -i ' s|root| %s |g ' %s " % ( self . mysqluser , path )
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
2025-09-27 14:13:33 +05:00
2025-09-25 22:29:53 +02:00
command = " sed -i \" s| ' PORT ' : ' ' | ' PORT ' : ' %s ' |g \" %s " % ( self . mysqlport , path )
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
2025-09-27 14:13:33 +05:00
logging . InstallLog . writeToFile ( " settings.py updated successfully - both database passwords configured! " )
2025-09-25 22:29:53 +02:00
2025-09-13 19:07:03 +02:00
2025-08-01 14:56:30 +05:00
def download_install_CyberPanel ( self , mysqlPassword , mysql ) :
##
os . chdir ( self . path )
os . chdir ( ' /usr/local ' )
2025-09-21 00:21:07 +05:00
# Since cyberpanel.sh has already cloned the repository and we're running from it,
# we simply need to clone a fresh copy to /usr/local/CyberCP for the application
logging . InstallLog . writeToFile ( " Setting up CyberPanel application directory... " )
# Remove existing CyberCP directory if it exists
if os . path . exists ( ' /usr/local/CyberCP ' ) :
logging . InstallLog . writeToFile ( " Removing existing CyberCP directory... " )
shutil . rmtree ( ' /usr/local/CyberCP ' )
# Clone directly to /usr/local/CyberCP with explicit path
logging . InstallLog . writeToFile ( " Cloning repository to /usr/local/CyberCP... " )
2025-09-24 11:28:20 +02:00
# Ensure the parent directory exists
os . makedirs ( " /usr/local " , exist_ok = True )
2025-09-24 22:45:12 +02:00
# Determine the correct branch/tag/commit to clone
branch_name = os . environ . get ( ' CYBERPANEL_BRANCH ' , ' stable ' )
2025-09-24 11:28:20 +02:00
# Try multiple clone methods for better reliability
2025-09-24 22:45:12 +02:00
clone_commands = [ ]
# If a specific branch/tag/commit is specified, try to clone it
if branch_name and branch_name != ' stable ' :
if branch_name . startswith ( ' commit: ' ) :
# It's a commit hash (e.g., commit:b05d9cb5bb3c277b22a6070f04844e8a7951585b)
commit_hash = branch_name [ 7 : ] # Remove 'commit:' prefix
clone_commands . append ( f " git clone https://github.com/usmannasir/cyberpanel /usr/local/CyberCP " )
clone_commands . append ( f " cd /usr/local/CyberCP && git checkout { commit_hash } " )
elif branch_name . startswith ( ' v ' ) :
# It's a tag (e.g., v2.4.4)
clone_commands . append ( f " git clone --depth 1 --branch { branch_name } https://github.com/usmannasir/cyberpanel /usr/local/CyberCP " )
elif branch_name . endswith ( ' -dev ' ) :
# It's a development branch (e.g., 2.5.5-dev)
clone_commands . append ( f " git clone --depth 1 --branch { branch_name } https://github.com/usmannasir/cyberpanel /usr/local/CyberCP " )
elif len ( branch_name ) > = 7 and all ( c in ' 0123456789abcdef ' for c in branch_name . lower ( ) ) :
# It's a commit hash (e.g., b05d9cb5bb3c277b22a6070f04844e8a7951585b)
clone_commands . append ( f " git clone https://github.com/usmannasir/cyberpanel /usr/local/CyberCP " )
clone_commands . append ( f " cd /usr/local/CyberCP && git checkout { branch_name } " )
else :
# It's a version number, try as both tag and branch
clone_commands . append ( f " git clone --depth 1 --branch v { branch_name } https://github.com/usmannasir/cyberpanel /usr/local/CyberCP " )
clone_commands . append ( f " git clone --depth 1 --branch { branch_name } https://github.com/usmannasir/cyberpanel /usr/local/CyberCP " )
# Fallback to stable branch
clone_commands . extend ( [
2025-09-24 11:28:20 +02:00
" git clone https://github.com/usmannasir/cyberpanel /usr/local/CyberCP " ,
" git clone --depth 1 https://github.com/usmannasir/cyberpanel /usr/local/CyberCP " ,
" git clone --single-branch --branch stable https://github.com/usmannasir/cyberpanel /usr/local/CyberCP "
2025-09-24 22:45:12 +02:00
] )
2025-09-24 11:28:20 +02:00
clone_success = False
for cmd in clone_commands :
try :
result = preFlightsChecks . call ( cmd , self . distro , cmd , cmd , 1 , 1 , os . EX_OSERR )
if result == 1 and os . path . exists ( ' /usr/local/CyberCP ' ) :
clone_success = True
break
except :
continue
if not clone_success or not os . path . exists ( ' /usr/local/CyberCP ' ) :
logging . InstallLog . writeToFile ( " [ERROR] All Git clone attempts failed! " )
preFlightsChecks . stdOut ( " [ERROR] All Git clone attempts failed! " )
# Try manual download as fallback
logging . InstallLog . writeToFile ( " Attempting manual download as fallback... " )
2025-09-24 22:45:12 +02:00
# Determine the correct download URL based on branch/tag/commit
if branch_name and branch_name != ' stable ' :
if branch_name . startswith ( ' commit: ' ) :
# It's a commit hash - use the commit hash directly
commit_hash = branch_name [ 7 : ] # Remove 'commit:' prefix
download_url = f " https://github.com/usmannasir/cyberpanel/archive/ { commit_hash } .zip "
extract_dir = f " cyberpanel- { commit_hash } "
elif len ( branch_name ) > = 7 and all ( c in ' 0123456789abcdef ' for c in branch_name . lower ( ) ) :
# It's a commit hash (e.g., b05d9cb5bb3c277b22a6070f04844e8a7951585b)
download_url = f " https://github.com/usmannasir/cyberpanel/archive/ { branch_name } .zip "
extract_dir = f " cyberpanel- { branch_name } "
elif branch_name . startswith ( ' v ' ) :
# It's a tag
download_url = f " https://github.com/usmannasir/cyberpanel/archive/refs/tags/ { branch_name } .zip "
extract_dir = f " cyberpanel- { branch_name [ 1 : ] } " # Remove 'v' prefix
elif branch_name . endswith ( ' -dev ' ) :
# It's a development branch
download_url = f " https://github.com/usmannasir/cyberpanel/archive/refs/heads/ { branch_name } .zip "
extract_dir = f " cyberpanel- { branch_name } "
else :
# It's a version number, try as tag first
download_url = f " https://github.com/usmannasir/cyberpanel/archive/refs/tags/v { branch_name } .zip "
extract_dir = f " cyberpanel- { branch_name } "
else :
# Default to stable
download_url = " https://github.com/usmannasir/cyberpanel/archive/refs/heads/stable.zip "
extract_dir = " cyberpanel-stable "
command = f " wget -O /tmp/cyberpanel.zip { download_url } "
2025-09-24 11:28:20 +02:00
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
command = " unzip /tmp/cyberpanel.zip -d /usr/local/ "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
2025-09-24 22:45:12 +02:00
command = f " mv /usr/local/ { extract_dir } /usr/local/CyberCP "
2025-09-24 11:28:20 +02:00
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
command = " rm -f /tmp/cyberpanel.zip "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
if not os . path . exists ( ' /usr/local/CyberCP ' ) :
logging . InstallLog . writeToFile ( " [ERROR] Manual download also failed! " )
preFlightsChecks . stdOut ( " [ERROR] Manual download also failed! " )
sys . exit ( 1 )
2025-09-20 20:21:18 +05:00
2025-09-21 00:21:07 +05:00
logging . InstallLog . writeToFile ( " Successfully cloned repository to /usr/local/CyberCP " )
2025-08-01 14:56:30 +05:00
##
### update password:
if self . remotemysql == ' OFF ' :
passFile = " /etc/cyberpanel/mysqlPassword "
2025-09-25 00:56:00 +02:00
# Check if MySQL password file exists, create it if missing
if not os . path . exists ( passFile ) :
logging . InstallLog . writeToFile ( " MySQL password file not found, creating it... " )
try :
# Ensure directory exists
os . makedirs ( ' /etc/cyberpanel ' , exist_ok = True )
# Use the stored MySQL root password
if hasattr ( self , ' mysql_Root_password ' ) and self . mysql_Root_password :
password = self . mysql_Root_password
# Create the password file
with open ( passFile , ' w ' ) as f :
f . write ( password )
os . chmod ( passFile , 0o600 )
logging . InstallLog . writeToFile ( " MySQL password file created successfully " )
else :
logging . InstallLog . writeToFile ( " ERROR: No MySQL root password available " )
raise Exception ( " MySQL root password not available " )
except Exception as e :
logging . InstallLog . writeToFile ( f " ERROR: Failed to create MySQL password file: { str ( e ) } " )
raise Exception ( f " Failed to create MySQL password file: { str ( e ) } " )
else :
# Read existing password file
try :
with open ( passFile , ' r ' ) as f :
2025-09-25 02:49:14 +02:00
data = f . read ( )
2025-09-25 00:56:00 +02:00
password = data . split ( ' \n ' , 1 ) [ 0 ] . strip ( )
if not password :
raise Exception ( " Empty password in file " )
except Exception as e :
logging . InstallLog . writeToFile ( f " ERROR: Failed to read MySQL password file: { str ( e ) } " )
raise Exception ( f " Failed to read MySQL password file: { str ( e ) } " )
2025-08-01 14:56:30 +05:00
else :
password = self . mysqlpassword
### Put correct mysql passwords in settings file!
# This allows root/sudo users to be able to work with MySQL/MariaDB without hunting down the password like
# all the other control panels allow
# reference: https://oracle-base.com/articles/mysql/mysql-password-less-logins-using-option-files
mysql_my_root_cnf = ' /root/.my.cnf '
mysql_root_cnf_content = """
[ client ]
user = root
password = " %s "
""" % password
with open ( mysql_my_root_cnf , ' w ' ) as f :
f . write ( mysql_root_cnf_content )
os . chmod ( mysql_my_root_cnf , 0o600 )
command = ' chown root:root %s ' % mysql_my_root_cnf
subprocess . call ( shlex . split ( command ) )
logging . InstallLog . writeToFile ( " Updating /root/.my.cnf! " )
2025-09-13 19:07:03 +02:00
logging . InstallLog . writeToFile ( " Generating secure environment configuration! " )
2025-08-01 14:56:30 +05:00
2025-09-29 12:42:27 +05:00
# Determine the correct MySQL root password to use
mysql_root_password = mysqlPassword if self . remotemysql == ' ON ' else self . mysql_Root_password
2025-09-21 00:21:07 +05:00
# For CentOS, we need to get the actual cyberpanel database password
# which is different from the root password
if self . distro == centos :
2025-09-24 17:29:33 +02:00
# On CentOS, generate a separate password for cyberpanel database
self . cyberpanel_db_password = install_utils . generate_pass ( )
2025-09-21 00:21:07 +05:00
else :
# On Ubuntu/Debian, the cyberpanel password is the same as root password
2025-09-29 12:42:27 +05:00
self . cyberpanel_db_password = mysql_root_password
2025-09-21 00:21:07 +05:00
2025-09-25 22:29:53 +02:00
# Update settings.py with correct passwords (no .env files needed)
2025-09-29 12:42:27 +05:00
self . update_settings_file ( mysql_root_password , self . cyberpanel_db_password , mysql )
2025-08-01 14:56:30 +05:00
2025-09-13 19:07:03 +02:00
logging . InstallLog . writeToFile ( " Environment configuration generated successfully! " )
2025-08-01 14:56:30 +05:00
if self . remotemysql == ' ON ' :
2025-09-20 20:21:18 +05:00
path = self . cyberPanelPath + " /CyberCP/settings.py "
2025-08-01 14:56:30 +05:00
command = " sed -i ' s|localhost| %s |g ' %s " % ( self . mysqlhost , path )
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
# command = "sed -i 's|'mysql'|'%s'|g' %s" % (self.mysqldb, path)
# preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR)
command = " sed -i ' s|root| %s |g ' %s " % ( self . mysqluser , path )
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
command = " sed -i \" s| ' PORT ' : ' ' | ' PORT ' : ' %s ' |g \" %s " % ( self . mysqlport , path )
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
logging . InstallLog . writeToFile ( " settings.py updated! " )
# self.setupVirtualEnv(self.distro)
2025-09-21 00:37:02 +05:00
# Now run Django migrations since we're in /usr/local/CyberCP and database exists
os . chdir ( " /usr/local/CyberCP " )
logging . InstallLog . writeToFile ( " Running Django migrations... " )
preFlightsChecks . stdOut ( " Running Django migrations... " )
2025-09-30 23:46:10 +05:00
# Clean any existing migration files first (except __init__.py and excluding virtual environment)
2025-09-21 13:04:51 +05:00
logging . InstallLog . writeToFile ( " Cleaning existing migration files... " )
2025-09-21 01:07:38 +05:00
2025-10-01 00:45:40 +05:00
# List of apps that have migrations folders
apps_with_migrations = [
' loginSystem ' , ' packages ' , ' websiteFunctions ' , ' baseTemplate ' , ' userManagment ' ,
' dns ' , ' databases ' , ' ftp ' , ' filemanager ' , ' mailServer ' , ' emailPremium ' ,
' emailMarketing ' , ' cloudAPI ' , ' containerization ' , ' IncBackups ' , ' CLManager ' ,
' s3Backups ' , ' dockerManager ' , ' aiScanner ' , ' firewall ' , ' tuning ' , ' serverStatus ' ,
' serverLogs ' , ' backup ' , ' managePHP ' , ' manageSSL ' , ' api ' , ' manageServices ' ,
' pluginHolder ' , ' highAvailability ' , ' WebTerminal '
]
2025-09-21 13:04:51 +05:00
2025-10-01 00:45:40 +05:00
# Clean migration files for each app specifically
for app in apps_with_migrations :
migration_dir = f " /usr/local/CyberCP/ { app } /migrations "
if os . path . exists ( migration_dir ) :
# Remove all .py files except __init__.py
command = f " bash -c \" find { migration_dir } -name ' *.py ' ! -name ' __init__.py ' -delete 2>/dev/null || true \" "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
# Remove all .pyc files
command = f " bash -c \" find { migration_dir } -name ' *.pyc ' -delete 2>/dev/null || true \" "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
# Remove __pycache__ directory
command = f " bash -c \" rm -rf { migration_dir } /__pycache__ 2>/dev/null || true \" "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-09-21 13:04:51 +05:00
2025-10-01 00:45:40 +05:00
logging . InstallLog . writeToFile ( " Migration cleanup completed " )
2025-09-23 09:55:27 +02:00
2025-09-24 13:56:32 +02:00
# Ensure virtual environment is properly set up
logging . InstallLog . writeToFile ( " Ensuring virtual environment is properly set up... " )
if not self . ensureVirtualEnvironmentSetup ( ) :
logging . InstallLog . writeToFile ( " ERROR: Virtual environment setup failed! " , 0 )
preFlightsChecks . stdOut ( " ERROR: Virtual environment setup failed! " , 0 )
return False
# Find the correct Python virtual environment path
python_paths = [
" /usr/local/CyberPanel/bin/python " ,
" /usr/local/CyberCP/bin/python " ,
" /usr/local/CyberPanel-venv/bin/python "
]
python_path = None
for path in python_paths :
if os . path . exists ( path ) :
python_path = path
logging . InstallLog . writeToFile ( f " Found Python virtual environment at: { path } " )
break
if not python_path :
logging . InstallLog . writeToFile ( " ERROR: No Python virtual environment found! " , 0 )
preFlightsChecks . stdOut ( " ERROR: No Python virtual environment found! " , 0 )
return False
2025-10-01 00:20:05 +05:00
# Create migrations in dependency order - loginSystem first since other apps depend on it
logging . InstallLog . writeToFile ( " Creating migrations for loginSystem first... " )
command = f " { python_path } manage.py makemigrations loginSystem --noinput "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
# Now create migrations for all other apps
logging . InstallLog . writeToFile ( " Creating migrations for all other apps... " )
2025-09-24 13:56:32 +02:00
command = f " { python_path } manage.py makemigrations --noinput "
2025-09-21 00:37:02 +05:00
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
2025-09-21 13:04:51 +05:00
# Apply all migrations
logging . InstallLog . writeToFile ( " Applying all migrations... " )
2025-09-24 13:56:32 +02:00
command = f " { python_path } manage.py migrate --noinput "
2025-09-21 00:37:02 +05:00
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
logging . InstallLog . writeToFile ( " Django migrations completed successfully! " )
preFlightsChecks . stdOut ( " Django migrations completed successfully! " )
2025-08-01 14:56:30 +05:00
if not os . path . exists ( " /usr/local/CyberCP/public " ) :
os . mkdir ( " /usr/local/CyberCP/public " )
2025-09-24 13:56:32 +02:00
command = f " { python_path } manage.py collectstatic --noinput --clear "
2025-08-01 14:56:30 +05:00
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
## Moving static content to lscpd location
command = ' mv static /usr/local/CyberCP/public/ '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
try :
path = " /usr/local/CyberCP/version.txt "
writeToFile = open ( path , ' w ' )
writeToFile . writelines ( ' %s \n ' % ( VERSION ) )
writeToFile . writelines ( str ( BUILD ) )
writeToFile . close ( )
except :
pass
2025-09-23 09:55:27 +02:00
def fixBaseTemplateMigrations ( self ) :
"""
Fix baseTemplate migrations to prevent NodeNotFoundError on AlmaLinux 9 and Ubuntu 24
"""
try :
# Ensure baseTemplate migrations directory exists
migrations_dir = " /usr/local/CyberCP/baseTemplate/migrations "
if not os . path . exists ( migrations_dir ) :
os . makedirs ( migrations_dir )
logging . InstallLog . writeToFile ( " Created baseTemplate migrations directory " )
# Create __init__.py if it doesn't exist
init_file = os . path . join ( migrations_dir , " __init__.py " )
if not os . path . exists ( init_file ) :
with open ( init_file , ' w ' ) as f :
f . write ( " " )
logging . InstallLog . writeToFile ( " Created baseTemplate migrations __init__.py " )
# Create 0001_initial.py if it doesn't exist
initial_migration = os . path . join ( migrations_dir , " 0001_initial.py " )
if not os . path . exists ( initial_migration ) :
initial_content = ''' # Generated by Django 3.2.25 on 2024-01-01 00:00
from django . db import migrations , models
class Migration ( migrations . Migration ) :
initial = True
dependencies = [
]
operations = [
migrations . CreateModel (
name = ' CyberPanelCosmetic ' ,
fields = [
( ' id ' , models . BigAutoField ( auto_created = True , primary_key = True , serialize = False , verbose_name = ' ID ' ) ) ,
( ' MainDashboardCSS ' , models . TextField ( default = ' ' ) ) ,
] ,
) ,
migrations . CreateModel (
name = ' UserNotificationPreferences ' ,
fields = [
( ' id ' , models . BigAutoField ( auto_created = True , primary_key = True , serialize = False , verbose_name = ' ID ' ) ) ,
( ' backup_notification_dismissed ' , models . BooleanField ( default = False , help_text = ' Whether user has dismissed the backup notification ' ) ) ,
( ' ai_scanner_notification_dismissed ' , models . BooleanField ( default = False , help_text = ' Whether user has dismissed the AI scanner notification ' ) ) ,
( ' created_at ' , models . DateTimeField ( auto_now_add = True ) ) ,
( ' updated_at ' , models . DateTimeField ( auto_now = True ) ) ,
] ,
options = {
' verbose_name ' : ' User Notification Preferences ' ,
' verbose_name_plural ' : ' User Notification Preferences ' ,
} ,
) ,
migrations . CreateModel (
name = ' version ' ,
fields = [
( ' id ' , models . BigAutoField ( auto_created = True , primary_key = True , serialize = False , verbose_name = ' ID ' ) ) ,
( ' version ' , models . CharField ( max_length = 10 ) ) ,
( ' build ' , models . IntegerField ( ) ) ,
] ,
) ,
]
'''
with open ( initial_migration , ' w ' ) as f :
f . write ( initial_content )
logging . InstallLog . writeToFile ( " Created baseTemplate 0001_initial.py migration " )
# Create 0002_usernotificationpreferences.py if it doesn't exist
notification_migration = os . path . join ( migrations_dir , " 0002_usernotificationpreferences.py " )
if not os . path . exists ( notification_migration ) :
notification_content = ''' # Generated by Django 3.2.25 on 2024-01-01 00:01
from django . db import migrations , models
import django . db . models . deletion
class Migration ( migrations . Migration ) :
dependencies = [
( ' baseTemplate ' , ' 0001_initial ' ) ,
( ' loginSystem ' , ' 0001_initial ' ) ,
]
operations = [
migrations . AddField (
model_name = ' usernotificationpreferences ' ,
name = ' user ' ,
field = models . OneToOneField ( on_delete = django . db . models . deletion . CASCADE , related_name = ' notification_preferences ' , to = ' loginSystem.administrator ' ) ,
) ,
]
'''
with open ( notification_migration , ' w ' ) as f :
f . write ( notification_content )
logging . InstallLog . writeToFile ( " Created baseTemplate 0002_usernotificationpreferences.py migration " )
# Set proper permissions
command = " chown -R root:root " + migrations_dir
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = " chmod -R 755 " + migrations_dir
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
logging . InstallLog . writeToFile ( " baseTemplate migrations fixed successfully " )
preFlightsChecks . stdOut ( " baseTemplate migrations fixed successfully " )
except Exception as e :
logging . InstallLog . writeToFile ( " Error fixing baseTemplate migrations: " + str ( e ) )
preFlightsChecks . stdOut ( " Warning: Could not fix baseTemplate migrations: " + str ( e ) )
2025-08-01 14:56:30 +05:00
def fixCyberPanelPermissions ( self ) :
###### fix Core CyberPanel permissions
command = " usermod -G lscpd,lsadm,nobody lscpd "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = " usermod -G lscpd,lsadm,nogroup lscpd "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-09-24 00:36:38 +02:00
command = r " find /usr/local/CyberCP -type d -exec chmod 0755 {} \ ; "
2025-08-01 14:56:30 +05:00
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-09-24 00:36:38 +02:00
command = r " find /usr/local/CyberCP -type f -exec chmod 0644 {} \ ; "
2025-08-01 14:56:30 +05:00
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = " chmod -R 755 /usr/local/CyberCP/bin "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
## change owner
command = " chown -R root:root /usr/local/CyberCP "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
########### Fix LSCPD
2025-09-24 00:36:38 +02:00
command = r " find /usr/local/lscp -type d -exec chmod 0755 {} \ ; "
2025-08-01 14:56:30 +05:00
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-09-24 00:36:38 +02:00
command = r " find /usr/local/lscp -type f -exec chmod 0644 {} \ ; "
2025-08-01 14:56:30 +05:00
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = " chmod -R 755 /usr/local/lscp/bin "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = " chmod -R 755 /usr/local/lscp/fcgi-bin "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = " chown -R lscpd:lscpd /usr/local/CyberCP/public/phpmyadmin/tmp "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
## change owner
command = " chown -R root:root /usr/local/lscp "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = " chown -R lscpd:lscpd /usr/local/lscp/cyberpanel/rainloop "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = " chmod 700 /usr/local/CyberCP/cli/cyberPanel.py "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = " chmod 700 /usr/local/CyberCP/plogical/upgradeCritical.py "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = " chmod 755 /usr/local/CyberCP/postfixSenderPolicy/client.py "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = " chmod 640 /usr/local/CyberCP/CyberCP/settings.py "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = " chown root:cyberpanel /usr/local/CyberCP/CyberCP/settings.py "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
files = [ ' /etc/yum.repos.d/MariaDB.repo ' , ' /etc/pdns/pdns.conf ' , ' /etc/systemd/system/lscpd.service ' ,
' /etc/pure-ftpd/pure-ftpd.conf ' , ' /etc/pure-ftpd/pureftpd-pgsql.conf ' ,
' /etc/pure-ftpd/pureftpd-mysql.conf ' , ' /etc/pure-ftpd/pureftpd-ldap.conf ' ,
' /etc/dovecot/dovecot.conf ' , ' /usr/local/lsws/conf/httpd_config.xml ' ,
' /usr/local/lsws/conf/modsec.conf ' , ' /usr/local/lsws/conf/httpd.conf ' ]
for items in files :
command = ' chmod 644 %s ' % ( items )
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
impFile = [ ' /etc/pure-ftpd/pure-ftpd.conf ' , ' /etc/pure-ftpd/pureftpd-pgsql.conf ' ,
' /etc/pure-ftpd/pureftpd-mysql.conf ' , ' /etc/pure-ftpd/pureftpd-ldap.conf ' ,
' /etc/dovecot/dovecot.conf ' , ' /etc/pdns/pdns.conf ' , ' /etc/pure-ftpd/db/mysql.conf ' ,
' /etc/powerdns/pdns.conf ' ]
for items in impFile :
command = ' chmod 600 %s ' % ( items )
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = ' chmod 640 /etc/postfix/*.cf '
subprocess . call ( command , shell = True )
command = ' chmod 644 /etc/postfix/main.cf '
subprocess . call ( command , shell = True )
command = ' chmod 640 /etc/dovecot/*.conf '
subprocess . call ( command , shell = True )
command = ' chmod 644 /etc/dovecot/dovecot.conf '
subprocess . call ( command , shell = True )
command = ' chmod 640 /etc/dovecot/dovecot-sql.conf.ext '
subprocess . call ( command , shell = True )
command = ' chmod 644 /etc/postfix/dynamicmaps.cf '
subprocess . call ( command , shell = True )
fileM = [ ' /usr/local/lsws/FileManager/ ' , ' /usr/local/CyberCP/install/FileManager ' ,
' /usr/local/CyberCP/serverStatus/litespeed/FileManager ' , ' /usr/local/lsws/Example/html/FileManager ' ]
for items in fileM :
try :
shutil . rmtree ( items )
except :
pass
command = ' chmod 755 /etc/pure-ftpd/ '
subprocess . call ( command , shell = True )
command = ' chmod +x /usr/local/CyberCP/plogical/renew.py '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = ' chmod +x /usr/local/CyberCP/CLManager/CLPackages.py '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
clScripts = [ ' /usr/local/CyberCP/CLScript/panel_info.py ' , ' /usr/local/CyberCP/CLScript/CloudLinuxPackages.py ' ,
' /usr/local/CyberCP/CLScript/CloudLinuxUsers.py ' ,
' /usr/local/CyberCP/CLScript/CloudLinuxDomains.py ' ,
' /usr/local/CyberCP/CLScript/CloudLinuxResellers.py ' , ' /usr/local/CyberCP/CLScript/CloudLinuxAdmins.py ' ,
' /usr/local/CyberCP/CLScript/CloudLinuxDB.py ' , ' /usr/local/CyberCP/CLScript/UserInfo.py ' ]
for items in clScripts :
command = ' chmod +x %s ' % ( items )
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = ' chmod 600 /usr/local/CyberCP/plogical/adminPass.py '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = ' chmod 600 /etc/cagefs/exclude/cyberpanelexclude '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = " find /usr/local/CyberCP/ -name ' *.pyc ' -delete "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
if self . is_centos_family ( ) :
command = ' chown root:pdns /etc/pdns/pdns.conf '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = ' chmod 640 /etc/pdns/pdns.conf '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
else :
command = ' chown root:pdns /etc/powerdns/pdns.conf '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = ' chmod 640 /etc/powerdns/pdns.conf '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = ' chmod 640 /usr/local/lscp/cyberpanel/logs/access.log '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-08-31 12:32:58 +05:00
# Create complete SnappyMail directory structure early in installation
2025-08-30 23:40:20 +05:00
command = ' mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/configs/ '
2025-08-31 12:32:58 +05:00
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = ' mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/domains/ '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = ' mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/storage/ '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = ' mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/temp/ '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = ' mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/cache/ '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
# Set proper ownership early
command = " chown -R lscpd:lscpd /usr/local/lscp/cyberpanel/snappymail/ "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-08-31 13:16:22 +05:00
# Set proper permissions - make all data directories group writable
command = " chmod -R 775 /usr/local/lscp/cyberpanel/snappymail/data/ "
2025-08-31 12:32:58 +05:00
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-08-31 13:16:22 +05:00
# Ensure the web server user (nobody) can access the directories
# Note: lscpd is already added to nobody group earlier in the installation
command = " usermod -a -G lscpd nobody 2>/dev/null || true "
2025-08-31 12:32:58 +05:00
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-08-01 14:56:30 +05:00
2025-08-31 19:55:56 +05:00
# Fix SnappyMail public directory ownership early
2025-09-24 01:44:26 +02:00
command = " chown -R lscpd:lscpd /usr/local/CyberCP/public/snappymail/data || true "
2025-08-31 19:55:56 +05:00
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-08-01 14:56:30 +05:00
snappymailinipath = ' /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/configs/application.ini '
command = ' chmod 600 /usr/local/CyberCP/public/snappymail.php '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
###
WriteToFile = open ( ' /etc/fstab ' , ' a ' )
WriteToFile . write ( ' proc /proc proc defaults,hidepid=2 0 0 \n ' )
WriteToFile . close ( )
command = ' mount -o remount,rw,hidepid=2 /proc '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
## symlink protection
writeToFile = open ( ' /usr/lib/sysctl.d/50-default.conf ' , ' a ' )
writeToFile . writelines ( ' fs.protected_hardlinks = 1 \n ' )
writeToFile . writelines ( ' fs.protected_symlinks = 1 \n ' )
writeToFile . close ( )
command = ' sysctl --system '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = ' chmod 700 %s ' % ( ' /home/cyberpanel ' )
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
destPrivKey = " /usr/local/lscp/conf/key.pem "
command = ' chmod 600 %s ' % ( destPrivKey )
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
###
def install_unzip ( self ) :
self . stdOut ( " Install unzip " )
try :
self . install_package ( " unzip " )
except BaseException as msg :
logging . InstallLog . writeToFile ( ' [ERROR] ' + str ( msg ) + " [install_unzip] " )
def install_zip ( self ) :
self . stdOut ( " Install zip " )
try :
self . install_package ( " zip " )
except BaseException as msg :
logging . InstallLog . writeToFile ( ' [ERROR] ' + str ( msg ) + " [install_zip] " )
def download_install_phpmyadmin ( self ) :
try :
if not os . path . exists ( " /usr/local/CyberCP/public " ) :
os . mkdir ( " /usr/local/CyberCP/public " )
command = ' wget -O /usr/local/CyberCP/public/phpmyadmin.zip https://github.com/usmannasir/cyberpanel/raw/stable/phpmyadmin.zip '
preFlightsChecks . call ( command , self . distro , ' [download_install_phpmyadmin] ' ,
command , 1 , 0 , os . EX_OSERR )
command = ' unzip /usr/local/CyberCP/public/phpmyadmin.zip -d /usr/local/CyberCP/public '
preFlightsChecks . call ( command , self . distro , ' [download_install_phpmyadmin] ' ,
command , 1 , 0 , os . EX_OSERR )
command = ' mv /usr/local/CyberCP/public/phpMyAdmin-*-all-languages /usr/local/CyberCP/public/phpmyadmin '
subprocess . call ( command , shell = True )
command = ' rm -f /usr/local/CyberCP/public/phpmyadmin.zip '
preFlightsChecks . call ( command , self . distro , ' [download_install_phpmyadmin] ' ,
command , 1 , 0 , os . EX_OSERR )
## Write secret phrase
rString = install_utils . generate_random_string ( 32 )
data = open ( ' /usr/local/CyberCP/public/phpmyadmin/config.sample.inc.php ' , ' r ' ) . readlines ( )
writeToFile = open ( ' /usr/local/CyberCP/public/phpmyadmin/config.inc.php ' , ' w ' )
writeE = 1
phpMyAdminContent = """
$ cfg [ ' Servers ' ] [ $ i ] [ ' AllowNoPassword ' ] = false ;
$ cfg [ ' Servers ' ] [ $ i ] [ ' auth_type ' ] = ' signon ' ;
$ cfg [ ' Servers ' ] [ $ i ] [ ' SignonSession ' ] = ' SignonSession ' ;
$ cfg [ ' Servers ' ] [ $ i ] [ ' SignonURL ' ] = ' phpmyadminsignin.php ' ;
$ cfg [ ' Servers ' ] [ $ i ] [ ' LogoutURL ' ] = ' phpmyadminsignin.php?logout ' ;
"""
for items in data :
if items . find ( ' blowfish_secret ' ) > - 1 :
writeToFile . writelines (
" $cfg[ ' blowfish_secret ' ] = ' " + rString + " ' ; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */ \n " )
elif items . find ( ' /* Authentication type */ ' ) > - 1 :
writeToFile . writelines ( items )
writeToFile . write ( phpMyAdminContent )
writeE = 0
elif items . find ( " $cfg[ ' Servers ' ][$i][ ' AllowNoPassword ' ] " ) > - 1 :
writeE = 1
else :
if writeE :
writeToFile . writelines ( items )
writeToFile . writelines ( " $cfg[ ' TempDir ' ] = ' /usr/local/CyberCP/public/phpmyadmin/tmp ' ; \n " )
writeToFile . close ( )
os . mkdir ( ' /usr/local/CyberCP/public/phpmyadmin/tmp ' )
command = ' chown -R lscpd:lscpd /usr/local/CyberCP/public/phpmyadmin '
preFlightsChecks . call ( command , self . distro , ' [chown -R lscpd:lscpd /usr/local/CyberCP/public/phpmyadmin] ' ,
' chown -R lscpd:lscpd /usr/local/CyberCP/public/phpmyadmin ' , 1 , 0 , os . EX_OSERR )
if self . remotemysql == ' ON ' :
command = " sed -i ' s| ' localhost ' | ' %s ' |g ' %s " % (
self . mysqlhost , ' /usr/local/CyberCP/public/phpmyadmin/config.inc.php ' )
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = ' cp /usr/local/CyberCP/plogical/phpmyadminsignin.php /usr/local/CyberCP/public/phpmyadmin/phpmyadminsignin.php '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
if self . remotemysql == ' ON ' :
command = " sed -i ' s|localhost| %s |g ' /usr/local/CyberCP/public/phpmyadmin/phpmyadminsignin.php " % (
self . mysqlhost )
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
except BaseException as msg :
logging . InstallLog . writeToFile ( ' [ERROR] ' + str ( msg ) + " [download_install_phpmyadmin] " )
return 0
###################################################### Email setup
def install_postfix_dovecot ( self ) :
self . stdOut ( " Install dovecot - first remove postfix " )
try :
if self . distro == centos :
self . remove_package ( " postfix " )
elif self . distro == ubuntu :
self . remove_package ( " postfix " )
self . stdOut ( " Install dovecot - do the install " )
if self . distro == centos :
command = ' yum install --enablerepo=gf-plus -y postfix3 postfix3-ldap postfix3-mysql postfix3-pcre '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
elif self . distro == cent8 :
clAPVersion = FetchCloudLinuxAlmaVersionVersion ( )
type = clAPVersion . split ( ' - ' ) [ 0 ]
version = int ( clAPVersion . split ( ' - ' ) [ 1 ] )
if type == ' al ' and version > = 90 :
2025-08-19 18:36:48 +05:00
command = ' dnf --nogpg install -y https://mirror.ghettoforge.net/distributions/gf/gf-release-latest.gf.el9.noarch.rpm '
2025-08-01 14:56:30 +05:00
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
else :
2025-08-19 18:36:48 +05:00
command = ' dnf --nogpg install -y https://mirror.ghettoforge.net/distributions/gf/gf-release-latest.gf.el8.noarch.rpm '
2025-08-01 14:56:30 +05:00
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = ' dnf install --enablerepo=gf-plus postfix3 postfix3-mysql -y '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
elif self . distro == openeuler :
command = ' dnf install postfix -y '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
else :
self . install_package ( " debconf-utils " , silent = True )
file_name = self . cwd + ' /pf.unattend.text '
pf = open ( file_name , ' w ' )
pf . write ( ' postfix postfix/mailname string ' + str ( socket . getfqdn ( ) + ' \n ' ) )
pf . write ( ' postfix postfix/main_mailer_type string " Internet Site " \n ' )
pf . close ( )
command = ' debconf-set-selections ' + file_name
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = ' DEBIAN_FRONTEND=noninteractive apt-get -y install postfix postfix-mysql '
# os.remove(file_name)
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR , True )
##
2025-09-24 01:11:23 +02:00
# Remove conflicting dovecot packages first
try :
2025-09-24 11:28:20 +02:00
if self . distro == centos :
# CentOS 7 (Legacy - EOL) - use yum
2025-09-24 01:11:23 +02:00
preFlightsChecks . call ( ' yum remove -y dovecot dovecot-* ' , self . distro ,
' Remove conflicting dovecot packages ' ,
' Remove conflicting dovecot packages ' , 1 , 0 , os . EX_OSERR )
2025-09-24 11:28:20 +02:00
elif self . distro in [ cent8 , openeuler ] :
# CentOS 8, AlmaLinux 8/9/10, RockyLinux 8/9, RHEL 8/9, CloudLinux 8/9 - use dnf
preFlightsChecks . call ( ' dnf remove -y dovecot dovecot-* ' , self . distro ,
' Remove conflicting dovecot packages ' ,
' Remove conflicting dovecot packages ' , 1 , 0 , os . EX_OSERR )
else :
# Ubuntu 24.04/22.04/20.04, Debian 13/12/11 - use apt
preFlightsChecks . call ( ' apt-get remove -y dovecot dovecot-* ' , self . distro ,
' Remove conflicting dovecot packages ' ,
' Remove conflicting dovecot packages ' , 1 , 0 , os . EX_OSERR )
2025-09-24 01:11:23 +02:00
except :
pass # Continue if removal fails
2025-08-01 14:56:30 +05:00
if self . distro == centos :
2025-09-24 11:28:20 +02:00
# CentOS 7 (Legacy - EOL)
2025-09-24 01:11:23 +02:00
command = ' yum --enablerepo=gf-plus -y install dovecot23 dovecot23-mysql --allowerasing '
2025-08-01 14:56:30 +05:00
elif self . distro == cent8 :
2025-09-24 11:28:20 +02:00
# CentOS 8, AlmaLinux 8, RockyLinux 8, RHEL 8, CloudLinux 8
2025-09-24 01:11:23 +02:00
command = ' dnf install --enablerepo=gf-plus dovecot23 dovecot23-mysql -y --allowerasing '
2025-08-01 14:56:30 +05:00
elif self . distro == openeuler :
2025-09-24 11:28:20 +02:00
# AlmaLinux 9/10, RockyLinux 9, RHEL 9, CloudLinux 9, and other modern RHEL-based systems
dovecot_commands = [
' dnf install dovecot dovecot-mysql -y --skip-broken --nobest ' ,
' dnf install dovecot23 dovecot23-mysql -y --skip-broken --nobest ' ,
' dnf install dovecot -y --skip-broken --nobest '
]
dovecot_installed = False
for cmd in dovecot_commands :
try :
preFlightsChecks . call ( cmd , self . distro , cmd , cmd , 1 , 1 , os . EX_OSERR , True )
if os . path . exists ( ' /etc/dovecot ' ) or os . path . exists ( ' /usr/sbin/dovecot ' ) :
dovecot_installed = True
break
except :
continue
if not dovecot_installed :
command = ' dnf install dovecot -y --skip-broken --nobest --allowerasing '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR , True )
2025-08-01 14:56:30 +05:00
else :
2025-09-24 11:28:20 +02:00
# Ubuntu 24.04/22.04/20.04, Debian 13/12/11
2025-08-01 14:56:30 +05:00
command = ' DEBIAN_FRONTEND=noninteractive apt-get -y install dovecot-mysql dovecot-imapd dovecot-pop3d '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR , True )
2025-09-24 11:28:20 +02:00
# Ensure Dovecot service is properly configured
self . manage_service ( ' dovecot ' , ' enable ' )
self . manage_service ( ' dovecot ' , ' start ' )
# Verify Dovecot installation
if os . path . exists ( ' /usr/sbin/dovecot ' ) or os . path . exists ( ' /usr/bin/dovecot ' ) :
logging . InstallLog . writeToFile ( " Dovecot installation successful " )
else :
logging . InstallLog . writeToFile ( " [WARNING] Dovecot binary not found after installation " )
2025-08-01 14:56:30 +05:00
except BaseException as msg :
logging . InstallLog . writeToFile ( ' [ERROR] ' + str ( msg ) + " [install_postfix_dovecot] " )
return 0
return 1
def setup_email_Passwords ( self , mysqlPassword , mysql ) :
try :
2025-09-24 20:23:49 +02:00
# Ensure mysqlPassword is not None
if mysqlPassword is None :
mysqlPassword = self . mysql_Root_password
logging . InstallLog . writeToFile ( " Warning: mysqlPassword was None, using mysql_Root_password " )
2025-08-01 14:56:30 +05:00
logging . InstallLog . writeToFile ( " Setting up authentication for Postfix and Dovecot... " )
os . chdir ( self . cwd )
mysql_virtual_domains = " email-configs-one/mysql-virtual_domains.cf "
mysql_virtual_forwardings = " email-configs-one/mysql-virtual_forwardings.cf "
mysql_virtual_mailboxes = " email-configs-one/mysql-virtual_mailboxes.cf "
mysql_virtual_email2email = " email-configs-one/mysql-virtual_email2email.cf "
dovecotmysql = " email-configs-one/dovecot-sql.conf.ext "
### update password:
data = open ( dovecotmysql , " r " ) . readlines ( )
writeDataToFile = open ( dovecotmysql , " w " )
if mysql == ' Two ' :
dataWritten = " connect = host=127.0.0.1 dbname=cyberpanel user=cyberpanel password= " + mysqlPassword + " port=3307 \n "
else :
dataWritten = " connect = host=localhost dbname=cyberpanel user=cyberpanel password= " + mysqlPassword + " port=3306 \n "
for items in data :
if items . find ( " connect " ) > - 1 :
writeDataToFile . writelines ( dataWritten )
else :
writeDataToFile . writelines ( items )
writeDataToFile . close ( )
### update password:
data = open ( mysql_virtual_domains , " r " ) . readlines ( )
writeDataToFile = open ( mysql_virtual_domains , " w " )
dataWritten = " password = " + mysqlPassword + " \n "
for items in data :
if items . find ( " password " ) > - 1 :
writeDataToFile . writelines ( dataWritten )
else :
writeDataToFile . writelines ( items )
writeDataToFile . close ( )
### update password:
data = open ( mysql_virtual_forwardings , " r " ) . readlines ( )
writeDataToFile = open ( mysql_virtual_forwardings , " w " )
dataWritten = " password = " + mysqlPassword + " \n "
for items in data :
if items . find ( " password " ) > - 1 :
writeDataToFile . writelines ( dataWritten )
else :
writeDataToFile . writelines ( items )
writeDataToFile . close ( )
### update password:
data = open ( mysql_virtual_mailboxes , " r " ) . readlines ( )
writeDataToFile = open ( mysql_virtual_mailboxes , " w " )
dataWritten = " password = " + mysqlPassword + " \n "
for items in data :
if items . find ( " password " ) > - 1 :
writeDataToFile . writelines ( dataWritten )
else :
writeDataToFile . writelines ( items )
writeDataToFile . close ( )
### update password:
data = open ( mysql_virtual_email2email , " r " ) . readlines ( )
writeDataToFile = open ( mysql_virtual_email2email , " w " )
dataWritten = " password = " + mysqlPassword + " \n "
for items in data :
if items . find ( " password " ) > - 1 :
writeDataToFile . writelines ( dataWritten )
else :
writeDataToFile . writelines ( items )
writeDataToFile . close ( )
if self . remotemysql == ' ON ' :
command = " sed -i ' s|host=localhost|host= %s |g ' %s " % ( self . mysqlhost , dovecotmysql )
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
command = " sed -i ' s|port=3306|port= %s |g ' %s " % ( self . mysqlport , dovecotmysql )
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
##
command = " sed -i ' s|localhost| %s : %s |g ' %s " % ( self . mysqlhost , self . mysqlport , mysql_virtual_domains )
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
command = " sed -i ' s|localhost| %s : %s |g ' %s " % (
self . mysqlhost , self . mysqlport , mysql_virtual_forwardings )
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
command = " sed -i ' s|localhost| %s : %s |g ' %s " % (
self . mysqlhost , self . mysqlport , mysql_virtual_mailboxes )
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
command = " sed -i ' s|localhost| %s : %s |g ' %s " % (
self . mysqlhost , self . mysqlport , mysql_virtual_email2email )
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
logging . InstallLog . writeToFile ( " Authentication for Postfix and Dovecot set. " )
except BaseException as msg :
logging . InstallLog . writeToFile ( ' [ERROR] ' + str ( msg ) + " [setup_email_Passwords] " )
return 0
return 1
def centos_lib_dir_to_ubuntu ( self , filename , old , new ) :
try :
fd = open ( filename , ' r ' )
lines = fd . readlines ( )
fd . close ( )
fd = open ( filename , ' w ' )
centos_prefix = old
ubuntu_prefix = new
for line in lines :
index = line . find ( centos_prefix )
if index != - 1 :
line = line [ : index ] + ubuntu_prefix + line [ index + len ( centos_prefix ) : ]
fd . write ( line )
fd . close ( )
except IOError as err :
self . stdOut (
" [ERROR] Error converting: " + filename + " from centos defaults to ubuntu defaults: " + str ( err ) , 1 ,
1 , os . EX_OSERR )
def setup_postfix_dovecot_config ( self , mysql ) :
try :
logging . InstallLog . writeToFile ( " Configuring postfix and dovecot... " )
os . chdir ( self . cwd )
mysql_virtual_domains = " /etc/postfix/mysql-virtual_domains.cf "
mysql_virtual_forwardings = " /etc/postfix/mysql-virtual_forwardings.cf "
mysql_virtual_mailboxes = " /etc/postfix/mysql-virtual_mailboxes.cf "
mysql_virtual_email2email = " /etc/postfix/mysql-virtual_email2email.cf "
main = " /etc/postfix/main.cf "
master = " /etc/postfix/master.cf "
dovecot = " /etc/dovecot/dovecot.conf "
dovecotmysql = " /etc/dovecot/dovecot-sql.conf.ext "
2025-09-24 11:28:20 +02:00
# Ensure dovecot directory exists
os . makedirs ( " /etc/dovecot " , exist_ok = True )
# Also ensure dovecot conf.d directory exists
os . makedirs ( " /etc/dovecot/conf.d " , exist_ok = True )
# Check if Dovecot is installed before proceeding
if not os . path . exists ( ' /usr/sbin/dovecot ' ) and not os . path . exists ( ' /usr/bin/dovecot ' ) :
logging . InstallLog . writeToFile ( " [ERROR] Dovecot not installed, cannot configure " )
return 0
2025-08-01 14:56:30 +05:00
if os . path . exists ( mysql_virtual_domains ) :
os . remove ( mysql_virtual_domains )
if os . path . exists ( mysql_virtual_forwardings ) :
os . remove ( mysql_virtual_forwardings )
if os . path . exists ( mysql_virtual_mailboxes ) :
os . remove ( mysql_virtual_mailboxes )
if os . path . exists ( mysql_virtual_email2email ) :
os . remove ( mysql_virtual_email2email )
if os . path . exists ( main ) :
os . remove ( main )
if os . path . exists ( master ) :
os . remove ( master )
if os . path . exists ( dovecot ) :
os . remove ( dovecot )
if os . path . exists ( dovecotmysql ) :
os . remove ( dovecotmysql )
###############Getting SSL
command = ' openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -subj " /C=US/ST=Denial/L=Springfield/O=Dis/CN=www.example.com " -keyout /etc/postfix/key.pem -out /etc/postfix/cert.pem '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
##
command = ' openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -subj " /C=US/ST=Denial/L=Springfield/O=Dis/CN=www.example.com " -keyout /etc/dovecot/key.pem -out /etc/dovecot/cert.pem '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
# Cleanup config files for ubuntu
if self . distro == ubuntu :
preFlightsChecks . stdOut ( " Cleanup postfix/dovecot config files " , 1 )
self . centos_lib_dir_to_ubuntu ( " email-configs-one/master.cf " , " /usr/libexec/ " , " /usr/lib/ " )
self . centos_lib_dir_to_ubuntu ( " email-configs-one/main.cf " , " /usr/libexec/postfix " ,
" /usr/lib/postfix/sbin " )
########### Copy config files
shutil . copy ( " email-configs-one/mysql-virtual_domains.cf " , " /etc/postfix/mysql-virtual_domains.cf " )
shutil . copy ( " email-configs-one/mysql-virtual_forwardings.cf " ,
" /etc/postfix/mysql-virtual_forwardings.cf " )
shutil . copy ( " email-configs-one/mysql-virtual_mailboxes.cf " , " /etc/postfix/mysql-virtual_mailboxes.cf " )
shutil . copy ( " email-configs-one/mysql-virtual_email2email.cf " ,
" /etc/postfix/mysql-virtual_email2email.cf " )
shutil . copy ( " email-configs-one/main.cf " , main )
shutil . copy ( " email-configs-one/master.cf " , master )
2025-09-24 11:28:20 +02:00
# Copy Dovecot configuration files with fallback
try :
shutil . copy ( " email-configs-one/dovecot.conf " , dovecot )
shutil . copy ( " email-configs-one/dovecot-sql.conf.ext " , dovecotmysql )
except FileNotFoundError :
# Fallback: create basic dovecot.conf if template not found
logging . InstallLog . writeToFile ( " [WARNING] Dovecot config templates not found, creating basic configuration " )
# Create basic dovecot.conf
with open ( dovecot , ' w ' ) as f :
f . write ( ''' protocols = imap pop3
log_timestamp = " % Y- % m- %d % H: % M: % S "
ssl_cert = < cert . pem
ssl_key = < key . pem
mail_plugins = zlib
namespace {
type = private
separator = .
prefix = INBOX .
inbox = yes
}
service auth {
unix_listener auth - master {
mode = 0600
user = vmail
}
unix_listener / var / spool / postfix / private / auth {
mode = 0666
user = postfix
group = postfix
}
user = root
}
service auth - worker {
user = root
}
protocol lda {
log_path = / home / vmail / dovecot - deliver . log
auth_socket_path = / var / run / dovecot / auth - master
postmaster_address = postmaster @example.com
mail_plugins = zlib
}
protocol pop3 {
pop3_uidl_format = % 08 Xu % 08 Xv
mail_plugins = $ mail_plugins zlib
}
protocol imap {
mail_plugins = $ mail_plugins zlib imap_zlib
}
passdb {
driver = sql
args = / etc / dovecot / dovecot - sql . conf . ext
}
userdb {
driver = sql
args = / etc / dovecot / dovecot - sql . conf . ext
}
plugin {
zlib_save = gz
zlib_save_level = 6
}
service stats {
unix_listener stats - reader {
user = vmail
group = vmail
mode = 0660
}
unix_listener stats - writer {
user = vmail
group = vmail
mode = 0660
}
}
''' )
# Create basic dovecot-sql.conf.ext
with open ( dovecotmysql , ' w ' ) as f :
f . write ( f ''' # Database driver: mysql, pgsql, sqlite
driver = mysql
# Database connection string
connect = host = localhost dbname = cyberpanel user = cyberpanel password = { self . mysqlPassword }
# Default password scheme
default_pass_scheme = MD5 - CRYPT
# SQL query to get password
password_query = SELECT email as user , password FROM mail_users WHERE email = ' %u ' ;
# SQL query to get user info
user_query = SELECT email as user , password , ' vmail ' as uid , ' vmail ' as gid , ' /home/vmail/ %d / % n ' as home FROM mail_users WHERE email = ' %u ' ;
''' )
2025-08-01 14:56:30 +05:00
########### Set custom settings
# We are going to leverage postconfig -e to edit the settings for hostname
command = " postconf -e ' myhostname = %s ' " % ( str ( socket . getfqdn ( ) ) )
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
# We are explicitly going to use sed to set the hostname default from "myhostname = server.example.com"
# to the fqdn from socket if the default is still found
command = " sed -i ' s|server.example.com| %s |g ' %s " % ( str ( socket . getfqdn ( ) ) , main )
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
######################################## Permissions
command = ' chmod o= /etc/postfix/mysql-virtual_domains.cf '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
##
command = ' chmod o= /etc/postfix/mysql-virtual_forwardings.cf '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
##
command = ' chmod o= /etc/postfix/mysql-virtual_mailboxes.cf '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
##
command = ' chmod o= /etc/postfix/mysql-virtual_email2email.cf '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
##
command = ' chmod o= ' + main
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
##
command = ' chmod o= ' + master
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
#######################################
command = ' chgrp postfix /etc/postfix/mysql-virtual_domains.cf '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
##
command = ' chgrp postfix /etc/postfix/mysql-virtual_forwardings.cf '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
##
command = ' chgrp postfix /etc/postfix/mysql-virtual_mailboxes.cf '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
##
command = ' chgrp postfix /etc/postfix/mysql-virtual_email2email.cf '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
##
command = ' chgrp postfix ' + main
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
##
command = ' chgrp postfix ' + master
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
######################################## users and groups
command = ' groupadd -g 5000 vmail '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
##
command = ' useradd -g vmail -u 5000 vmail -d /home/vmail -m '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
######################################## Further configurations
# hostname = socket.gethostname()
################################### Restart postix
self . manage_service ( ' postfix ' , ' enable ' )
self . manage_service ( ' postfix ' , ' start ' )
######################################## Permissions
command = ' chgrp dovecot /etc/dovecot/dovecot-sql.conf.ext '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
##
command = ' chmod o= /etc/dovecot/dovecot-sql.conf.ext '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
################################### Restart dovecot
self . manage_service ( ' dovecot ' , ' enable ' )
self . manage_service ( ' dovecot ' , ' start ' )
2025-09-24 11:28:20 +02:00
# Verify Dovecot service is running
if self . manage_service ( ' dovecot ' , ' status ' ) == 0 :
logging . InstallLog . writeToFile ( " Dovecot service started successfully " )
else :
logging . InstallLog . writeToFile ( " [WARNING] Dovecot service may not be running properly " )
2025-08-01 14:56:30 +05:00
##
self . manage_service ( ' postfix ' , ' restart ' )
## chaging permissions for main.cf
command = " chmod 755 " + main
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
if self . distro == ubuntu :
command = " mkdir -p /etc/pki/dovecot/private/ "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = " mkdir -p /etc/pki/dovecot/certs/ "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = " mkdir -p /etc/opendkim/keys/ "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = " sed -i ' s/auth_mechanisms = plain/#auth_mechanisms = plain/g ' /etc/dovecot/conf.d/10-auth.conf "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
## Ubuntu 18.10 ssl_dh for dovecot 2.3.2.1
if get_Ubuntu_release ( ) == 18.10 :
dovecotConf = ' /etc/dovecot/dovecot.conf '
data = open ( dovecotConf , ' r ' ) . readlines ( )
writeToFile = open ( dovecotConf , ' w ' )
for items in data :
if items . find ( ' ssl_key = <key.pem ' ) > - 1 :
writeToFile . writelines ( items )
writeToFile . writelines ( ' ssl_dh = </usr/share/dovecot/dh.pem \n ' )
else :
writeToFile . writelines ( items )
writeToFile . close ( )
self . manage_service ( ' dovecot ' , ' restart ' )
logging . InstallLog . writeToFile ( " Postfix and Dovecot configured " )
except BaseException as msg :
logging . InstallLog . writeToFile ( ' [ERROR] ' + str ( msg ) + " [setup_postfix_dovecot_config] " )
return 0
return 1
def downoad_and_install_raindloop ( self ) :
try :
#######
if not os . path . exists ( " /usr/local/CyberCP/public " ) :
os . mkdir ( " /usr/local/CyberCP/public " )
if os . path . exists ( " /usr/local/CyberCP/public/snappymail " ) :
return 0
os . chdir ( " /usr/local/CyberCP/public " )
command = ' wget https://github.com/the-djmaze/snappymail/releases/download/v %s /snappymail- %s .zip ' % ( preFlightsChecks . SnappyVersion , preFlightsChecks . SnappyVersion )
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
#############
command = ' unzip snappymail- %s .zip -d /usr/local/CyberCP/public/snappymail ' % ( preFlightsChecks . SnappyVersion )
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
try :
os . remove ( " snappymail- %s .zip " % ( preFlightsChecks . SnappyVersion ) )
except :
pass
#######
os . chdir ( " /usr/local/CyberCP/public/snappymail " )
2025-09-24 00:36:38 +02:00
command = r ' find . -type d -exec chmod 755 {} \ ; '
2025-08-01 14:56:30 +05:00
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
#############
2025-09-24 00:36:38 +02:00
command = r ' find . -type f -exec chmod 644 {} \ ; '
2025-08-01 14:56:30 +05:00
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
######
2025-08-30 23:40:20 +05:00
# Create SnappyMail data directories with proper structure
command = " mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/configs/ "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = " mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/domains/ "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = " mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/storage/ "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = " mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/temp/ "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = " mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/cache/ "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
# Set proper ownership for SnappyMail data directories
command = " chown -R lscpd:lscpd /usr/local/lscp/cyberpanel/snappymail/ "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-08-31 13:16:22 +05:00
# Set proper permissions for SnappyMail data directories (group writable)
command = " chmod -R 775 /usr/local/lscp/cyberpanel/snappymail/data/ "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
# Ensure web server users are in the lscpd group for access
command = " usermod -a -G lscpd nobody 2>/dev/null || true "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-08-31 19:55:56 +05:00
# Fix SnappyMail public directory ownership immediately after creation
2025-09-24 01:44:26 +02:00
command = " chown -R lscpd:lscpd /usr/local/CyberCP/public/snappymail/data || true "
2025-08-30 23:40:20 +05:00
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-08-01 14:56:30 +05:00
command = " mkdir -p /usr/local/lscp/cyberpanel/rainloop/data "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
### Enable sub-folders
command = " mkdir -p /usr/local/lscp/cyberpanel/rainloop/data/_data_/_default_/configs/ "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
# labsPath = '/usr/local/lscp/cyberpanel/rainloop/data/_data_/_default_/configs/application.ini'
#
# labsData = """[labs]
# imap_folder_list_limit = 0
# autocreate_system_folders = On
# """
#
# # writeToFile = open(labsPath, 'a')
# # writeToFile.write(labsData)
# # writeToFile.close()
#
# iPath = os.listdir('/usr/local/CyberCP/public/snappymail/snappymail/v/')
#
# path = "/usr/local/CyberCP/public/snappymail/snappymail/v/%s/include.php" % (iPath[0])
#
# data = open(path, 'r').readlines()
# writeToFile = open(path, 'w')
#
# for items in data:
# if items.find("$sCustomDataPath = '';") > -1:
# writeToFile.writelines(
# " $sCustomDataPath = '/usr/local/lscp/cyberpanel/rainloop/data';\n")
# else:
# writeToFile.writelines(items)
#
# writeToFile.close()
#
# includeFileOldPath = '/usr/local/CyberCP/public/snappymail/_include.php'
# includeFileNewPath = '/usr/local/CyberCP/public/snappymail/include.php'
#
# if os.path.exists(includeFileOldPath):
# writeToFile = open(includeFileOldPath, 'a')
# writeToFile.write("\ndefine('APP_DATA_FOLDER_PATH', '/usr/local/lscp/cyberpanel/rainloop/data/');\n")
# writeToFile.close()
#
# command = 'mv %s %s' % (includeFileOldPath, includeFileNewPath)
# preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
#
# #command = "sed -i 's|autocreate_system_folders = Off|autocreate_system_folders = On|g' %s" % (labsPath)
# command = "sed -i 's|verify_certificate = On|verify_certificate = Off|g' %s" % (labsPath)
# preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
#
# ### now download and install actual plugin
#
# command = f'mkdir /usr/local/lscp/cyberpanel/rainloop/data/_data_/_default_/plugins/mailbox-detect'
# preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
#
# command = f'chmod 700 /usr/local/lscp/cyberpanel/rainloop/data/_data_/_default_/plugins/mailbox-detect'
# preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
#
# command = f'chmod 700 /usr/local/lscp/cyberpanel/rainloop/data/_data_/_default_/plugins/mailbox-detect'
# preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
#
# command = f'wget -O /usr/local/lscp/cyberpanel/rainloop/data/_data_/_default_/plugins/mailbox-detect/index.php https://raw.githubusercontent.com/the-djmaze/snappymail/master/plugins/mailbox-detect/index.php'
# preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
#
# command = f'chmod 644 /usr/local/lscp/cyberpanel/rainloop/data/_data_/_default_/plugins/mailbox-detect/index.php'
# preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
#
# command = f'chown lscpd:lscpd /usr/local/lscp/cyberpanel/rainloop/data/_data_/_default_/plugins/mailbox-detect/index.php'
# preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
#
# ### Enable plugins and enable mailbox creation plugin
#
# labsDataLines = open(labsPath, 'r').readlines()
# PluginsActivator = 0
# WriteToFile = open(labsPath, 'w')
# for lines in labsDataLines:
# if lines.find('[plugins]') > -1:
# PluginsActivator = 1
# WriteToFile.write(lines)
# elif PluginsActivator and lines.find('enable = ') > -1:
# WriteToFile.write(f'enable = On\n')
# elif PluginsActivator and lines.find('enabled_list = ') > -1:
# WriteToFile.write(f'enabled_list = "mailbox-detect"\n')
# elif PluginsActivator == 1 and lines.find('[defaults]') > -1:
# PluginsActivator = 0
# WriteToFile.write(lines)
# else:
# WriteToFile.write(lines)
# WriteToFile.close()
#
# ## enable auto create in the enabled plugin
# PluginsFilePath = '/usr/local/lscp/cyberpanel/rainloop/data/_data_/_default_/configs/plugin-mailbox-detect.json'
#
# WriteToFile = open(PluginsFilePath, 'w')
# WriteToFile.write("""{
# "plugin": {
# "autocreate_system_folders": true
# }
# }
# """)
# WriteToFile.close()
#
# command = f'chown lscpd:lscpd {PluginsFilePath}'
# preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
#
# command = f'chmod 600 {PluginsFilePath}'
# preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
command = f ' wget -O /usr/local/CyberCP/snappymail_cyberpanel.php https://raw.githubusercontent.com/the-djmaze/snappymail/master/integrations/cyberpanel/install.php '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = f ' /usr/local/lsws/lsphp80/bin/php /usr/local/CyberCP/snappymail_cyberpanel.php '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
except BaseException as msg :
logging . InstallLog . writeToFile ( ' [ERROR] ' + str ( msg ) + " [downoad_and_install_snappymail] " )
return 0
return 1
###################################################### Email setup ends!
def reStartLiteSpeed ( self ) :
command = install_utils . format_restart_litespeed_command ( self . server_root_path )
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
def removeUfw ( self ) :
try :
preFlightsChecks . stdOut ( " Checking to see if ufw firewall is installed (will be removed) " , 1 )
status = subprocess . check_output ( shlex . split ( ' ufw status ' ) ) . decode ( " utf-8 " )
preFlightsChecks . stdOut ( " ufw current status: " + status + " ...will be removed " )
except BaseException as msg :
preFlightsChecks . stdOut ( " [ERROR] Expected access to ufw not available, do not need to remove it " , 1 )
return True
try :
preFlightsChecks . call ( ' DEBIAN_FRONTEND=noninteractive apt-get -y remove ufw ' , self . distro , ' [remove_ufw] ' , ' Remove ufw firewall ' +
' (using firewalld) ' , 1 , 0 , os . EX_OSERR , True )
except :
pass
return True
def findSSHPort ( self ) :
try :
sshData = subprocess . check_output ( shlex . split ( ' cat /etc/ssh/sshd_config ' ) ) . decode ( " utf-8 " ) . split ( ' \n ' )
for items in sshData :
if items . find ( ' Port ' ) > - 1 :
if items [ 0 ] == 0 :
pass
else :
return items . split ( ' ' ) [ 1 ]
return ' 22 '
except BaseException as msg :
return ' 22 '
def installFirewalld ( self ) :
2025-09-18 14:20:01 +05:00
if self . distro == ubuntu or self . distro == debian12 :
2025-08-01 14:56:30 +05:00
self . removeUfw ( )
try :
preFlightsChecks . stdOut ( " Enabling Firewall! " )
self . install_package ( " firewalld " )
######
if self . distro == centos :
2025-09-18 14:20:01 +05:00
# Not available in ubuntu/debian
2025-08-01 14:56:30 +05:00
self . manage_service ( ' dbus ' , ' restart ' )
2025-09-18 14:20:01 +05:00
elif self . distro == debian12 :
# For Debian 12, ensure dbus is running for firewalld
self . manage_service ( ' dbus ' , ' start ' )
self . manage_service ( ' dbus ' , ' enable ' )
2025-08-01 14:56:30 +05:00
2025-09-18 14:20:01 +05:00
# Restart systemd-logind on all systems
2025-08-01 14:56:30 +05:00
self . manage_service ( ' systemd-logind ' , ' restart ' )
self . manage_service ( ' firewalld ' , ' start ' )
self . manage_service ( ' firewalld ' , ' enable ' )
FirewallUtilities . addRule ( " tcp " , " 8090 " )
FirewallUtilities . addRule ( " tcp " , " 7080 " )
FirewallUtilities . addRule ( " tcp " , " 80 " )
FirewallUtilities . addRule ( " tcp " , " 443 " )
FirewallUtilities . addRule ( " tcp " , " 21 " )
FirewallUtilities . addRule ( " tcp " , " 25 " )
FirewallUtilities . addRule ( " tcp " , " 587 " )
FirewallUtilities . addRule ( " tcp " , " 465 " )
FirewallUtilities . addRule ( " tcp " , " 110 " )
FirewallUtilities . addRule ( " tcp " , " 143 " )
FirewallUtilities . addRule ( " tcp " , " 993 " )
FirewallUtilities . addRule ( " tcp " , " 995 " )
FirewallUtilities . addRule ( " udp " , " 53 " )
FirewallUtilities . addRule ( " tcp " , " 53 " )
FirewallUtilities . addRule ( " tcp " , " 8888 " )
FirewallUtilities . addRule ( " udp " , " 443 " )
FirewallUtilities . addRule ( " tcp " , " 40110-40210 " )
try :
SSHPort = self . findSSHPort ( )
if SSHPort != ' 22 ' :
FirewallUtilities . addRule ( ' tcp ' , SSHPort )
except BaseException as msg :
logging . InstallLog . writeToFile ( f ' [Error Custom SSH port] { str ( msg ) } ' )
preFlightsChecks . stdOut ( f ' [Error Custom SSH port] { str ( msg ) } ' )
logging . InstallLog . writeToFile ( " FirewallD installed and configured! " )
preFlightsChecks . stdOut ( " FirewallD installed and configured! " )
except OSError as msg :
logging . InstallLog . writeToFile ( ' [ERROR] ' + str ( msg ) + " [installFirewalld] " )
return 0
except ValueError as msg :
logging . InstallLog . writeToFile ( ' [ERROR] ' + str ( msg ) + " [installFirewalld] " )
return 0
return 1
## from here
def installLSCPD ( self ) :
try :
logging . InstallLog . writeToFile ( " Starting LSCPD installation.. " )
os . chdir ( self . cwd )
if self . distro == ubuntu :
self . install_package ( " gcc g++ make autoconf rcs " )
else :
self . install_package ( " gcc gcc-c++ make autoconf glibc " )
if self . distro == ubuntu :
self . install_package ( " libpcre3 libpcre3-dev openssl libexpat1 libexpat1-dev libgeoip-dev zlib1g zlib1g-dev libudns-dev whichman curl " )
else :
self . install_package ( " pcre-devel openssl-devel expat-devel geoip-devel zlib-devel udns-devel " )
command = ' tar zxf lscp.tar.gz -C /usr/local/ '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
###
lscpdPath = ' /usr/local/lscp/bin/lscpd '
# if subprocess.check_output('uname -a').decode("utf-8").find("aarch64") == -1:
# lscpdPath = '/usr/local/lscp/bin/lscpd'
#
# lscpdSelection = 'lscpd-0.3.1'
# if os.path.exists('/etc/lsb-release'):
# result = open('/etc/lsb-release', 'r').read()
2025-08-29 20:13:28 +05:00
# if result.find('22.04') > -1 or result.find('24.04') > -1:
2025-08-01 14:56:30 +05:00
# lscpdSelection = 'lscpd.0.4.0'
# else:
# lscpdSelection = 'lscpd.aarch64'
try :
try :
result = subprocess . run ( ' uname -a ' , capture_output = True , universal_newlines = True , shell = True )
except :
result = subprocess . run ( ' uname -a ' , stdout = subprocess . PIPE , stderr = subprocess . PIPE , universal_newlines = True , shell = True )
if result . stdout . find ( ' aarch64 ' ) == - 1 :
lscpdSelection = ' lscpd-0.3.1 '
if os . path . exists ( ' /etc/lsb-release ' ) :
result = open ( ' /etc/lsb-release ' , ' r ' ) . read ( )
2025-08-29 20:13:28 +05:00
if result . find ( ' 22.04 ' ) > - 1 or result . find ( ' 24.04 ' ) > - 1 :
2025-08-01 14:56:30 +05:00
lscpdSelection = ' lscpd.0.4.0 '
else :
lscpdSelection = ' lscpd.aarch64 '
except :
lscpdSelection = ' lscpd-0.3.1 '
if os . path . exists ( ' /etc/lsb-release ' ) :
result = open ( ' /etc/lsb-release ' , ' r ' ) . read ( )
2025-08-29 20:13:28 +05:00
if result . find ( ' 22.04 ' ) > - 1 or result . find ( ' 24.04 ' ) > - 1 :
2025-08-01 14:56:30 +05:00
lscpdSelection = ' lscpd.0.4.0 '
command = f ' cp -f /usr/local/CyberCP/ { lscpdSelection } /usr/local/lscp/bin/ { lscpdSelection } '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
command = ' rm -f /usr/local/lscp/bin/lscpd '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
command = f ' mv /usr/local/lscp/bin/ { lscpdSelection } /usr/local/lscp/bin/lscpd '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
command = ' chmod 755 %s ' % ( lscpdPath )
preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
##
command = ' openssl req -newkey rsa:1024 -new -nodes -x509 -days 3650 -subj " /C=US/ST=Denial/L=Springfield/O=Dis/CN=www.example.com " -keyout /usr/local/lscp/conf/key.pem -out /usr/local/lscp/conf/cert.pem '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-08-29 21:37:38 +05:00
# Create lsphp symlink for fcgi-bin with better error handling
self . setup_lsphp_symlink ( )
2025-08-01 14:56:30 +05:00
if self . is_centos_family ( ) :
command = ' adduser lscpd -M -d /usr/local/lscp '
else :
command = ' useradd lscpd -M -d /usr/local/lscp '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
if self . is_centos_family ( ) :
command = ' groupadd lscpd '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
# Added group in useradd for Ubuntu
command = ' usermod -a -G lscpd lscpd '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = ' usermod -a -G lsadm lscpd '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
try :
os . mkdir ( ' /usr/local/lscp/cyberpanel ' )
except :
pass
try :
os . mkdir ( ' /usr/local/lscp/cyberpanel/logs ' )
except :
pass
# self.setupComodoRules()
logging . InstallLog . writeToFile ( " LSCPD successfully installed! " )
except BaseException as msg :
logging . InstallLog . writeToFile ( ' [ERROR] ' + str ( msg ) + " [installLSCPD] " )
def setupComodoRules ( self ) :
try :
os . chdir ( self . cwd )
extractLocation = " /usr/local/lscp/modsec "
command = " mkdir -p /usr/local/lscp/modsec "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
try :
if os . path . exists ( ' comodo.tar.gz ' ) :
os . remove ( ' comodo.tar.gz ' )
except :
pass
command = " wget https://cyberpanel.net/modsec/comodo.tar.gz "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = " tar -zxf comodo.tar.gz -C /usr/local/lscp/modsec "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
###
modsecConfPath = " /usr/local/lscp/conf/modsec.conf "
modsecConfig = """
module mod_security {
ls_enabled 0
modsecurity on
modsecurity_rules `
SecDebugLogLevel 0
SecDebugLog / usr / local / lscp / logs / modsec . log
SecAuditEngine on
SecAuditLogRelevantStatus " ^(?:5|4(?!04)) "
SecAuditLogParts AFH
SecAuditLogType Serial
SecAuditLog / usr / local / lscp / logs / auditmodsec . log
SecRuleEngine Off
`
modsecurity_rules_file / usr / local / lscp / modsec / comodo / modsecurity . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 00 _Init_Initialization . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 01 _Init_AppsInitialization . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 02 _Global_Generic . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 03 _Global_Agents . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 04 _Global_Domains . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 05 _Global_Backdoor . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 06 _XSS_XSS . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 07 _Global_Other . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 08 _Bruteforce_Bruteforce . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 09 _HTTP_HTTP . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 10 _HTTP_HTTPDoS . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 11 _HTTP_Protocol . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 12 _HTTP_Request . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 13 _Outgoing_FilterGen . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 14 _Outgoing_FilterASP . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 15 _Outgoing_FilterPHP . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 16 _Outgoing_FilterSQL . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 17 _Outgoing_FilterOther . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 18 _Outgoing_FilterInFrame . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 19 _Outgoing_FiltersEnd . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 20 _PHP_PHPGen . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 21 _SQL_SQLi . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 22 _Apps_Joomla . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 23 _Apps_JComponent . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 24 _Apps_WordPress . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 25 _Apps_WPPlugin . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 26 _Apps_WHMCS . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 27 _Apps_Drupal . conf
modsecurity_rules_file / usr / local / lscp / modsec / comodo / 28 _Apps_OtherApps . conf
}
"""
writeToFile = open ( modsecConfPath , ' w ' )
writeToFile . write ( modsecConfig )
writeToFile . close ( )
###
command = " chown -R lscpd:lscpd /usr/local/lscp/modsec "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
return 1
except BaseException as msg :
logging . InstallLog . writeToFile ( " [ERROR] " + str ( msg ) )
return 0
def setupPort ( self ) :
try :
###
bindConfPath = " /usr/local/lscp/conf/bind.conf "
writeToFile = open ( bindConfPath , ' w ' )
writeToFile . write ( " *: " + self . port )
writeToFile . close ( )
except :
return 0
def setupPythonWSGI ( self ) :
try :
2025-09-23 19:06:33 +02:00
preFlightsChecks . stdOut ( " Setting up Python WSGI-LSAPI with optimized compilation... " , 1 )
2025-09-23 23:16:36 +02:00
# 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
2025-08-01 14:56:30 +05:00
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 )
command = " tar xf wsgi-lsapi-2.1.tgz "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
os . chdir ( " wsgi-lsapi-2.1 " )
2025-09-23 23:16:36 +02:00
command = f " { python_path } ./configure.py "
2025-08-01 14:56:30 +05:00
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-09-23 19:06:33 +02:00
# Fix Makefile to use proper optimization flags to avoid _FORTIFY_SOURCE warnings
self . _fixWSGIMakefile ( )
2025-08-01 14:56:30 +05:00
2025-09-23 19:06:33 +02:00
# Compile with proper optimization flags
command = " make clean "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-08-01 14:56:30 +05:00
command = " make "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
if not os . path . exists ( ' /usr/local/CyberCP/bin/ ' ) :
os . mkdir ( ' /usr/local/CyberCP/bin/ ' )
command = " cp lswsgi /usr/local/CyberCP/bin/ "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-09-23 19:06:33 +02:00
# Set proper permissions
command = " chmod +x /usr/local/CyberCP/bin/lswsgi "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-08-01 14:56:30 +05:00
os . chdir ( self . cwd )
2025-09-23 19:06:33 +02:00
preFlightsChecks . stdOut ( " WSGI-LSAPI compiled successfully with optimized flags " , 1 )
2025-08-01 14:56:30 +05:00
2025-09-23 19:06:33 +02:00
except Exception as e :
preFlightsChecks . stdOut ( f " WSGI setup error: { str ( e ) } " , 0 )
2025-08-01 14:56:30 +05:00
return 0
2025-09-23 23:16:36 +02:00
def ensureVirtualEnvironmentSetup ( self ) :
""" Ensure virtual environment is properly set up and accessible """
try :
2025-09-24 13:56:32 +02:00
# Check multiple possible virtual environment locations
venv_paths = [
' /usr/local/CyberCP/bin/python ' ,
' /usr/local/CyberPanel/bin/python ' ,
' /usr/local/CyberPanel-venv/bin/python '
]
found_venv = None
for path in venv_paths :
if os . path . exists ( path ) :
found_venv = path
preFlightsChecks . stdOut ( f " Virtual environment found at: { path } " , 1 )
break
if not found_venv :
preFlightsChecks . stdOut ( " No virtual environment found in expected locations " , 0 )
return False
# Create symlinks for compatibility if needed
if found_venv == ' /usr/local/CyberCP/bin/python ' :
2025-09-23 23:16:36 +02:00
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
2025-09-24 13:56:32 +02:00
# Test if Python is executable
try :
result = os . system ( f " { found_venv } --version > /dev/null 2>&1 " )
if result != 0 :
preFlightsChecks . stdOut ( f " Python at { found_venv } is not executable " , 0 )
return False
except Exception as e :
preFlightsChecks . stdOut ( f " Error testing Python executable: { str ( e ) } " , 0 )
2025-09-23 23:16:36 +02:00
return False
2025-09-24 13:56:32 +02:00
return True
2025-09-23 23:16:36 +02:00
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
2025-09-23 19:06:33 +02:00
def _fixWSGIMakefile ( self ) :
""" Fix the Makefile to use proper compiler optimization flags """
try :
makefile_path = " Makefile "
if not os . path . exists ( makefile_path ) :
preFlightsChecks . stdOut ( " Makefile not found, skipping optimization fix " , 1 )
return
# Read the Makefile
with open ( makefile_path , ' r ' ) as f :
content = f . read ( )
# Fix compiler flags to avoid _FORTIFY_SOURCE warnings
# Replace -O0 -g3 with -O2 -g to satisfy _FORTIFY_SOURCE
content = content . replace ( ' -O0 -g3 ' , ' -O2 -g ' )
# Ensure we have proper optimization flags
if ' CFLAGS ' in content and ' -O2 ' not in content :
content = content . replace ( ' CFLAGS = ' , ' CFLAGS = -O2 ' )
# Write the fixed Makefile
with open ( makefile_path , ' w ' ) as f :
f . write ( content )
preFlightsChecks . stdOut ( " Makefile optimized for proper compilation " , 1 )
except Exception as e :
preFlightsChecks . stdOut ( f " Warning: Could not optimize Makefile: { str ( e ) } " , 1 )
2025-08-01 14:56:30 +05:00
def setupLSCPDDaemon ( self ) :
try :
preFlightsChecks . stdOut ( " Trying to setup LSCPD Daemon! " )
logging . InstallLog . writeToFile ( " Trying to setup LSCPD Daemon! " )
os . chdir ( self . cwd )
shutil . copy ( " lscpd/lscpd.service " , " /etc/systemd/system/lscpd.service " )
shutil . copy ( " lscpd/lscpdctrl " , " /usr/local/lscp/bin/lscpdctrl " )
##
command = ' chmod +x /usr/local/lscp/bin/lscpdctrl '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
##
path = " /usr/local/lscpd/admin/ "
command = " mkdir -p " + path
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
path = " /usr/local/CyberCP/conf/ "
command = " mkdir -p " + path
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
path = " /usr/local/CyberCP/conf/token_env "
writeToFile = open ( path , " w " )
writeToFile . write ( " abc \n " )
writeToFile . close ( )
command = " chmod 600 " + path
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
##
self . manage_service ( ' lscpd ' , ' enable ' )
##
count = 0
# In Ubuntu, the library that lscpd looks for is libpcre.so.1, but the one it installs is libpcre.so.3...
if self . distro == ubuntu :
command = ' ln -s /lib/x86_64-linux-gnu/libpcre.so.3 /lib/x86_64-linux-gnu/libpcre.so.1 '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
##
command = ' systemctl start lscpd '
# preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
preFlightsChecks . stdOut ( " LSCPD Daemon Set! " )
logging . InstallLog . writeToFile ( " LSCPD Daemon Set! " )
except BaseException as msg :
logging . InstallLog . writeToFile ( ' [ERROR] ' + str ( msg ) + " [setupLSCPDDaemon] " )
return 0
return 1
def setup_cron ( self ) :
try :
## first install crontab
if self . is_centos_family ( ) :
self . install_package ( ' cronie ' )
else :
self . install_package ( ' cron ' )
if self . is_centos_family ( ) :
self . manage_service ( ' crond ' , ' enable ' )
self . manage_service ( ' crond ' , ' start ' )
else :
self . manage_service ( ' cron ' , ' enable ' )
self . manage_service ( ' cron ' , ' start ' )
##
CentOSPath = ' /etc/redhat-release '
openEulerPath = ' /etc/openEuler-release '
if os . path . exists ( CentOSPath ) or os . path . exists ( openEulerPath ) :
cronPath = ' /var/spool/cron/root '
else :
cronPath = ' /var/spool/cron/crontabs/root '
cronFile = open ( cronPath , " w " )
content = """
0 * * * * / usr / local / CyberCP / bin / python / usr / local / CyberCP / plogical / findBWUsage . py > / dev / null 2 > & 1
0 * * * * / usr / local / CyberCP / bin / python / usr / local / CyberCP / postfixSenderPolicy / client . py hourlyCleanup > / dev / null 2 > & 1
0 0 1 * * / usr / local / CyberCP / bin / python / usr / local / CyberCP / postfixSenderPolicy / client . py monthlyCleanup > / dev / null 2 > & 1
0 2 * * * / usr / local / CyberCP / bin / python / usr / local / CyberCP / plogical / upgradeCritical . py > / dev / null 2 > & 1
0 0 * * 4 / usr / local / CyberCP / bin / python / usr / local / CyberCP / plogical / renew . py > / dev / null 2 > & 1
7 0 * * * " /root/.acme.sh " / acme . sh - - cron - - home " /root/.acme.sh " > / dev / null
0 0 * * * / usr / local / CyberCP / bin / python / usr / local / CyberCP / IncBackups / IncScheduler . py Daily
0 0 * * 0 / usr / local / CyberCP / bin / python / usr / local / CyberCP / IncBackups / IncScheduler . py Weekly
* / 30 * * * * / usr / local / CyberCP / bin / python / usr / local / CyberCP / IncBackups / IncScheduler . py ' 30 Minutes '
0 * * * * / usr / local / CyberCP / bin / python / usr / local / CyberCP / IncBackups / IncScheduler . py ' 1 Hour '
0 * / 6 * * * / usr / local / CyberCP / bin / python / usr / local / CyberCP / IncBackups / IncScheduler . py ' 6 Hours '
0 * / 12 * * * / usr / local / CyberCP / bin / python / usr / local / CyberCP / IncBackups / IncScheduler . py ' 12 Hours '
0 1 * * * / usr / local / CyberCP / bin / python / usr / local / CyberCP / IncBackups / IncScheduler . py ' 1 Day '
0 0 * / 3 * * / usr / local / CyberCP / bin / python / usr / local / CyberCP / IncBackups / IncScheduler . py ' 3 Days '
0 0 * * 0 / usr / local / CyberCP / bin / python / usr / local / CyberCP / IncBackups / IncScheduler . py ' 1 Week '
* / 3 * * * * if ! find / home / * / public_html / - maxdepth 2 - type f - newer / usr / local / lsws / cgid - name ' .htaccess ' - exec false { } + ; then / usr / local / lsws / bin / lswsctrl restart ; fi
"""
cronFile . write ( content )
cronFile . close ( )
### Check and remove OLS restart if lsws ent detected
if not os . path . exists ( ' /usr/local/lsws/bin/openlitespeed ' ) :
data = open ( cronPath , ' r ' ) . readlines ( )
writeToFile = open ( cronPath , ' w ' )
for items in data :
if items . find ( ' -maxdepth 2 -type f -newer ' ) > - 1 :
pass
else :
writeToFile . writelines ( items )
writeToFile . close ( )
if not os . path . exists ( CentOSPath ) or not os . path . exists ( openEulerPath ) :
command = ' chmod 600 %s ' % ( cronPath )
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
if self . is_centos_family ( ) :
self . manage_service ( ' crond ' , ' restart ' )
else :
self . manage_service ( ' cron ' , ' restart ' )
except BaseException as msg :
logging . InstallLog . writeToFile ( ' [ERROR] ' + str ( msg ) + " [setup_cron] " )
return 0
def install_default_keys ( self ) :
try :
path = " /root/.ssh "
if not os . path . exists ( path ) :
os . mkdir ( path )
command = " ssh-keygen -f /root/.ssh/cyberpanel -t rsa -N ' ' "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
except BaseException as msg :
logging . InstallLog . writeToFile ( ' [ERROR] ' + str ( msg ) + " [install_default_keys] " )
return 0
def install_rsync ( self ) :
try :
self . install_package ( ' rsync ' )
except BaseException as msg :
logging . InstallLog . writeToFile ( ' [ERROR] ' + str ( msg ) + " [install_rsync] " )
return 0
def test_Requests ( self ) :
try :
import requests
getVersion = requests . get ( ' https://cyberpanel.net/version.txt ' )
latest = getVersion . json ( )
except BaseException as msg :
2025-08-29 20:44:19 +05:00
# Handle Ubuntu 24.04's externally-managed-environment policy
pip_flags = " "
if self . distro == ubuntu :
try :
release = install_utils . get_Ubuntu_release ( use_print = False , exit_on_error = False )
if release and release > = 24.04 :
pip_flags = " --break-system-packages "
except :
pass # If version detection fails, try without flags
command = f " pip uninstall --yes { pip_flags } urllib3 "
2025-08-01 14:56:30 +05:00
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-08-29 20:44:19 +05:00
command = f " pip uninstall --yes { pip_flags } requests "
2025-08-01 14:56:30 +05:00
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-08-29 20:44:19 +05:00
command = f " pip install { pip_flags } http://mirror.cyberpanel.net/urllib3-1.22.tar.gz "
2025-08-01 14:56:30 +05:00
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-08-29 20:44:19 +05:00
command = f " pip install { pip_flags } http://mirror.cyberpanel.net/requests-2.18.4.tar.gz "
2025-08-01 14:56:30 +05:00
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
def installation_successfull ( self ) :
print ( " ################################################################### " )
print ( " CyberPanel Successfully Installed " )
print ( " " )
print ( " " )
print ( " " )
2025-09-25 02:12:33 +02:00
print ( ( " Visit: https:// " + self . ipAddr + " :8090 " ) )
2025-08-01 14:56:30 +05:00
print ( " Username: admin " )
print ( " Password: 1234567 " )
print ( " ################################################################### " )
def modSecPreReqs ( self ) :
try :
pathToRemoveGarbageFile = os . path . join ( self . server_root_path , " modules/mod_security.so " )
os . remove ( pathToRemoveGarbageFile )
except OSError as msg :
logging . InstallLog . writeToFile ( ' [ERROR] ' + str ( msg ) + " [modSecPreReqs] " )
return 0
def installOpenDKIM ( self ) :
try :
2025-09-24 01:44:26 +02:00
# Install dependencies first
if self . distro == ubuntu :
deps = [ ' libmilter-dev ' , ' libmemcached-dev ' ]
for dep in deps :
try :
self . install_package ( dep )
except :
pass
2025-08-01 14:56:30 +05:00
self . install_package ( ' opendkim opendkim-tools ' )
else :
2025-09-24 01:44:26 +02:00
# Install dependencies for RHEL-based systems
2025-09-25 02:12:33 +02:00
deps = [ ' sendmail-milter ' , ' sendmail-milter-devel ' ]
2025-09-24 01:44:26 +02:00
for dep in deps :
try :
self . install_package ( dep , ' --skip-broken ' )
2025-09-25 02:49:14 +02:00
except :
pass
2025-09-25 02:12:33 +02:00
# Handle libmemcached with fallback for AlmaLinux 9
try :
self . install_package ( ' libmemcached libmemcached-devel ' , ' --skip-broken ' )
except :
# Fallback for AlmaLinux 9
try :
self . install_package ( ' memcached-devel ' , ' --skip-broken ' )
2025-09-24 01:44:26 +02:00
except :
2025-09-25 02:12:33 +02:00
self . stdOut ( " Warning: libmemcached packages not available, continuing... " , 1 )
2025-09-24 01:44:26 +02:00
if self . distro == cent8 or self . distro == openeuler :
self . install_package ( ' opendkim opendkim-tools ' , ' --skip-broken ' )
else :
self . install_package ( ' opendkim ' , ' --skip-broken ' )
2025-08-01 14:56:30 +05:00
command = ' mkdir -p /etc/opendkim/keys/ '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
except BaseException as msg :
logging . InstallLog . writeToFile ( ' [ERROR] ' + str ( msg ) + " [installOpenDKIM] " )
return 0
return 1
def configureOpenDKIM ( self ) :
try :
## Configure OpenDKIM specific settings
openDKIMConfigurePath = " /etc/opendkim.conf "
configData = """
Mode sv
Canonicalization relaxed / simple
KeyTable refile : / etc / opendkim / KeyTable
SigningTable refile : / etc / opendkim / SigningTable
ExternalIgnoreList refile : / etc / opendkim / TrustedHosts
InternalHosts refile : / etc / opendkim / TrustedHosts
"""
writeToFile = open ( openDKIMConfigurePath , ' a ' )
writeToFile . write ( configData )
writeToFile . close ( )
## Configure postfix specific settings
postfixFilePath = " /etc/postfix/main.cf "
configData = """
smtpd_milters = inet : 127.0 .0 .1 : 8891
non_smtpd_milters = $ smtpd_milters
milter_default_action = accept
"""
writeToFile = open ( postfixFilePath , ' a ' )
writeToFile . write ( configData )
writeToFile . close ( )
if self . distro == ubuntu or self . distro == cent8 :
data = open ( openDKIMConfigurePath , ' r ' ) . readlines ( )
writeToFile = open ( openDKIMConfigurePath , ' w ' )
for items in data :
if items . find ( ' Socket ' ) > - 1 and items . find ( ' local: ' ) :
writeToFile . writelines ( ' Socket inet:8891@localhost \n ' )
else :
writeToFile . writelines ( items )
writeToFile . close ( )
#### Restarting Postfix and OpenDKIM
self . manage_service ( ' opendkim ' , ' start ' )
self . manage_service ( ' opendkim ' , ' enable ' )
self . manage_service ( ' postfix ' , ' start ' )
except BaseException as msg :
logging . InstallLog . writeToFile ( ' [ERROR] ' + str ( msg ) + " [configureOpenDKIM] " )
return 0
return 1
def setupCLI ( self ) :
command = " ln -s /usr/local/CyberCP/cli/cyberPanel.py /usr/bin/cyberpanel "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = " chmod +x /usr/local/CyberCP/cli/cyberPanel.py "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
def setupPHPSymlink ( self ) :
try :
2025-09-24 11:28:20 +02:00
# Ensure LiteSpeed repository is available for PHP packages
if self . distro == centos or self . distro == cent8 or self . distro == openeuler :
# Check if LiteSpeed repository is available
command = ' dnf repolist | grep -q litespeed '
result = preFlightsChecks . call ( command , self . distro , command , command , 1 , 1 , os . EX_OSERR )
if result != 1 :
logging . InstallLog . writeToFile ( " [setupPHPSymlink] LiteSpeed repository not found, attempting to add it... " )
# Add LiteSpeed repository
2025-09-25 00:56:00 +02:00
# Use compatible repository version for RHEL-based systems
# AlmaLinux 9 is compatible with el8 repositories
2025-09-25 01:34:57 +02:00
os_info = self . detect_os_info ( )
2025-09-25 00:56:00 +02:00
if os_info [ ' name ' ] in [ ' almalinux ' , ' rocky ' , ' rhel ' ] and os_info [ ' major_version ' ] in [ ' 8 ' , ' 9 ' ] :
repo_command = ' rpm -Uvh http://rpms.litespeedtech.com/centos/litespeed-repo-1.1-1.el8.noarch.rpm '
else :
2025-09-25 02:49:14 +02:00
repo_command = ' rpm -Uvh http://rpms.litespeedtech.com/centos/litespeed-repo-1.1-1.el8.noarch.rpm '
2025-09-24 11:28:20 +02:00
preFlightsChecks . call ( repo_command , self . distro , repo_command , repo_command , 1 , 0 , os . EX_OSERR )
2025-09-07 22:57:53 +02:00
# Check if PHP 8.2 exists
if not os . path . exists ( ' /usr/local/lsws/lsphp82/bin/php ' ) :
logging . InstallLog . writeToFile ( " [setupPHPSymlink] PHP 8.2 not found, ensuring it ' s installed... " )
# Install PHP 8.2 based on OS
if self . distro == centos or self . distro == cent8 or self . distro == openeuler :
2025-09-24 11:28:20 +02:00
command = ' dnf install lsphp82 lsphp82-* -y --skip-broken --nobest '
2025-09-07 22:57:53 +02:00
else :
command = ' DEBIAN_FRONTEND=noninteractive apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y install lsphp82 lsphp82-* '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-08-07 06:58:48 +05:00
# Check if PHP 8.3 exists
if not os . path . exists ( ' /usr/local/lsws/lsphp83/bin/php ' ) :
logging . InstallLog . writeToFile ( " [setupPHPSymlink] PHP 8.3 not found, ensuring it ' s installed... " )
# Install PHP 8.3 based on OS
if self . distro == centos or self . distro == cent8 or self . distro == openeuler :
2025-09-24 11:28:20 +02:00
command = ' dnf install lsphp83 lsphp83-* -y --skip-broken --nobest '
2025-08-07 06:58:48 +05:00
else :
command = ' DEBIAN_FRONTEND=noninteractive apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y install lsphp83 lsphp83-* '
2025-09-24 11:28:20 +02:00
result = preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-08-07 06:58:48 +05:00
# Verify installation
if not os . path . exists ( ' /usr/local/lsws/lsphp83/bin/php ' ) :
2025-09-24 11:28:20 +02:00
logging . InstallLog . writeToFile ( ' [ERROR] Failed to install PHP 8.3, trying alternative method... ' )
# Try alternative installation method
alt_command = ' dnf install lsphp83 -y --skip-broken --nobest --allowerasing '
preFlightsChecks . call ( alt_command , self . distro , alt_command , alt_command , 1 , 0 , os . EX_OSERR )
if not os . path . exists ( ' /usr/local/lsws/lsphp83/bin/php ' ) :
logging . InstallLog . writeToFile ( ' [ERROR] Alternative PHP 8.3 installation also failed ' )
return 0
2025-09-07 22:57:53 +02:00
# Install PHP 8.4
if not os . path . exists ( ' /usr/local/lsws/lsphp84/bin/php ' ) :
logging . InstallLog . writeToFile ( " [setupPHPSymlink] PHP 8.4 not found, ensuring it ' s installed... " )
if self . distro == centos or self . distro == cent8 or self . distro == openeuler :
2025-09-24 11:28:20 +02:00
command = ' dnf install lsphp84 lsphp84-* -y --skip-broken --nobest '
2025-09-07 22:57:53 +02:00
else :
command = ' DEBIAN_FRONTEND=noninteractive apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y install lsphp84 lsphp84-* '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
# Install PHP 8.5
if not os . path . exists ( ' /usr/local/lsws/lsphp85/bin/php ' ) :
logging . InstallLog . writeToFile ( " [setupPHPSymlink] PHP 8.5 not found, ensuring it ' s installed... " )
if self . distro == centos or self . distro == cent8 or self . distro == openeuler :
2025-09-24 11:28:20 +02:00
command = ' dnf install lsphp85 lsphp85-* -y --skip-broken --nobest '
2025-09-07 22:57:53 +02:00
else :
command = ' DEBIAN_FRONTEND=noninteractive apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y install lsphp85 lsphp85-* '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
2025-08-07 06:58:48 +05:00
2025-08-01 14:56:30 +05:00
# Remove existing PHP symlink if it exists
if os . path . exists ( ' /usr/bin/php ' ) :
os . remove ( ' /usr/bin/php ' )
2025-09-24 11:28:20 +02:00
# Create symlink to the best available PHP version
# Try to find and use the best available PHP version
# Priority: 85 (beta), 84, 83, 82, 81, 80, 74 (newest to oldest)
php_versions = [ ' 85 ' , ' 84 ' , ' 83 ' , ' 82 ' , ' 81 ' , ' 80 ' , ' 74 ' ]
php_symlink_source = None
for php_ver in php_versions :
candidate_path = f " /usr/local/lsws/lsphp { php_ver } /bin/php "
if os . path . exists ( candidate_path ) :
php_symlink_source = candidate_path
logging . InstallLog . writeToFile ( f " [setupPHPSymlink] Found PHP { php_ver } binary: { candidate_path } " )
break
if php_symlink_source :
command = f ' ln -sf { php_symlink_source } /usr/bin/php '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
logging . InstallLog . writeToFile ( f " [setupPHPSymlink] PHP symlink updated to { php_symlink_source } successfully. " )
# Verify symlink works
verify_command = f ' { php_symlink_source } --version '
result = preFlightsChecks . call ( verify_command , self . distro , verify_command , verify_command , 1 , 1 , os . EX_OSERR )
if result == 1 :
logging . InstallLog . writeToFile ( " [setupPHPSymlink] PHP symlink verification successful " )
else :
logging . InstallLog . writeToFile ( " [WARNING] PHP symlink verification failed " )
else :
logging . InstallLog . writeToFile ( " [ERROR] No PHP versions found for symlink creation " )
# List available PHP versions for debugging
command = ' find /usr/local/lsws -name " lsphp* " -type d 2>/dev/null || true '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
return 0
2025-08-01 14:56:30 +05:00
except OSError as msg :
logging . InstallLog . writeToFile ( ' [ERROR] ' + str ( msg ) + " [setupPHPSymlink] " )
return 0
2025-08-29 21:37:38 +05:00
def setup_lsphp_symlink ( self ) :
""" Create lsphp symlink in fcgi-bin directory with robust error handling """
try :
fcgi_bin_dir = " /usr/local/lscp/fcgi-bin "
lsphp_target = os . path . join ( fcgi_bin_dir , " lsphp " )
# Ensure fcgi-bin directory exists
if not os . path . exists ( fcgi_bin_dir ) :
os . makedirs ( fcgi_bin_dir , exist_ok = True )
logging . InstallLog . writeToFile ( f " [setup_lsphp_symlink] Created fcgi-bin directory: { fcgi_bin_dir } " )
# Remove existing lsphp file/symlink if it exists
if os . path . exists ( lsphp_target ) or os . path . islink ( lsphp_target ) :
os . remove ( lsphp_target )
logging . InstallLog . writeToFile ( " [setup_lsphp_symlink] Removed existing lsphp file/symlink " )
# Try to find and use the best available PHP version
2025-09-24 01:11:23 +02:00
# Priority: 85 (beta), 84, 83, 82, 81, 80, 74 (newest to oldest)
php_versions = [ ' 85 ' , ' 84 ' , ' 83 ' , ' 82 ' , ' 81 ' , ' 80 ' , ' 74 ' ]
2025-08-29 21:37:38 +05:00
lsphp_source = None
for php_ver in php_versions :
candidate_path = f " /usr/local/lsws/lsphp { php_ver } /bin/lsphp "
if os . path . exists ( candidate_path ) :
lsphp_source = candidate_path
logging . InstallLog . writeToFile ( f " [setup_lsphp_symlink] Found lsphp binary: { candidate_path } " )
break
# If no lsphp binary found, try to find php binary as fallback
if not lsphp_source :
for php_ver in php_versions :
candidate_path = f " /usr/local/lsws/lsphp { php_ver } /bin/php "
if os . path . exists ( candidate_path ) :
lsphp_source = candidate_path
logging . InstallLog . writeToFile ( f " [setup_lsphp_symlink] Using php binary as fallback: { candidate_path } " )
break
# If still no source found, try admin_php as last resort
if not lsphp_source :
admin_php_path = " /usr/local/lscp/admin/fcgi-bin/admin_php "
if os . path . exists ( admin_php_path ) :
lsphp_source = admin_php_path
logging . InstallLog . writeToFile ( f " [setup_lsphp_symlink] Using admin_php as fallback: { admin_php_path } " )
admin_php5_path = " /usr/local/lscp/admin/fcgi-bin/admin_php5 "
if not lsphp_source and os . path . exists ( admin_php5_path ) :
lsphp_source = admin_php5_path
logging . InstallLog . writeToFile ( f " [setup_lsphp_symlink] Using admin_php5 as fallback: { admin_php5_path } " )
# Create the symlink/copy
if lsphp_source :
try :
# Try to create symlink first (preferred)
os . symlink ( lsphp_source , lsphp_target )
logging . InstallLog . writeToFile ( f " [setup_lsphp_symlink] Created symlink: { lsphp_target } -> { lsphp_source } " )
except OSError :
# If symlink fails (e.g., cross-filesystem), copy the file
shutil . copy2 ( lsphp_source , lsphp_target )
logging . InstallLog . writeToFile ( f " [setup_lsphp_symlink] Copied file: { lsphp_source } -> { lsphp_target } " )
# Set proper permissions
os . chmod ( lsphp_target , 0o755 )
logging . InstallLog . writeToFile ( " [setup_lsphp_symlink] Set permissions to 755 " )
# Verify the file was created successfully
if os . path . exists ( lsphp_target ) :
logging . InstallLog . writeToFile ( " [setup_lsphp_symlink] lsphp symlink creation successful " )
return True
else :
logging . InstallLog . writeToFile ( " [setup_lsphp_symlink] ERROR: lsphp file was not created " )
return False
else :
logging . InstallLog . writeToFile ( " [setup_lsphp_symlink] ERROR: No suitable PHP binary found " )
return False
except Exception as e :
logging . InstallLog . writeToFile ( f " [setup_lsphp_symlink] ERROR: { str ( e ) } " )
return False
2025-08-01 14:56:30 +05:00
def setupPHPAndComposer ( self ) :
try :
# First setup the PHP symlink
self . setupPHPSymlink ( )
if self . distro == ubuntu :
if not os . access ( ' /usr/local/lsws/lsphp70/bin/php ' , os . R_OK ) :
if os . access ( ' /usr/local/lsws/lsphp70/bin/php7.0 ' , os . R_OK ) :
os . symlink ( ' /usr/local/lsws/lsphp70/bin/php7.0 ' , ' /usr/local/lsws/lsphp70/bin/php ' )
if not os . access ( ' /usr/local/lsws/lsphp71/bin/php ' , os . R_OK ) :
if os . access ( ' /usr/local/lsws/lsphp71/bin/php7.1 ' , os . R_OK ) :
os . symlink ( ' /usr/local/lsws/lsphp71/bin/php7.1 ' , ' /usr/local/lsws/lsphp71/bin/php ' )
if not os . access ( ' /usr/local/lsws/lsphp72/bin/php ' , os . R_OK ) :
if os . access ( ' /usr/local/lsws/lsphp72/bin/php7.2 ' , os . R_OK ) :
os . symlink ( ' /usr/local/lsws/lsphp72/bin/php7.2 ' , ' /usr/local/lsws/lsphp72/bin/php ' )
#command = "cp /usr/local/lsws/lsphp71/bin/php /usr/bin/"
#preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
os . chdir ( self . cwd )
command = " chmod +x composer.sh "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = " ./composer.sh "
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
except OSError as msg :
logging . InstallLog . writeToFile ( ' [ERROR] ' + str ( msg ) + " [setupPHPAndComposer] " )
return 0
@staticmethod
def installOne ( package ) :
res = subprocess . call ( shlex . split ( ' DEBIAN_FRONTEND=noninteractive apt-get -y install ' + package ) )
if res != 0 :
preFlightsChecks . stdOut ( " Error # " + str ( res ) + ' installing: ' + package + ' . This may not be an issue ' \
' but may affect installation of something later ' ,
1 )
return res # Though probably not used
@staticmethod
def enableDisableDNS ( state ) :
try :
servicePath = ' /home/cyberpanel/powerdns '
if state == ' off ' :
2025-09-23 22:35:47 +02:00
pdns_service = preFlightsChecks . get_service_name ( ' pdns ' )
2025-09-18 12:30:22 +05:00
command = f ' sudo systemctl stop { pdns_service } '
2025-08-01 14:56:30 +05:00
subprocess . call ( shlex . split ( command ) )
2025-09-18 12:30:22 +05:00
command = f ' sudo systemctl disable { pdns_service } '
2025-08-01 14:56:30 +05:00
subprocess . call ( shlex . split ( command ) )
try :
os . remove ( servicePath )
except :
pass
else :
writeToFile = open ( servicePath , ' w+ ' )
writeToFile . close ( )
except OSError as msg :
logging . InstallLog . writeToFile ( ' [ERROR] ' + str ( msg ) + " [enableDisableDNS] " )
return 0
@staticmethod
def enableDisableEmail ( state ) :
try :
servicePath = ' /home/cyberpanel/postfix '
if state == ' off ' :
command = ' sudo systemctl stop postfix '
subprocess . call ( shlex . split ( command ) )
command = ' sudo systemctl disable postfix '
subprocess . call ( shlex . split ( command ) )
try :
os . remove ( servicePath )
except :
pass
else :
writeToFile = open ( servicePath , ' w+ ' )
writeToFile . close ( )
except OSError as msg :
logging . InstallLog . writeToFile ( ' [ERROR] ' + str ( msg ) + " [enableDisableEmail] " )
return 0
@staticmethod
def enableDisableFTP ( state , distro ) :
try :
servicePath = ' /home/cyberpanel/pureftpd '
if state == ' off ' :
command = ' sudo systemctl stop ' + preFlightsChecks . pureFTPDServiceName ( distro )
subprocess . call ( shlex . split ( command ) )
command = ' sudo systemctl disable ' + preFlightsChecks . pureFTPDServiceName ( distro )
subprocess . call ( shlex . split ( command ) )
try :
os . remove ( servicePath )
except :
pass
else :
writeToFile = open ( servicePath , ' w+ ' )
writeToFile . close ( )
except OSError as msg :
logging . InstallLog . writeToFile ( ' [ERROR] ' + str ( msg ) + " [enableDisableEmail] " )
return 0
@staticmethod
def fixSudoers ( ) :
try :
distroPath = ' /etc/lsb-release '
if not os . path . exists ( distroPath ) :
fileName = ' /etc/sudoers '
data = open ( fileName , ' r ' ) . readlines ( )
writeDataToFile = open ( fileName , ' w ' )
for line in data :
if line . find ( " root " ) > - 1 and line . find ( " ALL=(ALL) " ) > - 1 and line [ 0 ] != ' # ' :
writeDataToFile . writelines ( ' root ALL=(ALL:ALL) ALL \n ' )
else :
writeDataToFile . write ( line )
writeDataToFile . close ( )
except IOError as err :
pass
@staticmethod
def setUpFirstAccount ( ) :
try :
command = ' python /usr/local/CyberCP/plogical/adminPass.py --password 1234567 '
subprocess . call ( shlex . split ( command ) )
except :
pass
def installRestic ( self ) :
try :
CentOSPath = ' /etc/redhat-release '
openEulerPath = ' /etc/openEuler-release '
if os . path . exists ( CentOSPath ) or os . path . exists ( openEulerPath ) :
if self . distro == centos :
command = ' yum install -y yum-plugin-copr '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = ' yum copr enable -y copart/restic '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = ' yum install -y restic '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = ' restic self-update '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
else :
# Skip apt-get update as it was already done in cyberpanel.sh
# Just install the package directly
command = ' DEBIAN_FRONTEND=noninteractive apt-get install restic -y '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR , True )
command = ' restic self-update '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
except :
pass
def installCLScripts ( self ) :
try :
CentOSPath = ' /etc/redhat-release '
openEulerPath = ' /etc/openEuler-release '
if os . path . exists ( CentOSPath ) or os . path . exists ( openEulerPath ) :
command = ' mkdir -p /opt/cpvendor/etc/ '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
content = """ [integration_scripts]
panel_info = / usr / local / CyberCP / CLScript / panel_info . py
packages = / usr / local / CyberCP / CLScript / CloudLinuxPackages . py
users = / usr / local / CyberCP / CLScript / CloudLinuxUsers . py
domains = / usr / local / CyberCP / CLScript / CloudLinuxDomains . py
resellers = / usr / local / CyberCP / CLScript / CloudLinuxResellers . py
admins = / usr / local / CyberCP / CLScript / CloudLinuxAdmins . py
db_info = / usr / local / CyberCP / CLScript / CloudLinuxDB . py
[ lvemanager_config ]
ui_user_info = / usr / local / CyberCP / CLScript / UserInfo . py
base_path = / usr / local / lvemanager
run_service = 1
service_port = 9000
"""
writeToFile = open ( ' /opt/cpvendor/etc/integration.ini ' , ' w ' )
writeToFile . write ( content )
writeToFile . close ( )
command = ' mkdir -p /etc/cagefs/exclude '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
content = """ cyberpanel
docker
ftpuser
lscpd
opendkim
pdns
vmail
"""
writeToFile = open ( ' /etc/cagefs/exclude/cyberpanelexclude ' , ' w ' )
writeToFile . write ( content )
writeToFile . close ( )
except :
pass
def installAcme ( self ) :
command = ' wget -O - https://get.acme.sh | sh '
subprocess . call ( command , shell = True )
command = ' /root/.acme.sh/acme.sh --upgrade --auto-upgrade '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
def installRedis ( self ) :
if self . distro == ubuntu :
command = ' apt install redis-server -y '
elif self . distro == centos :
command = ' yum install redis -y '
else :
command = ' dnf install redis -y '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
## install redis conf
redisConf = ' /usr/local/lsws/conf/dvhost_redis.conf '
writeToFile = open ( redisConf , ' w ' )
writeToFile . write ( ' 127.0.0.1,6379,<auth_password> \n ' )
writeToFile . close ( )
##
os . chdir ( self . cwd )
confPath = ' /usr/local/lsws/conf/ '
if os . path . exists ( ' %s httpd.conf ' % ( confPath ) ) :
os . remove ( ' %s httpd.conf ' % ( confPath ) )
shutil . copy ( ' litespeed/httpd-redis.conf ' , ' %s httpd.conf ' % ( confPath ) )
## start and enable
command = ' systemctl start redis '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
command = ' systemctl enable redis '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
def disablePackegeUpdates ( self ) :
if self . distro == centos :
mainConfFile = ' /etc/yum.conf '
content = ' exclude=MariaDB-client MariaDB-common MariaDB-devel MariaDB-server MariaDB-shared ' \
' pdns pdns-backend-mysql dovecot dovecot-mysql postfix3 postfix3-ldap postfix3-mysql ' \
' postfix3-pcre restic opendkim libopendkim pure-ftpd ftp \n '
writeToFile = open ( mainConfFile , ' a ' )
writeToFile . write ( content )
writeToFile . close ( )
def installDNS_CyberPanelACMEFile ( self ) :
os . chdir ( self . cwd )
filePath = ' /root/.acme.sh/dns_cyberpanel.sh '
shutil . copy ( ' dns_cyberpanel.sh ' , filePath )
command = f ' chmod +x { filePath } '
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
def startDeferredServices ( self ) :
""" Start services that were deferred during installation (PowerDNS and Pure-FTPd)
These services require database tables that are created by Django migrations """
preFlightsChecks . stdOut ( " Starting deferred services that depend on database tables... " )
2025-09-23 22:35:47 +02:00
# Ensure database is ready first
self . ensureDatabaseReady ( )
2025-08-01 14:56:30 +05:00
# Start PowerDNS if it was installed
if os . path . exists ( ' /home/cyberpanel/powerdns ' ) :
2025-09-23 22:35:47 +02:00
self . fixAndStartPowerDNS ( )
# Start Pure-FTPd if it was installed
if os . path . exists ( ' /home/cyberpanel/pureftpd ' ) :
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 " )
2025-09-23 23:16:36 +02:00
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
2025-09-29 12:18:03 +05:00
sql_commands = [
( " CREATE DATABASE IF NOT EXISTS powerdns " , " PowerDNS database creation " ) ,
( " CREATE USER IF NOT EXISTS ' powerdns ' @ ' localhost ' IDENTIFIED BY ' cyberpanel ' " , " PowerDNS user creation " ) ,
( " GRANT ALL PRIVILEGES ON powerdns.* TO ' powerdns ' @ ' localhost ' " , " PowerDNS privileges " ) ,
( " FLUSH PRIVILEGES " , " PowerDNS privilege flush " )
2025-09-23 23:16:36 +02:00
]
2025-09-29 12:18:03 +05:00
for sql_cmd , desc in sql_commands :
if not self . execute_mysql_command ( sql_cmd , desc ) :
self . stdOut ( f " Warning: { desc } may have failed " , 0 )
2025-09-23 23:16:36 +02:00
# Import PowerDNS schema if tables don't exist
2025-09-29 12:18:03 +05:00
schema_check_success = self . execute_mysql_command ( " USE powerdns; SHOW TABLES " , " PowerDNS schema check " )
# For now, assume schema needs import if we can't check properly
if not schema_check_success :
2025-09-23 23:16:36 +02:00
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 )
2025-09-23 22:35:47 +02:00
def fixAndStartPowerDNS ( self ) :
""" Fix PowerDNS configuration and start the service """
preFlightsChecks . stdOut ( " Fixing and starting PowerDNS service... " )
2025-09-25 02:12:33 +02:00
# Check if PowerDNS is enabled first
if not os . path . exists ( ' /home/cyberpanel/powerdns ' ) :
preFlightsChecks . stdOut ( " PowerDNS not enabled, skipping... " , 1 )
return
2025-09-23 22:35:47 +02:00
# Determine correct service name
pdns_service = None
2025-09-25 02:12:33 +02:00
try :
result = subprocess . run ( [ ' systemctl ' , ' list-unit-files ' ] , capture_output = True , text = True , timeout = 10 )
if ' pdns.service ' in result . stdout :
pdns_service = ' pdns '
elif ' powerdns.service ' in result . stdout :
pdns_service = ' powerdns '
except :
preFlightsChecks . stdOut ( " Could not check systemctl services " , 1 )
2025-09-23 22:35:47 +02:00
if not pdns_service :
2025-09-25 02:12:33 +02:00
preFlightsChecks . stdOut ( " [WARNING] PowerDNS service not found, attempting to install... " , 1 )
# Try to install PowerDNS
try :
if self . distro in [ centos , cent8 , openeuler ] :
preFlightsChecks . call ( ' dnf install -y pdns pdns-backend-mysql ' , self . distro , ' Install PowerDNS ' , ' Install PowerDNS ' , 1 , 0 , os . EX_OSERR )
else :
preFlightsChecks . call ( ' apt-get install -y pdns-server pdns-backend-mysql ' , self . distro , ' Install PowerDNS ' , ' Install PowerDNS ' , 1 , 0 , os . EX_OSERR )
pdns_service = ' pdns '
except :
preFlightsChecks . stdOut ( " [WARNING] Could not install PowerDNS, skipping... " , 1 )
return
2025-09-23 22:35:47 +02:00
# 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 } " )
2025-09-23 23:16:36 +02:00
# Read existing content
try :
with open ( config_file , ' r ' ) as f :
content = f . read ( )
except :
content = " "
2025-09-23 22:35:47 +02:00
# Add missing configuration if not present
2025-09-23 23:16:36 +02:00
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 ' )
2025-09-23 22:35:47 +02:00
# Ensure proper permissions
os . chmod ( config_file , 0o644 )
break
2025-09-23 23:16:36 +02:00
# Ensure PowerDNS can connect to database
self . ensurePowerDNSDatabaseAccess ( )
2025-09-23 22:35:47 +02:00
2025-09-23 23:16:36 +02:00
# 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 )
2025-09-23 22:35:47 +02:00
2025-09-23 23:16:36 +02:00
# 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
2025-09-24 00:36:38 +02:00
command = f ' systemctl is-active { pdns_service } '
try :
2025-09-23 23:16:36 +02:00
result = subprocess . run ( command , shell = True , capture_output = True , text = True , timeout = 10 )
output = result . stdout . strip ( )
2025-09-24 00:36:38 +02:00
if output == ' active ' :
2025-09-23 23:16:36 +02:00
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 )
2025-09-24 00:36:38 +02:00
else :
2025-09-23 23:16:36 +02:00
preFlightsChecks . stdOut ( " PowerDNS service running but status check failed " , 0 )
2025-09-24 00:36:38 +02:00
except :
2025-09-23 23:16:36 +02:00
preFlightsChecks . stdOut ( " PowerDNS service running but status verification failed " , 0 )
break
2025-09-23 22:35:47 +02:00
else :
2025-09-23 23:16:36 +02:00
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 )
2025-09-23 22:35:47 +02:00
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
2025-09-23 23:16:36 +02:00
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... " )
2025-09-24 00:36:38 +02:00
command = f " sed -i ' s/MYSQLCrypt md5/MYSQLCrypt crypt/g ' { config_file } "
2025-09-23 23:16:36 +02:00
preFlightsChecks . call ( command , self . distro , command , command , 1 , 0 , os . EX_OSERR )
except :
2025-09-24 00:36:38 +02:00
pass
2025-09-23 22:35:47 +02:00
2025-09-23 23:16:36 +02:00
# 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 )
2025-09-23 22:35:47 +02:00
2025-09-23 23:16:36 +02:00
# Start service
command = f ' systemctl start { ftp_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
2025-09-23 22:35:47 +02:00
command = f ' systemctl is-active { ftp_service } '
try :
2025-09-23 23:16:36 +02:00
result = subprocess . run ( command , shell = True , capture_output = True , text = True , timeout = 10 )
output = result . stdout . strip ( )
2025-09-23 22:35:47 +02:00
if output == ' active ' :
2025-09-23 23:16:36 +02:00
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
2025-09-23 22:35:47 +02:00
else :
2025-09-23 23:16:36 +02:00
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 )
2025-09-23 22:35:47 +02:00
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 } '
2025-08-01 14:56:30 +05:00
try :
output = subprocess . check_output ( shlex . split ( command ) ) . decode ( " utf-8 " ) . strip ( )
if output == ' active ' :
2025-09-23 22:35:47 +02:00
preFlightsChecks . stdOut ( f " { service } is running successfully! " )
2025-08-01 14:56:30 +05:00
else :
2025-09-23 22:35:47 +02:00
preFlightsChecks . stdOut ( f " [WARNING] { service } status: { output } " )
2025-08-01 14:56:30 +05:00
except :
2025-09-23 22:35:47 +02:00
preFlightsChecks . stdOut ( f " [WARNING] Could not verify { service } status " )
def fixLiteSpeedPermissions ( self ) :
""" Fix LiteSpeed directory permissions """
preFlightsChecks . stdOut ( " Fixing LiteSpeed permissions... " )
2025-08-01 14:56:30 +05:00
2025-09-23 22:35:47 +02:00
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 )
2025-08-29 22:30:06 +05:00
2025-09-23 22:35:47 +02:00
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 } '
2025-08-01 14:56:30 +05:00
try :
output = subprocess . check_output ( shlex . split ( command ) ) . decode ( " utf-8 " ) . strip ( )
if output == ' active ' :
2025-09-23 22:35:47 +02:00
preFlightsChecks . stdOut ( f " ✓ { service } is running " )
2025-08-01 14:56:30 +05:00
else :
2025-09-23 22:35:47 +02:00
preFlightsChecks . stdOut ( f " ✗ { service } is not running (status: { output } ) " )
all_services_ok = False
2025-08-01 14:56:30 +05:00
except :
2025-09-23 22:35:47 +02:00
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 " )
2025-08-01 14:56:30 +05:00
def configure_jwt_secret ( ) :
try :
import secrets
secret = secrets . token_urlsafe ( 32 )
fastapi_file = ' /usr/local/CyberCP/fastapi_ssh_server.py '
with open ( fastapi_file , ' r ' ) as f :
lines = f . readlines ( )
with open ( fastapi_file , ' w ' ) as f :
for line in lines :
if line . strip ( ) . startswith ( ' JWT_SECRET ' ) :
f . write ( f ' JWT_SECRET = " { secret } " \n ' )
else :
f . write ( line )
print ( f " Configured JWT_SECRET in fastapi_ssh_server.py " )
except :
pass
def main ( ) :
parser = argparse . ArgumentParser ( description = ' CyberPanel Installer ' )
parser . add_argument ( ' publicip ' , help = ' Please enter public IP for your VPS or dedicated server. ' )
parser . add_argument ( ' --mysql ' , help = ' Specify number of MySQL instances to be used. ' )
parser . add_argument ( ' --postfix ' , help = ' Enable or disable Email Service. ' )
parser . add_argument ( ' --powerdns ' , help = ' Enable or disable DNS Service. ' )
parser . add_argument ( ' --ftp ' , help = ' Enable or disable ftp Service. ' )
parser . add_argument ( ' --ent ' , help = ' Install LS Ent or OpenLiteSpeed ' )
parser . add_argument ( ' --serial ' , help = ' Install LS Ent or OpenLiteSpeed ' )
parser . add_argument ( ' --port ' , help = ' LSCPD Port ' )
parser . add_argument ( ' --redis ' , help = ' vHosts on Redis - Requires LiteSpeed Enterprise ' )
parser . add_argument ( ' --remotemysql ' , help = ' Opt to choose local or remote MySQL ' )
parser . add_argument ( ' --mysqlhost ' , help = ' MySQL host if remote is chosen. ' )
parser . add_argument ( ' --mysqldb ' , help = ' MySQL DB if remote is chosen. ' )
parser . add_argument ( ' --mysqluser ' , help = ' MySQL user if remote is chosen. ' )
parser . add_argument ( ' --mysqlpassword ' , help = ' MySQL password if remote is chosen. ' )
parser . add_argument ( ' --mysqlport ' , help = ' MySQL port if remote is chosen. ' )
args = parser . parse_args ( )
logging . InstallLog . ServerIP = args . publicip
logging . InstallLog . writeToFile ( " Starting CyberPanel installation..,10 " )
preFlightsChecks . stdOut ( " Starting CyberPanel installation.. " )
2025-09-24 18:20:59 +02:00
# Initialize serial variable
serial = None
2025-09-25 02:12:33 +02:00
2025-08-01 14:56:30 +05:00
if args . ent is None :
ent = 0
preFlightsChecks . stdOut ( " OpenLiteSpeed web server will be installed. " )
else :
if args . ent == ' ols ' :
ent = 0
preFlightsChecks . stdOut ( " OpenLiteSpeed web server will be installed. " )
else :
preFlightsChecks . stdOut ( " LiteSpeed Enterprise web server will be installed. " )
ent = 1
if args . serial is not None :
serial = args . serial
preFlightsChecks . stdOut ( " LiteSpeed Enterprise Serial detected: " + serial )
else :
preFlightsChecks . stdOut ( " Installation failed, please specify LiteSpeed Enterprise key using --serial " )
os . _exit ( 0 )
## Writing public IP
try :
os . mkdir ( " /etc/cyberpanel " )
except :
pass
machineIP = open ( " /etc/cyberpanel/machineIP " , " w " )
machineIP . writelines ( args . publicip )
machineIP . close ( )
cwd = os . getcwd ( )
if args . remotemysql == ' ON ' :
remotemysql = args . remotemysql
mysqlhost = args . mysqlhost
mysqluser = args . mysqluser
mysqlpassword = args . mysqlpassword
mysqlport = args . mysqlport
mysqldb = args . mysqldb
if preFlightsChecks . debug :
print ( ' mysqlhost: %s , mysqldb: %s , mysqluser: %s , mysqlpassword: %s , mysqlport: %s ' % (
mysqlhost , mysqldb , mysqluser , mysqlpassword , mysqlport ) )
time . sleep ( 10 )
else :
remotemysql = args . remotemysql
mysqlhost = ' '
mysqluser = ' '
mysqlpassword = ' '
mysqlport = ' '
mysqldb = ' '
distro = get_distro ( )
checks = preFlightsChecks ( " /usr/local/lsws/ " , args . publicip , " /usr/local " , cwd , " /usr/local/CyberCP " , distro ,
remotemysql , mysqlhost , mysqldb , mysqluser , mysqlpassword , mysqlport )
2025-09-24 17:29:33 +02:00
# Apply OS-specific fixes early in the installation process
checks . apply_os_specific_fixes ( )
2025-09-25 00:56:00 +02:00
# Ensure MySQL password file is created early to prevent FileNotFoundError
checks . ensure_mysql_password_file ( )
2025-08-01 14:56:30 +05:00
checks . mountTemp ( )
checks . installQuota ( )
if args . port is None :
port = " 8090 "
else :
port = args . port
if args . mysql is None :
mysql = ' One '
preFlightsChecks . stdOut ( " Single MySQL instance version will be installed. " )
else :
mysql = args . mysql
preFlightsChecks . stdOut ( " Dobule MySQL instance version will be installed. " )
checks . checkPythonVersion ( )
checks . setup_account_cyberpanel ( )
checks . installCyberPanelRepo ( )
2025-09-24 17:29:33 +02:00
# Note: OS-specific fixes are now applied earlier in the installation process
# The installCyberPanel.Main() functionality has been integrated into the main installation flow
2025-08-01 14:56:30 +05:00
2025-09-24 20:51:46 +02:00
# Apply AlmaLinux 9 comprehensive fixes first if needed
if checks . is_almalinux9 ( ) :
checks . fix_almalinux9_comprehensive ( )
2025-09-24 17:29:33 +02:00
# Install core services in the correct order
checks . installLiteSpeed ( ent , serial )
checks . installMySQL ( mysql )
2025-09-27 11:41:16 +05:00
# Create cyberpanel database and user immediately after MySQL installation
logging . InstallLog . writeToFile ( " Creating cyberpanel database and user... " )
preFlightsChecks . stdOut ( " Creating cyberpanel database and user... " , 1 )
try :
2025-09-28 02:50:33 +05:00
import mysqlUtilities
import install_utils
2025-09-27 11:41:16 +05:00
# Generate cyberpanel database password using the same logic as download_install_CyberPanel
if checks . distro == centos :
# On CentOS, generate a separate password for cyberpanel database
checks . cyberpanel_db_password = install_utils . generate_pass ( )
else :
# On Ubuntu/Debian, the cyberpanel password is the same as root password
checks . cyberpanel_db_password = checks . mysql_Root_password
# Create cyberpanel database and user (restored from v2.4.4 installCyberPanel.py)
2025-09-28 02:00:25 +05:00
logging . InstallLog . writeToFile ( f " Attempting to create cyberpanel database with password length: { len ( checks . cyberpanel_db_password ) } " )
2025-09-27 11:41:16 +05:00
result = mysqlUtilities . mysqlUtilities . createDatabase ( " cyberpanel " , " cyberpanel " , checks . cyberpanel_db_password , " localhost " )
if result == 1 :
2025-09-28 02:00:25 +05:00
logging . InstallLog . writeToFile ( " ✅ Cyberpanel database and user created successfully! " )
2025-09-27 11:41:16 +05:00
preFlightsChecks . stdOut ( " Cyberpanel database and user created successfully! " , 1 )
2025-09-28 02:00:25 +05:00
# Verify the user was created by testing the connection
try :
2025-09-29 12:18:03 +05:00
test_success = False
# Try mariadb first, then mysql
for cmd_base in [ ' mariadb ' , ' mysql ' ] :
if checks . command_exists ( cmd_base ) :
test_cmd = f " { cmd_base } -u cyberpanel -p { checks . cyberpanel_db_password } -e ' SELECT 1; ' "
test_result = subprocess . call ( test_cmd , shell = True , stdout = subprocess . DEVNULL , stderr = subprocess . DEVNULL )
if test_result == 0 :
logging . InstallLog . writeToFile ( " ✅ Verified: cyberpanel user can connect to MySQL " )
test_success = True
break
if not test_success :
logging . InstallLog . writeToFile ( " ⚠️ Warning: Could not verify cyberpanel user connection " )
2025-09-28 02:00:25 +05:00
except Exception as verify_error :
logging . InstallLog . writeToFile ( f " Could not verify MySQL connection: { str ( verify_error ) } " )
2025-09-27 11:41:16 +05:00
else :
2025-09-28 02:00:25 +05:00
error_msg = f " ❌ CRITICAL ERROR: Cyberpanel database creation failed (returned { result } ) "
logging . InstallLog . writeToFile ( error_msg )
preFlightsChecks . stdOut ( " Database creation failed - installation cannot continue " , 1 )
# Don't continue with settings.py update if database creation failed
raise Exception ( " Database creation failed - cyberpanel user does not exist " )
2025-09-27 11:41:16 +05:00
except Exception as e :
logging . InstallLog . writeToFile ( f " Error creating cyberpanel database: { str ( e ) } " )
preFlightsChecks . stdOut ( f " Error: Database creation failed: { str ( e ) } " , 1 )
2025-09-24 17:29:33 +02:00
checks . installPowerDNS ( )
checks . installPureFTPD ( )
2025-08-01 14:56:30 +05:00
2025-09-24 20:51:46 +02:00
# Setup PHP and Composer (dependencies already installed by comprehensive fix)
2025-08-01 14:56:30 +05:00
checks . setupPHPAndComposer ( )
checks . fix_selinux_issue ( )
checks . install_psmisc ( )
checks . fixSudoers ( )
if args . postfix is None :
checks . install_postfix_dovecot ( )
2025-09-24 20:23:49 +02:00
# Ensure cyberpanel_db_password is set before calling setup_email_Passwords
if not hasattr ( checks , ' cyberpanel_db_password ' ) or checks . cyberpanel_db_password is None :
checks . cyberpanel_db_password = checks . mysql_Root_password
2025-09-24 17:29:33 +02:00
checks . setup_email_Passwords ( checks . cyberpanel_db_password , mysql )
2025-08-01 14:56:30 +05:00
checks . setup_postfix_dovecot_config ( mysql )
else :
if args . postfix == ' ON ' :
checks . install_postfix_dovecot ( )
2025-09-24 20:23:49 +02:00
# Ensure cyberpanel_db_password is set before calling setup_email_Passwords
if not hasattr ( checks , ' cyberpanel_db_password ' ) or checks . cyberpanel_db_password is None :
checks . cyberpanel_db_password = checks . mysql_Root_password
2025-09-24 17:29:33 +02:00
checks . setup_email_Passwords ( checks . cyberpanel_db_password , mysql )
2025-08-01 14:56:30 +05:00
checks . setup_postfix_dovecot_config ( mysql )
checks . install_unzip ( )
checks . install_zip ( )
checks . install_rsync ( )
checks . installFirewalld ( )
checks . install_default_keys ( )
2025-09-25 22:45:35 +02:00
checks . download_install_CyberPanel ( checks . mysqlpassword , mysql )
2025-08-01 14:56:30 +05:00
checks . downoad_and_install_raindloop ( )
checks . download_install_phpmyadmin ( )
checks . setupCLI ( )
checks . setup_cron ( )
checks . installRestic ( )
checks . installAcme ( )
2025-09-24 01:44:26 +02:00
# Fix Django AutoField warnings
2025-09-24 11:08:22 +02:00
fix_django_autofield_warnings ( )
2025-08-01 14:56:30 +05:00
## Install and Configure OpenDKIM.
if args . postfix is None :
checks . installOpenDKIM ( )
checks . configureOpenDKIM ( )
else :
if args . postfix == ' ON ' :
checks . installOpenDKIM ( )
checks . configureOpenDKIM ( )
checks . modSecPreReqs ( )
checks . installLSCPD ( )
checks . setupPort ( )
checks . setupPythonWSGI ( )
checks . setupLSCPDDaemon ( )
checks . installDNS_CyberPanelACMEFile ( )
if args . redis is not None :
checks . installRedis ( )
if args . postfix is not None :
checks . enableDisableEmail ( args . postfix . lower ( ) )
else :
preFlightsChecks . stdOut ( " Postfix will be installed and enabled. " )
checks . enableDisableEmail ( ' on ' )
if args . powerdns is not None :
checks . enableDisableDNS ( args . powerdns . lower ( ) )
else :
preFlightsChecks . stdOut ( " PowerDNS will be installed and enabled. " )
checks . enableDisableDNS ( ' on ' )
if args . ftp is not None :
checks . enableDisableFTP ( args . ftp . lower ( ) , distro )
else :
preFlightsChecks . stdOut ( " Pure-FTPD will be installed and enabled. " )
checks . enableDisableFTP ( ' on ' , distro )
checks . installCLScripts ( )
# checks.disablePackegeUpdates()
try :
# command = 'mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/data/default/configs/'
# subprocess.call(shlex.split(command))
writeToFile = open ( ' /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/configs/application.ini ' , ' a ' )
writeToFile . write ( """
[ security ]
admin_login = " admin "
admin_password = " 12345 "
""" )
writeToFile . close ( )
2025-09-24 00:36:38 +02:00
content = r """ <?php
2025-08-01 14:56:30 +05:00
$ _ENV [ ' snappymail_INCLUDE_AS_API ' ] = true ;
include ' /usr/local/CyberCP/public/snappymail/index.php ' ;
$ oConfig = \snappymail \Api : : Config ( ) ;
$ oConfig - > SetPassword ( ' %s ' ) ;
echo $ oConfig - > Save ( ) ? ' Done ' : ' Error ' ;
? > """ % (generate_pass())
writeToFile = open ( ' /usr/local/CyberCP/public/snappymail.php ' , ' w ' )
writeToFile . write ( content )
writeToFile . close ( )
2025-09-15 01:25:52 +02:00
command = ' /usr/local/lsws/lsphp83/bin/php /usr/local/CyberCP/public/snappymail.php '
2025-08-01 14:56:30 +05:00
subprocess . call ( shlex . split ( command ) )
command = " chown -R lscpd:lscpd /usr/local/lscp/cyberpanel/snappymail/data "
subprocess . call ( shlex . split ( command ) )
2025-08-31 13:16:22 +05:00
# Ensure all data directories have group write permissions
command = " chmod -R 775 /usr/local/lscp/cyberpanel/snappymail/data "
subprocess . call ( shlex . split ( command ) )
# Ensure web server users are in the lscpd group
command = " usermod -a -G lscpd nobody 2>/dev/null || true "
subprocess . call ( shlex . split ( command ) )
2025-08-31 19:55:56 +05:00
# Fix SnappyMail public directory ownership (critical fix)
2025-09-24 01:44:26 +02:00
command = " chown -R lscpd:lscpd /usr/local/CyberCP/public/snappymail/data || true "
2025-08-31 13:16:22 +05:00
subprocess . call ( shlex . split ( command ) )
2025-08-01 14:56:30 +05:00
except :
pass
checks . fixCyberPanelPermissions ( )
configure_jwt_secret ( )
# Start services that were enabled but not started during installation
# These services require database tables that are created by Django migrations
checks . startDeferredServices ( )
2025-09-24 00:45:34 +02:00
# Installation summary
show_installation_summary ( )
2025-08-01 14:56:30 +05:00
logging . InstallLog . writeToFile ( " CyberPanel installation successfully completed!,80 " )
2025-09-24 00:45:34 +02:00
def show_installation_summary ( ) :
""" Display comprehensive installation summary """
try :
import time
import subprocess
print ( " \n " + " = " * 80 )
print ( " 📊 CYBERPANEL INSTALLATION SUMMARY " )
print ( " = " * 80 )
# Check component status
components = {
" CyberPanel Core " : check_service_status ( " lscpd " ) ,
2025-09-24 01:45:55 +02:00
" OpenLiteSpeed " : check_openlitespeed_status ( ) ,
2025-09-24 00:45:34 +02:00
" MariaDB/MySQL " : check_service_status ( " mysql " ) or check_service_status ( " mariadb " ) ,
2025-09-24 01:45:55 +02:00
" PowerDNS " : check_powerdns_status ( ) ,
" Pure-FTPd " : check_pureftpd_status ( ) ,
2025-09-24 00:45:34 +02:00
" Postfix " : check_service_status ( " postfix " ) ,
" Dovecot " : check_service_status ( " dovecot " ) ,
2025-09-24 01:45:55 +02:00
" LSMCD " : check_service_status ( " lsmcd " ) ,
2025-09-24 00:45:34 +02:00
" SnappyMail " : check_file_exists ( " /usr/local/CyberCP/public/snappymail " ) ,
" phpMyAdmin " : check_file_exists ( " /usr/local/CyberCP/public/phpmyadmin " )
}
print ( " \n 🔧 COMPONENT STATUS: " )
print ( " - " * 50 )
for component , status in components . items ( ) :
if status :
print ( f " ✅ { component : <20 } - INSTALLED & RUNNING " )
else :
print ( f " ❌ { component : <20 } - NOT AVAILABLE " )
# System information
try :
memory_info = subprocess . check_output ( " free -m " , shell = True ) . decode ( )
memory_line = [ line for line in memory_info . split ( ' \n ' ) if ' Mem: ' in line ] [ 0 ]
memory_parts = memory_line . split ( )
total_mem = memory_parts [ 1 ]
used_mem = memory_parts [ 2 ]
mem_percent = ( int ( used_mem ) / int ( total_mem ) ) * 100
disk_info = subprocess . check_output ( " df -h / " , shell = True ) . decode ( )
disk_line = [ line for line in disk_info . split ( ' \n ' ) if ' /dev/ ' in line ] [ 0 ]
disk_parts = disk_line . split ( )
disk_usage = disk_parts [ 4 ]
print ( f " \n 📈 SYSTEM RESOURCES: " )
print ( f " • Memory Usage: { used_mem } MB / { total_mem } MB ( { mem_percent : .1f } %) " )
print ( f " • Disk Usage: { disk_usage } " )
print ( f " • CPU Cores: { subprocess . check_output ( ' nproc ' , shell = True ) . decode ( ) . strip ( ) } " )
except Exception as e :
print ( f " \n 📈 SYSTEM RESOURCES: Unable to retrieve ( { str ( e ) } ) " )
# Installation time
try :
if hasattr ( show_installation_summary , ' start_time ' ) :
elapsed = time . time ( ) - show_installation_summary . start_time
minutes = int ( elapsed / / 60 )
seconds = int ( elapsed % 60 )
print ( f " • Install Time: { minutes } m { seconds } s " )
except :
pass
print ( " \n " + " = " * 80 )
except Exception as e :
print ( f " \n ⚠️ Could not generate installation summary: { str ( e ) } " )
def check_service_status ( service_name ) :
""" Check if a service is running """
try :
result = subprocess . run ( [ ' systemctl ' , ' is-active ' , service_name ] ,
capture_output = True , text = True )
return result . returncode == 0
except :
return False
2025-09-24 01:45:55 +02:00
def check_openlitespeed_status ( ) :
""" Check if OpenLiteSpeed is running (special case) """
try :
# Check if lsws process is running
result = subprocess . run ( [ ' pgrep ' , ' -f ' , ' litespeed ' ] , capture_output = True , text = True )
if result . returncode == 0 :
return True
# Check if lsws service is active
result = subprocess . run ( [ ' systemctl ' , ' is-active ' , ' lsws ' ] , capture_output = True , text = True )
if result . returncode == 0 :
return True
# Check if openlitespeed service is active
result = subprocess . run ( [ ' systemctl ' , ' is-active ' , ' openlitespeed ' ] , capture_output = True , text = True )
if result . returncode == 0 :
return True
return False
except :
return False
def check_powerdns_status ( ) :
""" Check if PowerDNS is running (special case) """
try :
# Check if pdns process is running
result = subprocess . run ( [ ' pgrep ' , ' -f ' , ' pdns ' ] , capture_output = True , text = True )
if result . returncode == 0 :
return True
# Check various PowerDNS service names
for service in [ ' pdns ' , ' pdns-server ' , ' powerdns ' ] :
result = subprocess . run ( [ ' systemctl ' , ' is-active ' , service ] , capture_output = True , text = True )
if result . returncode == 0 :
return True
return False
except :
return False
def check_pureftpd_status ( ) :
""" Check if Pure-FTPd is running (special case) """
try :
# Check if pure-ftpd process is running
result = subprocess . run ( [ ' pgrep ' , ' -f ' , ' pure-ftpd ' ] , capture_output = True , text = True )
if result . returncode == 0 :
return True
# Check various Pure-FTPd service names
for service in [ ' pure-ftpd ' , ' pureftpd ' ] :
result = subprocess . run ( [ ' systemctl ' , ' is-active ' , service ] , capture_output = True , text = True )
if result . returncode == 0 :
return True
return False
except :
return False
2025-09-24 01:44:26 +02:00
def fix_django_autofield_warnings ( ) :
""" Fix Django AutoField warnings by setting DEFAULT_AUTO_FIELD """
try :
settings_file = ' /usr/local/CyberCP/cyberpanel/settings.py '
if os . path . exists ( settings_file ) :
with open ( settings_file , ' r ' ) as f :
content = f . read ( )
# Add DEFAULT_AUTO_FIELD setting if not present
if ' DEFAULT_AUTO_FIELD ' not in content :
with open ( settings_file , ' a ' ) as f :
f . write ( ' \n # Fix Django AutoField warnings \n ' )
f . write ( ' DEFAULT_AUTO_FIELD = " django.db.models.BigAutoField " \n ' )
logging . InstallLog . writeToFile ( " [fix_django_autofield_warnings] Added DEFAULT_AUTO_FIELD setting " )
except Exception as e :
logging . InstallLog . writeToFile ( f " [ERROR] { str ( e ) } [fix_django_autofield_warnings] " )
2025-09-24 00:45:34 +02:00
def check_file_exists ( file_path ) :
""" Check if a file or directory exists """
try :
return os . path . exists ( file_path )
except :
return False
# Set installation start time
import time
2025-09-25 02:12:33 +02:00
installation_start_time = time . time ( )
2025-09-24 00:45:34 +02:00
2025-08-01 14:56:30 +05:00
if __name__ == " __main__ " :
main ( )