Update PHP version references and improve AlmaLinux 9 compatibility

- Changed PHP symlink from version 8.0 to 8.3 in various scripts to ensure compatibility with the latest PHP version.
- Updated documentation links in the FAQ to point to the new community support page.
- Added checks and fixes for MariaDB installation issues specific to AlmaLinux 9.
- Enhanced the installation script to support additional PHP versions and improve overall installation reliability.
This commit is contained in:
Master3395
2025-09-15 01:25:52 +02:00
parent 1fbbf66481
commit 1a82700f51
14 changed files with 374 additions and 8640 deletions

View File

@@ -39,9 +39,9 @@ CyberPanel supports a wide range of PHP versions across different operating syst
### ☑️ **Currently Supported PHP Versions**
- **PHP 8.5** - Latest stable version (EOL: Dec 2028)
- **PHP 8.5** - Latest stable version (EOL: Dec 2028)**NEW!**
- **PHP 8.4** - Stable version (EOL: Dec 2027)
- **PHP 8.3** - Stable version (EOL: Dec 2027)
- **PHP 8.3** - **Default version** - Stable version (EOL: Dec 2027) 🎯
- **PHP 8.2** - Stable version (EOL: Dec 2026)
- **PHP 8.1** - Stable version (EOL: Dec 2025)
- **PHP 8.0** - Legacy support (EOL: Nov 2023)

View File

@@ -2278,7 +2278,7 @@ echo "echo \$@ > /etc/cyberpanel/adminPass" >> /usr/bin/adminPass
chmod 700 /usr/bin/adminPass
rm -f /usr/bin/php
ln -s /usr/local/lsws/lsphp80/bin/php /usr/bin/php
ln -s /usr/local/lsws/lsphp83/bin/php /usr/bin/php
if [[ "$Server_OS" = "CentOS" ]] ; then
#all centos 7/8 post change goes here

14
faq.sh
View File

@@ -28,7 +28,7 @@ ${BLUE}------------------------------------------------------------${NC}
${PURPLE}3.${NC} How to access LiteSpeed webadmin console ?
Please check this post: ${GREEN}https://forums.cyberpanel.net/discussion/87/tutorial-how-to-setup-and-login-to-openlitespeed-webadmin-console/p1${NC}
Please check this post: ${GREEN}https://community.cyberpanel.net/c/support/55${NC}
${BLUE}------------------------------------------------------------${NC}
@@ -52,9 +52,9 @@ ${BLUE}------------------------------------------------------------${NC}
${PURPLE}6.${NC} How to raise upload limit for cyberpanel's phpMyAdmin and File Manager?
edit file ${RED}/usr/local/lsws/lsphp73/etc/php.ini${NC} for CentOS or openEuler
edit file ${RED}/usr/local/lsws/lsphp83/etc/php.ini${NC} for CentOS or openEuler
${RED}/usr/local/lsws/lsphp73/etc/php/7.3/litespeed/php.ini${NC} for Ubbuntu
${RED}/usr/local/lsws/lsphp83/etc/php/8.3/litespeed/php.ini${NC} for Ubuntu
find 2 configurations:
@@ -66,9 +66,9 @@ ${BLUE}------------------------------------------------------------${NC}
${PURPLE}7.${NC} How to add more IPs to my website(s) ?
For OpenLiteSpeed, please check this post: ${GREEN}https://forums.cyberpanel.net/discussion/126/tutorial-how-to-add-2nd-ip-for-websites/p1${NC}
For OpenLiteSpeed, please check this post: ${GREEN}https://community.cyberpanel.net/c/support/55${NC}
For LiteSpeed Enterprise, please check this post: ${GREEN}https://forums.cyberpanel.net/discussion/3745/tutorial-how-to-add-2nd-ip-for-litespeed-enterprise/p1${NC}
For LiteSpeed Enterprise, please check this post: ${GREEN}https://community.cyberpanel.net/c/support/55${NC}
${BLUE}------------------------------------------------------------${NC}
@@ -80,7 +80,7 @@ ${BLUE}------------------------------------------------------------${NC}
${PURPLE}9.${NC} How to enable Auto-Index for my site ?
Please check this post ${GREEN}https://forums.cyberpanel.net/discussion/3850/tutorial-how-to-enable-auto-index-on-openlitespeed-and-litespeed-enterprise${NC}
Please check this post ${GREEN}https://community.cyberpanel.net/c/support/55${NC}
${BLUE}------------------------------------------------------------${NC}
@@ -111,5 +111,5 @@ ${BLUE}------------------------------------------------------------${NC}
${PURPLE}13.${NC} How to enable PHP error log ?
Please check this post ${GREEN}https://forums.cyberpanel.net/discussion/3977/tutorial-how-to-enable-php-error-log/p1${NC}
Please check this post ${GREEN}https://community.cyberpanel.net/c/support/55${NC}
"

View File

@@ -1,190 +0,0 @@
import os
import shutil
import pathlib
import stat
def mkdir_p(path, exist_ok=True):
"""
Creates the directory and paths leading up to it like unix mkdir -p .
Defaults to exist_ok so if it exists were not throwing fatal errors
https://docs.python.org/3.7/library/os.html#os.makedirs
"""
if not os.path.exists(path):
print('creating directory: ' + path)
os.makedirs(path, exist_ok)
def chmod_digit(file_path, perms):
"""
Helper function to chmod like you would in unix without having to preface 0o or converting to octal yourself.
Credits: https://stackoverflow.com/a/60052847/1621381
"""
try:
os.chmod(file_path, int(str(perms), base=8))
except:
print(f'Could not chmod : {file_path} to {perms}')
pass
def touch(filepath: str, exist_ok=True):
"""
Touches a file like unix `touch somefile` would.
"""
try:
pathlib.Path(filepath).touch(exist_ok)
except FileExistsError:
print('Could touch : ' + filepath)
pass
def symlink(src, dst):
"""
Symlink a path to another if the src exists.
"""
try:
if os.access(src, os.R_OK):
os.symlink(src, dst)
except:
print(f'Could not symlink Source: {src} > Destination: {dst}')
pass
def chown(path, user, group=-1):
"""
Chown file/path to user/group provided. Passing -1 to user or group will leave it unchanged.
Useful if just changing user or group vs both.
"""
try:
shutil.chown(path, user, group)
except PermissionError:
print(f'Could not change permissions for: {path} to {user}:{group}')
pass
def recursive_chown(path, owner, group=-1):
"""
Recursively chown a path and contents to owner.
https://docs.python.org/3/library/shutil.html
"""
for dirpath, dirnames, filenames in os.walk(path):
try:
shutil.chown(dirpath, owner, group)
except PermissionError:
print('Could not change permissions for: ' + dirpath + ' to: ' + owner)
pass
for filename in filenames:
try:
shutil.chown(os.path.join(dirpath, filename), owner, group)
except PermissionError:
print('Could not change permissions for: ' + os.path.join(dirpath, filename) + ' to: ' + owner)
pass
def recursive_permissions(path, dir_mode=755, file_mode=644, topdir=True):
"""
Recursively chmod a path and contents to mode.
Defaults to chmod top level directory but can be optionally
toggled off when you want to chmod only contents of like a user's homedir vs homedir itself
https://docs.python.org/3.6/library/os.html#os.walk
"""
# Here we are converting the integers to string and then to octal.
# so this function doesn't need to be called with 0o prefixed for the file and dir mode
dir_mode = int(str(dir_mode), base=8)
file_mode = int(str(file_mode), base=8)
if topdir:
# Set chmod on top level path
try:
os.chmod(path, dir_mode)
except:
print('Could not chmod :' + path + ' to ' + str(dir_mode))
for root, dirs, files in os.walk(path):
for d in dirs:
try:
os.chmod(os.path.join(root, d), dir_mode)
except:
print('Could not chmod :' + os.path.join(root, d) + ' to ' + str(dir_mode))
pass
for f in files:
try:
os.chmod(os.path.join(root, f), file_mode)
except:
print('Could not chmod :' + path + ' to ' + str(file_mode))
pass
# Left intentionally here for reference.
# Set recursive chown for a path
# recursive_chown(my_path, 'root', 'root')
# for changing group recursively without affecting user
# recursive_chown('/usr/local/lscp/cyberpanel/rainloop/data', -1, 'lscpd')
# explicitly set permissions for directories/folders to 0755 and files to 0644
# recursive_permissions(my_path, 755, 644)
# Fix permissions and use default values
# recursive_permissions(my_path)
# =========================================================
# Below is a helper class for getting and working with permissions
# Original credits to : https://github.com/keysemble/perfm
def perm_octal_digit(rwx):
digit = 0
if rwx[0] == 'r':
digit += 4
if rwx[1] == 'w':
digit += 2
if rwx[2] == 'x':
digit += 1
return digit
class FilePerm:
def __init__(self, filepath):
filemode = stat.filemode(os.stat(filepath).st_mode)
permissions = [filemode[-9:][i:i + 3] for i in range(0, len(filemode[-9:]), 3)]
self.filepath = filepath
self.access_dict = dict(zip(['user', 'group', 'other'], [list(perm) for perm in permissions]))
def mode(self):
mode = 0
for shift, digit in enumerate(self.octal()[::-1]):
mode += digit << (shift * 3)
return mode
def digits(self):
"""Get the octal chmod equivalent value 755 in single string"""
return "".join(map(str, self.octal()))
def octal(self):
"""Get the octal value in a list [7, 5, 5]"""
return [perm_octal_digit(p) for p in self.access_dict.values()]
def access_bits(self, access):
if access in self.access_dict.keys():
r, w, x = self.access_dict[access]
return [r == 'r', w == 'w', x == 'x']
def update_bitwise(self, settings):
def perm_list(read=False, write=False, execute=False):
pl = ['-', '-', '-']
if read:
pl[0] = 'r'
if write:
pl[1] = 'w'
if execute:
pl[2] = 'x'
return pl
self.access_dict = dict(
[(access, perm_list(read=r, write=w, execute=x)) for access, [r, w, x] in settings.items()])
os.chmod(self.filepath, self.mode())
# project_directory = os.path.abspath(os.path.dirname(sys.argv[0]))
# home_directory = os.path.expanduser('~')
# print(f'Path: {home_directory} Mode: {FilePerm(home_directory).mode()} Octal: {FilePerm(home_directory).octal()} '
# f'Digits: {FilePerm(home_directory).digits()}')
# Example: Output
# Path: /home/cooluser Mode: 493 Octal: [7, 5, 5] Digits: 755

View File

@@ -2969,7 +2969,7 @@ echo $oConfig->Save() ? 'Done' : 'Error';
writeToFile.write(content)
writeToFile.close()
command = '/usr/local/lsws/lsphp72/bin/php /usr/local/CyberCP/public/snappymail.php'
command = '/usr/local/lsws/lsphp83/bin/php /usr/local/CyberCP/public/snappymail.php'
subprocess.call(shlex.split(command))
command = "chown -R lscpd:lscpd /usr/local/lscp/cyberpanel/snappymail/data"

File diff suppressed because it is too large Load Diff

View File

@@ -44,6 +44,62 @@ FetchCloudLinuxAlmaVersionVersion = install_utils.FetchCloudLinuxAlmaVersionVers
class InstallCyberPanel:
mysql_Root_password = ""
mysqlPassword = ""
def is_almalinux9(self):
"""Check if running on AlmaLinux 9"""
if os.path.exists('/etc/almalinux-release'):
try:
with open('/etc/almalinux-release', 'r') as f:
content = f.read()
return 'release 9' in content
except:
return False
return False
def fix_almalinux9_mariadb(self):
"""Fix AlmaLinux 9 MariaDB installation issues"""
if not self.is_almalinux9():
return
self.stdOut("Applying AlmaLinux 9 MariaDB fixes...", 1)
try:
# Disable problematic MariaDB MaxScale repository
self.stdOut("Disabling problematic MariaDB MaxScale repository...", 1)
command = "dnf config-manager --disable mariadb-maxscale 2>/dev/null || true"
install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
# Remove problematic repository files
self.stdOut("Removing problematic repository files...", 1)
problematic_repos = [
'/etc/yum.repos.d/mariadb-maxscale.repo',
'/etc/yum.repos.d/mariadb-maxscale.repo.rpmnew'
]
for repo_file in problematic_repos:
if os.path.exists(repo_file):
os.remove(repo_file)
self.stdOut(f"Removed {repo_file}", 1)
# Clean DNF cache
self.stdOut("Cleaning DNF cache...", 1)
command = "dnf clean all"
install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
# Install MariaDB from official repository
self.stdOut("Setting up official MariaDB repository...", 1)
command = "curl -sS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | bash -s -- --mariadb-server-version='10.11'"
install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
# Install MariaDB packages
self.stdOut("Installing MariaDB packages...", 1)
mariadb_packages = "MariaDB-server MariaDB-client MariaDB-backup MariaDB-devel"
command = f"dnf install -y {mariadb_packages}"
install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
self.stdOut("AlmaLinux 9 MariaDB fixes completed", 1)
except Exception as e:
self.stdOut(f"Error applying AlmaLinux 9 MariaDB fixes: {str(e)}", 0)
CloudLinux8 = 0
def install_package(self, package_name, options=""):
@@ -335,7 +391,7 @@ class InstallCyberPanel:
return self.reStartLiteSpeed()
def installAllPHPVersions(self):
php_versions = ['71', '72', '73', '74', '80', '81', '82', '83']
php_versions = ['71', '72', '73', '74', '80', '81', '82', '83', '84', '85']
if self.distro == ubuntu:
# Install base PHP 7.x packages
@@ -563,6 +619,12 @@ gpgcheck=1
if self.remotemysql == 'OFF':
############## Start mariadb ######################
# Check if AlmaLinux 9 and apply fixes
if self.is_almalinux9():
self.stdOut("AlmaLinux 9 detected - applying MariaDB fixes", 1)
self.fix_almalinux9_mariadb()
self.manage_service('mariadb', 'start')
############## Enable mariadb at system startup ######################

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,121 +0,0 @@
{% extends "baseTemplate/index.html" %}
{% load i18n %}
{% block title %}{% trans "Mail Functions - CyberPanel" %}{% endblock %}
{% block content %}
{% load static %}
{% get_current_language as LANGUAGE_CODE %}
<!-- Current language: {{ LANGUAGE_CODE }} -->
<div class="container">
<div id="page-title">
<h2>{% trans "Mail Functions" %}</h2>
<p>{% trans "Manage email accounts on this page." %}</p>
</div>
<div class="panel col-md-12">
<div class="panel-body">
<h3 class="content-box-header">
{% trans "Available Functions" %}
</h3>
<div class="example-box-wrapper">
<div class="row">
<div class="col-md-3 btn-min-width">
<a href="{% url 'createEmailAccount' %}" title="{% trans 'Create Email' %}"
class="tile-box tile-box-shortcut btn-primary">
<div class="tile-header">
{% trans "Create Email" %}
</div>
<div class="tile-content-wrapper">
<i class="fa fa-plus-square"></i>
</div>
</a>
</div>
<div class="col-md-3 btn-min-width">
<a href="{% url 'listEmails' %}" title="{% trans 'List Emails' %}"
class="tile-box tile-box-shortcut btn-primary">
<div class="tile-header">
{% trans "List Emails" %}
</div>
<div class="tile-content-wrapper">
<i class="fa fa-plus-square"></i>
</div>
</a>
</div>
<div class="col-md-3 btn-min-width">
<a href="{% url 'deleteEmailAccount' %}" title="{% trans 'Delete Email' %}"
class="tile-box tile-box-shortcut btn-primary">
<div class="tile-header">
{% trans "Delete Email" %}
</div>
<div class="tile-content-wrapper">
<i class="fa fa-trash"></i>
</div>
</a>
</div>
<div class="col-md-3 btn-min-width">
<a href="{% url 'emailForwarding' %}" title="{% trans 'Email Forwarding' %}"
class="tile-box tile-box-shortcut btn-primary">
<div class="tile-header">
{% trans "Email Forwarding" %}
</div>
<div class="tile-content-wrapper">
<i class="fa fa-plus-square"></i>
</div>
</a>
</div>
<div class="col-md-3 btn-min-width">
<a href="{% url 'changeEmailAccountPassword' %}" title="{% trans 'Change Password' %}"
class="tile-box tile-box-shortcut btn-primary">
<div class="tile-header">
{% trans "Change Password" %}
</div>
<div class="tile-content-wrapper">
<i class="fa fa-key"></i>
</div>
</a>
</div>
<div class="col-md-3 btn-min-width">
<a href="{% url 'dkimManager' %}" title="{% trans 'DKIM Manager' %}"
class="tile-box tile-box-shortcut btn-primary">
<div class="tile-header">
{% trans "DKIM Manager" %}
</div>
<div class="tile-content-wrapper">
<i class="fa fa-key"></i>
</div>
</a>
</div>
<div class="col-md-3 btn-min-width">
<a href="/snappymail/index.php" title="{% trans 'Access Webmail' %}"
class="tile-box tile-box-shortcut btn-primary">
<div class="tile-header">
{% trans "Access Webmail" %}
</div>
<div class="tile-content-wrapper">
<i class="fa fa-key"></i>
</div>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -1372,7 +1372,7 @@ echo $oConfig->Save() ? 'Done' : 'Error';
command = 'chmod 640 /usr/local/lscp/cyberpanel/logs/access.log'
ProcessUtilities.executioner(command, 'root', True)
command = '/usr/local/lsws/lsphp72/bin/php /usr/local/CyberCP/public/snappymail.php'
command = '/usr/local/lsws/lsphp83/bin/php /usr/local/CyberCP/public/snappymail.php'
ProcessUtilities.executioner(command, 'root', True)
command = 'chmod 600 /usr/local/CyberCP/public/snappymail.php'

View File

@@ -1,190 +0,0 @@
import os
import shutil
import pathlib
import stat
def mkdir_p(path, exist_ok=True):
"""
Creates the directory and paths leading up to it like unix mkdir -p .
Defaults to exist_ok so if it exists were not throwing fatal errors
https://docs.python.org/3.7/library/os.html#os.makedirs
"""
if not os.path.exists(path):
print('creating directory: ' + path)
os.makedirs(path, exist_ok)
def chmod_digit(file_path, perms):
"""
Helper function to chmod like you would in unix without having to preface 0o or converting to octal yourself.
Credits: https://stackoverflow.com/a/60052847/1621381
"""
try:
os.chmod(file_path, int(str(perms), base=8))
except:
print(f'Could not chmod : {file_path} to {perms}')
pass
def touch(filepath: str, exist_ok=True):
"""
Touches a file like unix `touch somefile` would.
"""
try:
pathlib.Path(filepath).touch(exist_ok)
except FileExistsError:
print('Could touch : ' + filepath)
pass
def symlink(src, dst):
"""
Symlink a path to another if the src exists.
"""
try:
if os.access(src, os.R_OK):
os.symlink(src, dst)
except:
print(f'Could not symlink Source: {src} > Destination: {dst}')
pass
def chown(path, user, group=-1):
"""
Chown file/path to user/group provided. Passing -1 to user or group will leave it unchanged.
Useful if just changing user or group vs both.
"""
try:
shutil.chown(path, user, group)
except PermissionError:
print(f'Could not change permissions for: {path} to {user}:{group}')
pass
def recursive_chown(path, owner, group=-1):
"""
Recursively chown a path and contents to owner.
https://docs.python.org/3/library/shutil.html
"""
for dirpath, dirnames, filenames in os.walk(path):
try:
shutil.chown(dirpath, owner, group)
except PermissionError:
print('Could not change permissions for: ' + dirpath + ' to: ' + owner)
pass
for filename in filenames:
try:
shutil.chown(os.path.join(dirpath, filename), owner, group)
except PermissionError:
print('Could not change permissions for: ' + os.path.join(dirpath, filename) + ' to: ' + owner)
pass
def recursive_permissions(path, dir_mode=755, file_mode=644, topdir=True):
"""
Recursively chmod a path and contents to mode.
Defaults to chmod top level directory but can be optionally
toggled off when you want to chmod only contents of like a user's homedir vs homedir itself
https://docs.python.org/3.6/library/os.html#os.walk
"""
# Here we are converting the integers to string and then to octal.
# so this function doesn't need to be called with 0o prefixed for the file and dir mode
dir_mode = int(str(dir_mode), base=8)
file_mode = int(str(file_mode), base=8)
if topdir:
# Set chmod on top level path
try:
os.chmod(path, dir_mode)
except:
print('Could not chmod :' + path + ' to ' + str(dir_mode))
for root, dirs, files in os.walk(path):
for d in dirs:
try:
os.chmod(os.path.join(root, d), dir_mode)
except:
print('Could not chmod :' + os.path.join(root, d) + ' to ' + str(dir_mode))
pass
for f in files:
try:
os.chmod(os.path.join(root, f), file_mode)
except:
print('Could not chmod :' + path + ' to ' + str(file_mode))
pass
# Left intentionally here for reference.
# Set recursive chown for a path
# recursive_chown(my_path, 'root', 'root')
# for changing group recursively without affecting user
# recursive_chown('/usr/local/lscp/cyberpanel/rainloop/data', -1, 'lscpd')
# explicitly set permissions for directories/folders to 0755 and files to 0644
# recursive_permissions(my_path, 755, 644)
# Fix permissions and use default values
# recursive_permissions(my_path)
# =========================================================
# Below is a helper class for getting and working with permissions
# Original credits to : https://github.com/keysemble/perfm
def perm_octal_digit(rwx):
digit = 0
if rwx[0] == 'r':
digit += 4
if rwx[1] == 'w':
digit += 2
if rwx[2] == 'x':
digit += 1
return digit
class FilePerm:
def __init__(self, filepath):
filemode = stat.filemode(os.stat(filepath).st_mode)
permissions = [filemode[-9:][i:i + 3] for i in range(0, len(filemode[-9:]), 3)]
self.filepath = filepath
self.access_dict = dict(zip(['user', 'group', 'other'], [list(perm) for perm in permissions]))
def mode(self):
mode = 0
for shift, digit in enumerate(self.octal()[::-1]):
mode += digit << (shift * 3)
return mode
def digits(self):
"""Get the octal chmod equivalent value 755 in single string"""
return "".join(map(str, self.octal()))
def octal(self):
"""Get the octal value in a list [7, 5, 5]"""
return [perm_octal_digit(p) for p in self.access_dict.values()]
def access_bits(self, access):
if access in self.access_dict.keys():
r, w, x = self.access_dict[access]
return [r == 'r', w == 'w', x == 'x']
def update_bitwise(self, settings):
def perm_list(read=False, write=False, execute=False):
pl = ['-', '-', '-']
if read:
pl[0] = 'r'
if write:
pl[1] = 'w'
if execute:
pl[2] = 'x'
return pl
self.access_dict = dict(
[(access, perm_list(read=r, write=w, execute=x)) for access, [r, w, x] in settings.items()])
os.chmod(self.filepath, self.mode())
# project_directory = os.path.abspath(os.path.dirname(sys.argv[0]))
# home_directory = os.path.expanduser('~')
# print(f'Path: {home_directory} Mode: {FilePerm(home_directory).mode()} Octal: {FilePerm(home_directory).octal()} '
# f'Digits: {FilePerm(home_directory).digits()}')
# Example: Output
# Path: /home/cooluser Mode: 493 Octal: [7, 5, 5] Digits: 755

View File

@@ -861,7 +861,7 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout';
command = f'wget -q -O /usr/local/CyberCP/snappymail_cyberpanel.php https://raw.githubusercontent.com/the-djmaze/snappymail/master/integrations/cyberpanel/install.php'
Upgrade.executioner_silent(command, 'verify certificate', 0)
command = f'/usr/local/lsws/lsphp80/bin/php /usr/local/CyberCP/snappymail_cyberpanel.php'
command = f'/usr/local/lsws/lsphp83/bin/php /usr/local/CyberCP/snappymail_cyberpanel.php'
Upgrade.executioner_silent(command, 'verify certificate', 0)
# labsPath = '/usr/local/lscp/cyberpanel/rainloop/data/_data_/_default_/configs/application.ini'
@@ -3121,7 +3121,7 @@ echo $oConfig->Save() ? 'Done' : 'Error';
command = 'chmod 640 /usr/local/lscp/cyberpanel/logs/access.log'
Upgrade.executioner(command, 0)
command = '/usr/local/lsws/lsphp72/bin/php /usr/local/CyberCP/public/snappymail.php'
command = '/usr/local/lsws/lsphp83/bin/php /usr/local/CyberCP/public/snappymail.php'
Upgrade.executioner_silent(command, 'Configure SnappyMail')
command = 'chmod 600 /usr/local/CyberCP/public/snappymail.php'
@@ -3182,44 +3182,221 @@ echo $oConfig->Save() ? 'Done' : 'Error';
command = '/root/.acme.sh/acme.sh --set-default-ca --server letsencrypt'
Upgrade.executioner(command, command, 0)
@staticmethod
def check_package_availability(package_name):
"""Check if a package is available in the repositories"""
try:
# Try to search for the package without installing
if os.path.exists('/etc/yum.repos.d/') or os.path.exists('/etc/dnf/dnf.conf'):
# RHEL-based systems
command = f"dnf search --quiet {package_name} 2>/dev/null | grep -q '^Last metadata expiration' || yum search --quiet {package_name} 2>/dev/null | head -1"
result = subprocess.run(command, shell=True, capture_output=True, text=True)
return result.returncode == 0
else:
# Ubuntu/Debian systems
command = f"apt-cache search {package_name} 2>/dev/null | head -1"
result = subprocess.run(command, shell=True, capture_output=True, text=True)
return result.returncode == 0 and result.stdout.strip() != ""
except Exception as e:
Upgrade.stdOut(f"Error checking package availability for {package_name}: {str(e)}", 0)
return False
@staticmethod
def is_almalinux9():
"""Check if running on AlmaLinux 9"""
if os.path.exists('/etc/almalinux-release'):
try:
with open('/etc/almalinux-release', 'r') as f:
content = f.read()
return 'release 9' in content
except:
return False
return False
@staticmethod
def fix_almalinux9_mariadb():
"""Fix AlmaLinux 9 MariaDB installation issues"""
if not Upgrade.is_almalinux9():
return
Upgrade.stdOut("Applying AlmaLinux 9 MariaDB fixes...", 1)
try:
# Disable problematic MariaDB MaxScale repository
Upgrade.stdOut("Disabling problematic MariaDB MaxScale repository...", 1)
command = "dnf config-manager --disable mariadb-maxscale 2>/dev/null || true"
subprocess.run(command, shell=True, capture_output=True)
# Remove problematic repository files
Upgrade.stdOut("Removing problematic repository files...", 1)
problematic_repos = [
'/etc/yum.repos.d/mariadb-maxscale.repo',
'/etc/yum.repos.d/mariadb-maxscale.repo.rpmnew'
]
for repo_file in problematic_repos:
if os.path.exists(repo_file):
os.remove(repo_file)
Upgrade.stdOut(f"Removed {repo_file}", 1)
# Clean DNF cache
Upgrade.stdOut("Cleaning DNF cache...", 1)
command = "dnf clean all"
subprocess.run(command, shell=True, capture_output=True)
# Install MariaDB from official repository
Upgrade.stdOut("Setting up official MariaDB repository...", 1)
command = "curl -sS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | bash -s -- --mariadb-server-version='10.11'"
result = subprocess.run(command, shell=True, capture_output=True, text=True)
if result.returncode != 0:
Upgrade.stdOut(f"Warning: MariaDB repo setup failed: {result.stderr}", 0)
# Install MariaDB packages
Upgrade.stdOut("Installing MariaDB packages...", 1)
mariadb_packages = "MariaDB-server MariaDB-client MariaDB-backup MariaDB-devel"
command = f"dnf install -y {mariadb_packages}"
result = subprocess.run(command, shell=True, capture_output=True, text=True)
if result.returncode != 0:
Upgrade.stdOut(f"Warning: MariaDB installation issues: {result.stderr}", 0)
# Start and enable MariaDB service
Upgrade.stdOut("Starting MariaDB service...", 1)
services = ['mariadb', 'mysql', 'mysqld']
for service in services:
try:
command = f"systemctl start {service}"
result = subprocess.run(command, shell=True, capture_output=True)
if result.returncode == 0:
command = f"systemctl enable {service}"
subprocess.run(command, shell=True, capture_output=True)
Upgrade.stdOut(f"MariaDB service started as {service}", 1)
break
except:
continue
Upgrade.stdOut("AlmaLinux 9 MariaDB fixes completed", 1)
except Exception as e:
Upgrade.stdOut(f"Error applying AlmaLinux 9 MariaDB fixes: {str(e)}", 0)
@staticmethod
def get_available_php_versions():
"""Get list of available PHP versions based on OS"""
# Check for AlmaLinux 9+ first
if os.path.exists('/etc/almalinux-release'):
try:
with open('/etc/almalinux-release', 'r') as f:
content = f.read()
if 'release 9' in content or 'release 10' in content:
Upgrade.stdOut("AlmaLinux 9+ detected - checking available PHP versions", 1)
# AlmaLinux 9+ doesn't have PHP 7.1, 7.2, 7.3
php_versions = ['74', '80', '81', '82', '83', '84', '85']
else:
php_versions = ['71', '72', '73', '74', '80', '81', '82', '83', '84', '85']
except:
php_versions = ['71', '72', '73', '74', '80', '81', '82', '83', '84', '85']
else:
# Check other OS versions
os_info = Upgrade.findOperatingSytem()
if os_info in [Ubuntu24, CENTOS8]:
php_versions = ['74', '80', '81', '82', '83', '84', '85']
else:
php_versions = ['71', '72', '73', '74', '80', '81', '82', '83', '84', '85']
# Check availability of each version
available_versions = []
for version in php_versions:
if Upgrade.check_package_availability(f'lsphp{version}'):
available_versions.append(version)
else:
Upgrade.stdOut(f"PHP {version} not available on this OS", 0)
return available_versions
@staticmethod
def fixLiteSpeedConfig():
"""Fix LiteSpeed configuration issues by creating missing files"""
try:
Upgrade.stdOut("Checking and fixing LiteSpeed configuration...", 1)
# Check if LiteSpeed is installed
if not os.path.exists('/usr/local/lsws'):
Upgrade.stdOut("LiteSpeed not found at /usr/local/lsws", 0)
return
# Create missing configuration files
config_files = [
"/usr/local/lsws/conf/httpd_config.xml",
"/usr/local/lsws/conf/httpd.conf",
"/usr/local/lsws/conf/modsec.conf"
]
for config_file in config_files:
if not os.path.exists(config_file):
Upgrade.stdOut(f"Missing LiteSpeed config: {config_file}", 0)
# Create directory if it doesn't exist
os.makedirs(os.path.dirname(config_file), exist_ok=True)
# Create minimal config file
if config_file.endswith('httpd_config.xml'):
with open(config_file, 'w') as f:
f.write('<?xml version="1.0" encoding="UTF-8"?>\n')
f.write('<httpServerConfig>\n')
f.write(' <!-- Minimal LiteSpeed configuration -->\n')
f.write(' <listener>\n')
f.write(' <name>Default</name>\n')
f.write(' <address>*:8088</address>\n')
f.write(' </listener>\n')
f.write('</httpServerConfig>\n')
elif config_file.endswith('httpd.conf'):
with open(config_file, 'w') as f:
f.write('# Minimal LiteSpeed HTTP configuration\n')
f.write('# This file will be updated by CyberPanel\n')
elif config_file.endswith('modsec.conf'):
with open(config_file, 'w') as f:
f.write('# ModSecurity configuration\n')
f.write('# This file will be updated by CyberPanel\n')
Upgrade.stdOut(f"Created minimal config: {config_file}", 1)
else:
Upgrade.stdOut(f"LiteSpeed config exists: {config_file}", 1)
except Exception as e:
Upgrade.stdOut(f"Error fixing LiteSpeed config: {str(e)}", 0)
@staticmethod
def installPHP73():
try:
if Upgrade.installedOutput.find('lsphp73') == -1:
command = 'yum install -y lsphp73 lsphp73-json lsphp73-xmlrpc lsphp73-xml lsphp73-tidy lsphp73-soap lsphp73-snmp ' \
'lsphp73-recode lsphp73-pspell lsphp73-process lsphp73-pgsql lsphp73-pear lsphp73-pdo lsphp73-opcache ' \
'lsphp73-odbc lsphp73-mysqlnd lsphp73-mcrypt lsphp73-mbstring lsphp73-ldap lsphp73-intl lsphp73-imap ' \
'lsphp73-gmp lsphp73-gd lsphp73-enchant lsphp73-dba lsphp73-common lsphp73-bcmath'
Upgrade.executioner(command, 'Install PHP 73, 0')
if Upgrade.installedOutput.find('lsphp74') == -1:
command = 'yum install -y lsphp74 lsphp74-json lsphp74-xmlrpc lsphp74-xml lsphp74-tidy lsphp74-soap lsphp74-snmp ' \
'lsphp74-recode lsphp74-pspell lsphp74-process lsphp74-pgsql lsphp74-pear lsphp74-pdo lsphp74-opcache ' \
'lsphp74-odbc lsphp74-mysqlnd lsphp74-mcrypt lsphp74-mbstring lsphp74-ldap lsphp74-intl lsphp74-imap ' \
'lsphp74-gmp lsphp74-gd lsphp74-enchant lsphp74-dba lsphp74-common lsphp74-bcmath'
Upgrade.executioner(command, 'Install PHP 74, 0')
if Upgrade.installedOutput.find('lsphp80') == -1:
command = 'yum install lsphp80* -y'
subprocess.call(command, shell=True)
if Upgrade.installedOutput.find('lsphp81') == -1:
command = 'yum install lsphp81* -y'
subprocess.call(command, shell=True)
if Upgrade.installedOutput.find('lsphp82') == -1:
command = 'yum install lsphp82* -y'
subprocess.call(command, shell=True)
command = 'yum install lsphp83* -y'
subprocess.call(command, shell=True)
command = 'yum install lsphp84* -y'
subprocess.call(command, shell=True)
command = 'yum install lsphp85* -y'
Upgrade.stdOut("Installing PHP versions based on OS compatibility...", 1)
# Get available PHP versions
available_versions = Upgrade.get_available_php_versions()
if not available_versions:
Upgrade.stdOut("No PHP versions available for installation", 0)
return
Upgrade.stdOut(f"Installing available PHP versions: {', '.join(available_versions)}", 1)
for version in available_versions:
try:
if version in ['71', '72', '73', '74']:
# PHP 7.x versions with specific extensions
if Upgrade.installedOutput.find(f'lsphp{version}') == -1:
extensions = ['json', 'xmlrpc', 'xml', 'tidy', 'soap', 'snmp', 'recode', 'pspell', 'process', 'pgsql', 'pear', 'pdo', 'opcache', 'odbc', 'mysqlnd', 'mcrypt', 'mbstring', 'ldap', 'intl', 'imap', 'gmp', 'gd', 'enchant', 'dba', 'common', 'bcmath']
package_list = f"lsphp{version} " + " ".join([f"lsphp{version}-{ext}" for ext in extensions])
command = f"yum install -y {package_list}"
Upgrade.executioner(command, f'Install PHP {version}', 0)
else:
# PHP 8.x versions
if Upgrade.installedOutput.find(f'lsphp{version}') == -1:
command = f"yum install lsphp{version}* -y"
subprocess.call(command, shell=True)
Upgrade.stdOut(f"Installed PHP {version}", 1)
except Exception as e:
Upgrade.stdOut(f"Error installing PHP {version}: {str(e)}", 0)
continue
except:
command = 'DEBIAN_FRONTEND=noninteractive apt-get -y install ' \
@@ -3997,9 +4174,20 @@ pm.max_spare_servers = 3
@staticmethod
def setupPHPSymlink():
try:
# Check if PHP 8.3 exists
if not os.path.exists('/usr/local/lsws/lsphp83/bin/php'):
Upgrade.stdOut("PHP 8.3 not found, installing it first...")
# Try to find available PHP version (prioritize modern stable versions)
# Priority: 8.3 (recommended), 8.2, 8.4, 8.5, 8.1, 8.0, then older versions
php_versions = ['83', '82', '84', '85', '81', '80', '74', '73', '72', '71']
selected_php = None
for version in php_versions:
if os.path.exists(f'/usr/local/lsws/lsphp{version}/bin/php'):
selected_php = version
Upgrade.stdOut(f"Found PHP {version}, using as default", 1)
break
if not selected_php:
# Try to install PHP 8.3 as fallback (modern stable version)
Upgrade.stdOut("No PHP found, installing PHP 8.3 as fallback...")
# Install PHP 8.3 based on OS
if os.path.exists(Upgrade.CentOSPath) or os.path.exists(Upgrade.openEulerPath):
@@ -4013,16 +4201,17 @@ pm.max_spare_servers = 3
if not os.path.exists('/usr/local/lsws/lsphp83/bin/php'):
Upgrade.stdOut('[ERROR] Failed to install PHP 8.3')
return 0
selected_php = '83'
# Remove existing PHP symlink if it exists
if os.path.exists('/usr/bin/php'):
os.remove('/usr/bin/php')
# Create symlink to PHP 8.3
command = 'ln -s /usr/local/lsws/lsphp83/bin/php /usr/bin/php'
Upgrade.executioner(command, 'Setup PHP Symlink to 8.3', 0)
# Create symlink to selected PHP version
command = f'ln -s /usr/local/lsws/lsphp{selected_php}/bin/php /usr/bin/php'
Upgrade.executioner(command, f'Setup PHP Symlink to {selected_php}', 0)
Upgrade.stdOut("PHP symlink updated to PHP 8.3 successfully.")
Upgrade.stdOut(f"PHP symlink updated to PHP {selected_php} successfully.")
except BaseException as msg:
Upgrade.stdOut('[ERROR] ' + str(msg) + " [setupPHPSymlink]")
@@ -4150,6 +4339,9 @@ pm.max_spare_servers = 3
Upgrade.manageServiceMigrations()
Upgrade.enableServices()
# Apply AlmaLinux 9 fixes before other installations
Upgrade.fix_almalinux9_mariadb()
Upgrade.installPHP73()
Upgrade.setupCLI()
Upgrade.someDirectories()
@@ -4158,6 +4350,9 @@ pm.max_spare_servers = 3
## Fix Apache configuration issues after upgrade
Upgrade.fixApacheConfiguration()
# Fix LiteSpeed configuration files if missing
Upgrade.fixLiteSpeedConfig()
### General migrations are not needed any more
@@ -4191,8 +4386,32 @@ pm.max_spare_servers = 3
except:
pass
command = 'cp /usr/local/lsws/lsphp80/bin/lsphp %s' % (phpPath)
# Try to find available PHP binary in order of preference (modern stable first)
php_versions = ['83', '82', '84', '85', '81', '80', '74', '73', '72', '71']
php_binary_found = False
for version in php_versions:
php_binary = f'/usr/local/lsws/lsphp{version}/bin/lsphp'
if os.path.exists(php_binary):
command = f'cp {php_binary} {phpPath}'
Upgrade.executioner(command, 0)
Upgrade.stdOut(f"Using PHP {version} for LSCPD", 1)
php_binary_found = True
break
if not php_binary_found:
Upgrade.stdOut("Warning: No PHP binary found for LSCPD", 0)
# Try to create a symlink to any available PHP
try:
command = 'find /usr/local/lsws -name "lsphp" -type f 2>/dev/null | head -1'
result = subprocess.run(command, shell=True, capture_output=True, text=True)
if result.stdout.strip():
php_binary = result.stdout.strip()
command = f'cp {php_binary} {phpPath}'
Upgrade.executioner(command, 0)
Upgrade.stdOut(f"Using found PHP binary: {php_binary}", 1)
except:
pass
if Upgrade.SoftUpgrade == 0:
try:
@@ -4200,6 +4419,42 @@ pm.max_spare_servers = 3
Upgrade.executioner(command, 'Start LSCPD', 0)
except:
pass
# Try to start other services if they exist
# Enhanced service startup with AlmaLinux 9 support
services_to_start = ['fastapi_ssh_server', 'cyberpanel']
# Special handling for AlmaLinux 9 MariaDB service
if Upgrade.is_almalinux9():
Upgrade.stdOut("AlmaLinux 9 detected - applying enhanced service management", 1)
mariadb_services = ['mariadb', 'mysql', 'mysqld']
for service in mariadb_services:
try:
check_command = f"systemctl list-unit-files | grep -q {service}"
result = subprocess.run(check_command, shell=True, capture_output=True)
if result.returncode == 0:
command = f"systemctl restart {service}"
Upgrade.executioner(command, f'Restart {service} for AlmaLinux 9', 0)
command = f"systemctl enable {service}"
Upgrade.executioner(command, f'Enable {service} for AlmaLinux 9', 0)
Upgrade.stdOut(f"MariaDB service managed as {service} on AlmaLinux 9", 1)
break
except Exception as e:
Upgrade.stdOut(f"Could not manage MariaDB service {service}: {str(e)}", 0)
continue
for service in services_to_start:
try:
# Check if service exists
check_command = f"systemctl list-unit-files | grep -q {service}"
result = subprocess.run(check_command, shell=True, capture_output=True)
if result.returncode == 0:
command = f"systemctl start {service}"
Upgrade.executioner(command, f'Start {service}', 0)
else:
Upgrade.stdOut(f"Service {service} not found, skipping", 0)
except Exception as e:
Upgrade.stdOut(f"Could not start {service}: {str(e)}", 0)
# Remove CSF if installed and restore firewalld (CSF is being discontinued on August 31, 2025)
if os.path.exists('/etc/csf'):

File diff suppressed because it is too large Load Diff