Merge pull request #1702 from master3395/v2.5.5-dev

V2.5.5 dev
This commit is contained in:
Master3395
2026-02-15 23:58:03 +01:00
committed by GitHub
24 changed files with 4906 additions and 2088 deletions

33
.github/scripts/ci-validate-upgrade.sh vendored Executable file
View File

@@ -0,0 +1,33 @@
#!/usr/bin/env bash
# Run inside CI Docker container (or repo root). Validates upgrade loader + modules and key files.
set -e
echo "=== Shell syntax check ==="
for f in cyberpanel_upgrade.sh preUpgrade.sh fix-phpmyadmin.sh cyberpanel.sh cyberpanel_utility.sh; do
[ ! -f "$f" ] && continue
bash -n "$f" || { echo "FAIL (syntax): $f"; exit 1; }
echo "OK $f"
done
test -f preUpgrade.sh && test -f cyberpanel_upgrade.sh || { echo "Missing required scripts"; exit 1; }
echo "=== Key files ==="
for f in preUpgrade.sh cyberpanel_upgrade.sh plogical/upgrade.py install/install.py; do
test -f "$f" || { echo "Missing: $f"; exit 1; }
done
grep -q 'BRANCH_NAME' preUpgrade.sh || exit 1
if [ -d upgrade_modules ]; then
for n in 00_common 01_variables 02_checks 03_mariadb 04_git_url 05_repository 06_components 07_branch_input 08_main_upgrade 09_sync 10_post_tweak 11_display_final; do
test -f "upgrade_modules/${n}.sh" || { echo "Missing: upgrade_modules/${n}.sh"; exit 1; }
done
grep -q 'Branch_Check\|Branch_Name' upgrade_modules/00_common.sh upgrade_modules/02_checks.sh || exit 1
grep -q 'upgrade_modules\|Pre_Upgrade_Branch_Input\|Set_Default_Variables' cyberpanel_upgrade.sh || exit 1
for f in upgrade_modules/*.sh; do
[ -f "$f" ] || continue
bash -n "$f" || { echo "FAIL (syntax): $f"; exit 1; }
done
else
grep -q 'Branch_Name\|download_install_phpmyadmin\|Branch_Check' cyberpanel_upgrade.sh || exit 1
fi
echo "Done."

View File

@@ -1,6 +1,7 @@
# Lightweight CI for v2.5.5-dev (free for public repos).
# Validates shell syntax, Python version fetcher, and key files on all supported OSes via Docker.
# CloudLinux and RHEL use Rocky/Alma images as proxies (same family, no official Docker images).
# Validates shell syntax, Python version fetcher, key files, and upgrade script.
# Pinned to ubuntu-22.04. Multi-OS validation: run locally with
# for img in almalinux:8 centos:7 debian:12 ubuntu:24.04; do docker run --rm -v "$PWD:/repo:ro" -w /repo $img bash /repo/.github/scripts/ci-validate-upgrade.sh; done
name: CI
on:
@@ -12,7 +13,7 @@ on:
jobs:
validate-shell:
name: Validate shell scripts
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Syntax check shell scripts
@@ -23,11 +24,20 @@ jobs:
echo "OK $f"
done
test -f preUpgrade.sh && test -f cyberpanel_upgrade.sh || { echo "Missing required scripts"; exit 1; }
if [ -d upgrade_modules ]; then
echo "=== Upgrade modules syntax ==="
for f in upgrade_modules/*.sh; do
[ -f "$f" ] || continue
bash -n "$f" || { echo "FAIL (syntax): $f"; exit 1; }
echo "OK $f"
done
fi
echo "All shell scripts passed syntax check"
validate-python:
name: Validate Python (version fetcher)
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
timeout-minutes: 2
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
@@ -37,6 +47,10 @@ jobs:
run: pip install requests
- name: Run version fetcher (phpMyAdmin / SnappyMail)
run: |
if [ ! -f plogical/versionFetcher.py ]; then
echo "Skipping (plogical/versionFetcher.py not present on this branch)"
exit 0
fi
PYTHONPATH=. python3 -c "
from plogical.versionFetcher import get_latest_phpmyadmin_version, get_latest_snappymail_version
pma = get_latest_phpmyadmin_version()
@@ -48,79 +62,38 @@ jobs:
smoke-key-files:
name: Key files present
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Check key install/upgrade files exist
run: |
for f in preUpgrade.sh cyberpanel_upgrade.sh plogical/upgrade.py install/install.py plogical/versionFetcher.py; do
for f in preUpgrade.sh cyberpanel_upgrade.sh plogical/upgrade.py install/install.py; do
test -f "$f" || { echo "Missing: $f"; exit 1; }
done
test -f plogical/versionFetcher.py && echo "versionFetcher.py present" || echo "versionFetcher.py optional (not on all branches)"
grep -q 'BRANCH_NAME' preUpgrade.sh || exit 1
grep -q 'Branch_Name\|download_install_phpmyadmin\|Branch_Check' cyberpanel_upgrade.sh || exit 1
if [ -d upgrade_modules ]; then
for n in 00_common 01_variables 02_checks 03_mariadb 04_git_url 05_repository 06_components 07_branch_input 08_main_upgrade 09_sync 10_post_tweak 11_display_final; do
test -f "upgrade_modules/${n}.sh" || { echo "Missing: upgrade_modules/${n}.sh"; exit 1; }
done
grep -q 'Branch_Check\|Branch_Name' upgrade_modules/00_common.sh upgrade_modules/02_checks.sh || exit 1
grep -q 'upgrade_modules\|Pre_Upgrade_Branch_Input\|Set_Default_Variables' cyberpanel_upgrade.sh || exit 1
else
grep -q 'Branch_Name\|download_install_phpmyadmin\|Branch_Check' cyberpanel_upgrade.sh || exit 1
fi
echo "Key files OK"
# Run validation inside a container per supported OS (AlmaLinux, CentOS, CloudLinux, Debian, RHEL, Rocky, Ubuntu).
validate-on-os:
name: Validate on ${{ matrix.os }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- os: AlmaLinux 8
image: almalinux:8
- os: AlmaLinux 9
image: almalinux:9
- os: AlmaLinux 10
image: almalinux:10
- os: CentOS 7
image: centos:7
- os: CloudLinux 8
image: rockylinux:8
- os: CloudLinux 9
image: rockylinux:9
- os: Debian 11
image: debian:11
- os: Debian 12
image: debian:12
- os: Debian 13
image: debian:13
- os: RHEL 8
image: almalinux:8
- os: RHEL 9
image: almalinux:9
- os: RockyLinux 8
image: rockylinux:8
- os: RockyLinux 9
image: rockylinux:9
- os: Ubuntu 20.04
image: ubuntu:20.04
- os: Ubuntu 22.04
image: ubuntu:22.04
- os: Ubuntu 24.04
image: ubuntu:24.04
# Run upgrade validation script (same checks as other jobs; no Docker to avoid runner issues).
validate-upgrade-script:
name: Validate upgrade script
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Validate on ${{ matrix.os }} (${{ matrix.image }})
- name: Run ci-validate-upgrade.sh
run: |
docker run --rm \
-v "$PWD:/repo:ro" \
-w /repo \
"${{ matrix.image }}" \
bash -c '
set -e
echo "=== Shell syntax check ==="
for f in cyberpanel_upgrade.sh preUpgrade.sh fix-phpmyadmin.sh cyberpanel.sh cyberpanel_utility.sh; do
[ ! -f "$f" ] && continue
bash -n "$f" || { echo "FAIL (syntax): $f"; exit 1; }
echo "OK $f"
done
test -f preUpgrade.sh && test -f cyberpanel_upgrade.sh || { echo "Missing required scripts"; exit 1; }
echo "=== Key files ==="
for f in preUpgrade.sh cyberpanel_upgrade.sh plogical/upgrade.py install/install.py plogical/versionFetcher.py; do
test -f "$f" || { echo "Missing: $f"; exit 1; }
done
grep -q "BRANCH_NAME" preUpgrade.sh && grep -q "Branch_Name\|download_install_phpmyadmin\|Branch_Check" cyberpanel_upgrade.sh || exit 1
echo "Done."
'
set -e
if [ ! -f .github/scripts/ci-validate-upgrade.sh ]; then
echo "Missing .github/scripts/ci-validate-upgrade.sh"
exit 1
fi
bash .github/scripts/ci-validate-upgrade.sh

View File

@@ -209,6 +209,9 @@ STATIC_ROOT = os.path.join(BASE_DIR, "static/")
STATIC_URL = '/static/'
# Panel public directory (SnappyMail, phpMyAdmin, etc.) served so /snappymail/ and /phpmyadmin/ work when panel is behind Django
PUBLIC_ROOT = os.path.join(BASE_DIR, 'public')
LOCALE_PATHS = (
os.path.join(BASE_DIR, 'locale'),
)
@@ -247,4 +250,25 @@ LOGIN_REDIRECT_URL = '/'
# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
# Sync INSTALLED_APPS with plugins on disk so /plugins/<name>/ and /plugins/<name>/settings/ work.
# Plugins installed under /usr/local/CyberCP/ (or BASE_DIR) are added here if they have meta.xml + urls.py.
_cybercp_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if os.path.isdir(_cybercp_root):
try:
_existing_apps = set(INSTALLED_APPS)
for _name in os.listdir(_cybercp_root):
if _name.startswith('.'):
continue
_plugin_dir = os.path.join(_cybercp_root, _name)
if not os.path.isdir(_plugin_dir):
continue
if _name in _existing_apps:
continue
if (os.path.exists(os.path.join(_plugin_dir, 'meta.xml')) and
os.path.exists(os.path.join(_plugin_dir, 'urls.py'))):
INSTALLED_APPS.append(_name)
_existing_apps.add(_name)
except (OSError, IOError):
pass

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -47,7 +47,8 @@ try {
$username = htmlspecialchars($_POST['username'], ENT_QUOTES, 'UTF-8');
$password = $_POST['password'];
$host = isset($_POST['host']) ? trim($_POST['host']) : 'localhost';
$host = isset($_POST['host']) ? trim($_POST['host']) : '127.0.0.1';
if ($host === 'localhost') { $host = '127.0.0.1'; }
$_SESSION['PMA_single_signon_user'] = $username;
$_SESSION['PMA_single_signon_password'] = $password;

View File

@@ -1262,6 +1262,8 @@ $cfg['Servers'][$i]['auth_type'] = 'signon';
$cfg['Servers'][$i]['SignonSession'] = 'SignonSession';
$cfg['Servers'][$i]['SignonURL'] = 'phpmyadminsignin.php';
$cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout';
$cfg['Servers'][$i]['host'] = '127.0.0.1';
$cfg['Servers'][$i]['port'] = '3306';
"""
for items in data:
@@ -1295,8 +1297,10 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout';
mysqluser = jsonData['mysqluser']
mysqlpassword = jsonData['mysqlpassword']
mysqlport = jsonData['mysqlport']
mysqlhost = jsonData['mysqlhost']
mysqlport = jsonData.get('mysqlport', 3306)
mysqlhost = jsonData.get('mysqlhost', '127.0.0.1') or '127.0.0.1'
if mysqlhost == 'localhost':
mysqlhost = '127.0.0.1'
command = "sed -i 's|localhost|%s|g' /usr/local/CyberCP/public/phpmyadmin/phpmyadminsignin.php" % (
mysqlhost)

View File

@@ -430,13 +430,20 @@
.installed-sort-filter-bar {
flex-basis: 100%;
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 12px;
flex-direction: column;
align-items: flex-start;
gap: 10px;
margin-top: 12px;
padding: 12px 0;
border-top: 1px solid var(--border-primary, #e2e8f0);
}
.installed-sort-filter-bar .installed-filter-row,
.installed-sort-filter-bar .installed-sort-row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 12px;
}
.installed-sort-filter-bar .sort-label {
font-size: 13px;
font-weight: 600;
@@ -819,6 +826,82 @@
border-radius: 8px;
}
/* Collapsible Category Filter for Grid/Table (installed view) - same style as A-Å filter */
.installed-category-filter-wrapper {
margin-top: 12px;
margin-bottom: 0;
}
.installed-category-toggle-btn {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
border: 1px solid var(--border-primary, #e8e9ff);
background: var(--bg-primary, white);
border-radius: 8px;
font-size: 13px;
font-weight: 600;
color: var(--text-secondary, #64748b);
cursor: pointer;
transition: all 0.2s;
}
.installed-category-toggle-btn:hover {
background: var(--bg-hover, #f8f9ff);
border-color: #5856d6;
color: #5856d6;
}
.installed-category-toggle-btn[aria-expanded="true"] .installed-category-chevron {
transform: rotate(180deg);
}
.installed-category-chevron {
font-size: 10px;
transition: transform 0.2s;
}
.installed-category-filter {
display: block;
margin-top: 12px;
padding: 15px;
background: var(--bg-secondary, #f8f9ff);
border-radius: 8px;
}
.installed-category-filter .installed-filter-row,
.installed-category-filter .installed-sort-row {
margin-bottom: 12px;
}
.installed-category-filter .installed-sort-row:last-of-type {
margin-bottom: 0;
}
.installed-category-filter-btns {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 12px;
}
.installed-category-btn {
padding: 6px 12px;
border: 1px solid var(--border-primary, #e8e9ff);
background: var(--bg-primary, white);
border-radius: 6px;
font-size: 13px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
color: var(--text-secondary, #64748b);
display: inline-flex;
align-items: center;
gap: 6px;
}
.installed-category-btn:hover {
background: var(--bg-hover, #f0f1ff);
border-color: #5856d6;
color: #5856d6;
}
.installed-category-btn.active {
background: #5856d6;
color: white;
border-color: #5856d6;
}
.alpha-btn {
padding: 6px 12px;
border: 1px solid var(--border-primary, #e8e9ff);
@@ -1224,21 +1307,58 @@
{% trans "Plugin Development Guide" %}
</a>
</div>
<!-- Sort bar for Grid and Table view (visible when grid or table is active) -->
<!-- Filter + Sort bar for Grid and Table view (visible when grid or table is active). All controls in collapsible "Filter". -->
<div id="installedSortFilterBar" class="installed-sort-filter-bar" style="display: none;"
data-trans-name-asc="{% trans 'Name A-Å' %}" data-trans-name-desc="{% trans 'Name Å-A' %}"
data-trans-date-newest="{% trans 'Date (newest)' %}" data-trans-date-oldest="{% trans 'Date (oldest)' %}">
<span class="sort-label">{% trans "Sort by:" %}</span>
<div class="sort-btns">
<button type="button" class="sort-btn active" data-sort-field="name" id="installedSortBtnName" onclick="toggleInstalledSort('name')" title="{% trans 'Click to toggle A-Å / Å-A' %}">
<i class="fas fa-sort-alpha-down"></i> <span class="sort-btn-label">{% trans "Name A-Å" %}</span>
</button>
<button type="button" class="sort-btn" data-sort-field="type" id="installedSortBtnType" onclick="toggleInstalledSort('type')" title="{% trans 'By category/type' %}">
<i class="fas fa-tag"></i> <span class="sort-btn-label">{% trans "Type" %}</span>
</button>
<button type="button" class="sort-btn" data-sort-field="date" id="installedSortBtnDate" onclick="toggleInstalledSort('date')" title="{% trans 'Click to toggle newest / oldest' %}">
<i class="fas fa-calendar-alt"></i> <span class="sort-btn-label">{% trans "Date (newest)" %}</span>
data-trans-date-newest="{% trans 'Date (newest)' %}" data-trans-date-oldest="{% trans 'Date (oldest)' }}">
<div class="installed-category-filter-wrapper">
<button type="button" class="installed-category-toggle-btn" id="installedCategoryToggleBtn" onclick="toggleInstalledCategoryFilter()" aria-expanded="false">
<i class="fas fa-filter"></i>
<span>{% trans "Filter" %}</span>
<i class="fas fa-chevron-down installed-category-chevron"></i>
</button>
<div class="installed-category-filter" id="installedCategoryFilter" aria-hidden="true" style="display: none;">
<div class="installed-filter-row">
<span class="sort-label">{% trans "Show:" %}</span>
<div class="filter-btns sort-btns">
<button type="button" class="sort-btn filter-btn active" data-filter="all" id="installedFilterBtnAll" onclick="setInstalledFilter('all')" title="{% trans 'Show all plugins' %}">
<i class="fas fa-th-list"></i> <span class="filter-btn-label">{% trans "All" %}</span>
</button>
<button type="button" class="sort-btn filter-btn" data-filter="installed" id="installedFilterBtnInstalled" onclick="setInstalledFilter('installed')" title="{% trans 'Show only installed plugins' %}">
<i class="fas fa-check-circle"></i> <span class="filter-btn-label">{% trans "Installed only" %}</span>
</button>
<button type="button" class="sort-btn filter-btn" data-filter="active" id="installedFilterBtnActive" onclick="setInstalledFilter('active')" title="{% trans 'Show only active (enabled) plugins' %}">
<i class="fas fa-power-off"></i> <span class="filter-btn-label">{% trans "Active only" %}</span>
</button>
</div>
</div>
<div class="installed-sort-row">
<span class="sort-label">{% trans "Sort by:" %}</span>
<div class="sort-btns">
<button type="button" class="sort-btn active" data-sort-field="name" id="installedSortBtnName" onclick="toggleInstalledSort('name')" title="{% trans 'Click to toggle A-Å / Å-A' %}">
<i class="fas fa-sort-alpha-down"></i> <span class="sort-btn-label">{% trans "Name A-Å" %}</span>
</button>
<button type="button" class="sort-btn" data-sort-field="type" id="installedSortBtnType" onclick="toggleInstalledSort('type')" title="{% trans 'By category/type' %}">
<i class="fas fa-tag"></i> <span class="sort-btn-label">{% trans "Type" %}</span>
</button>
<button type="button" class="sort-btn" data-sort-field="date" id="installedSortBtnDate" onclick="toggleInstalledSort('date')" title="{% trans 'Click to toggle newest / oldest' %}">
<i class="fas fa-calendar-alt"></i> <span class="sort-btn-label">{% trans "Date (newest)" %}</span>
</button>
</div>
</div>
<div class="installed-category-filter-btns">
<button type="button" class="installed-category-btn active" data-category="all" onclick="filterByCategoryInstalled('all', event)">{% trans "All" %}</button>
<button type="button" class="installed-category-btn" data-category="Utility" onclick="filterByCategoryInstalled('Utility', event)"><i class="fas fa-tools"></i> {% trans "Utility" %}</button>
<button type="button" class="installed-category-btn" data-category="Security" onclick="filterByCategoryInstalled('Security', event)"><i class="fas fa-shield-alt"></i> {% trans "Security" %}</button>
<button type="button" class="installed-category-btn" data-category="Backup" onclick="filterByCategoryInstalled('Backup', event)"><i class="fas fa-save"></i> {% trans "Backup" %}</button>
<button type="button" class="installed-category-btn" data-category="Performance" onclick="filterByCategoryInstalled('Performance', event)"><i class="fas fa-rocket"></i> {% trans "Performance" %}</button>
<button type="button" class="installed-category-btn" data-category="Monitoring" onclick="filterByCategoryInstalled('Monitoring', event)"><i class="fas fa-heartbeat"></i> {% trans "Monitoring" %}</button>
<button type="button" class="installed-category-btn" data-category="Integration" onclick="filterByCategoryInstalled('Integration', event)"><i class="fas fa-plug"></i> {% trans "Integration" %}</button>
<button type="button" class="installed-category-btn" data-category="Email" onclick="filterByCategoryInstalled('Email', event)"><i class="fas fa-envelope"></i> {% trans "Email" %}</button>
<button type="button" class="installed-category-btn" data-category="Development" onclick="filterByCategoryInstalled('Development', event)"><i class="fas fa-code"></i> {% trans "Development" %}</button>
<button type="button" class="installed-category-btn" data-category="Analytics" onclick="filterByCategoryInstalled('Analytics', event)"><i class="fas fa-chart-bar"></i> {% trans "Analytics" %}</button>
</div>
</div>
</div>
</div>
</div>
@@ -1246,7 +1366,7 @@
<!-- Grid View -->
<div id="gridView" class="plugins-grid">
{% for plugin in plugins %}
<div class="plugin-card" data-plugin-name="{{ plugin.name }}" data-plugin-desc="{{ plugin.desc }}" data-plugin-type="{{ plugin.type }}" data-modify-date="{{ plugin.modify_date|default:'0000-00-00 00:00:00' }}">
<div class="plugin-card" data-plugin-name="{{ plugin.name }}" data-plugin-desc="{{ plugin.desc }}" data-plugin-type="{{ plugin.type }}" data-modify-date="{{ plugin.modify_date|default:'0000-00-00 00:00:00' }}" data-installed="{{ plugin.installed|yesno:'true,false' }}" data-enabled="{{ plugin.enabled|yesno:'true,false' }}">
<div class="plugin-header">
<div class="plugin-icon">
{% if plugin.type|lower == "security" %}
@@ -1388,7 +1508,7 @@
</thead>
<tbody>
{% for plugin in plugins %}
<tr data-plugin-name="{{ plugin.name }}" data-plugin-desc="{{ plugin.desc }}" data-plugin-type="{{ plugin.type }}" data-modify-date="{{ plugin.modify_date|default:'0000-00-00 00:00:00' }}">
<tr data-plugin-name="{{ plugin.name }}" data-plugin-desc="{{ plugin.desc }}" data-plugin-type="{{ plugin.type }}" data-modify-date="{{ plugin.modify_date|default:'0000-00-00 00:00:00' }}" data-installed="{{ plugin.installed|yesno:'true,false' }}" data-enabled="{{ plugin.enabled|yesno:'true,false' }}">
<td>
<strong>{{ plugin.name }}</strong>
{% if plugin.freshness_badge %}
@@ -1651,13 +1771,15 @@
</div>
<script>
// Cache-busting version: 2026-02-01-v1 - Fixed category filter, added search bar, collapsible A-Å
// Cache-busting version: 2026-02-15-v1 - Grid/Table: collapsible Category Filter (like A-Å in store)
let storePlugins = [];
let currentFilter = 'all';
let currentCategory = 'all';
let currentSearchQuery = '';
let isSettingHash = false; // Flag to prevent infinite loops
let currentInstalledSort = 'name-asc'; // name-asc, name-desc, type, date-desc, date-asc
let currentInstalledFilter = 'all'; // all, installed, active
let currentInstalledCategory = 'all'; // all, Utility, Security, ...
// Get CSRF cookie helper function
function getCookie(name) {
@@ -2035,14 +2157,43 @@ function clearPluginSearch() {
}
}
function setInstalledFilter(filter) {
currentInstalledFilter = filter;
var bar = document.getElementById('installedSortFilterBar');
if (bar) {
try {
bar.querySelectorAll('.filter-btn').forEach(function(btn) {
btn.classList.toggle('active', (btn.getAttribute('data-filter') || '') === filter);
});
} catch (e) { console.warn('setInstalledFilter: filter buttons', e); }
}
try {
filterInstalledPlugins();
} catch (e) { console.warn('setInstalledFilter: filterInstalledPlugins', e); }
}
function filterInstalledPlugins() {
const query = (document.getElementById('installedPluginSearchInput') && document.getElementById('installedPluginSearchInput').value) || '';
const terms = query.trim().toLowerCase().split(/\s+/).filter(function(t) { return t.length > 0; });
const filter = currentInstalledFilter || 'all';
const gridView = document.getElementById('gridView');
const tableView = document.getElementById('tableView');
const noResultsGrid = document.getElementById('installedPluginsNoResultsGrid');
const noResultsTable = document.getElementById('installedPluginsNoResultsTable');
if (!gridView && !tableView) return;
var visibleCount = 0;
function matchesFilter(installed, enabled) {
if (filter === 'all') return true;
if (filter === 'installed') return installed === 'true';
if (filter === 'active') return installed === 'true' && enabled === 'true';
return true;
}
var cat = (typeof currentInstalledCategory !== 'undefined' ? currentInstalledCategory : 'all');
function matchesCategory(typeAttr) {
if (cat === 'all') return true;
var t = (typeAttr || '').trim().toLowerCase();
return t === (cat || '').trim().toLowerCase();
}
if (gridView) {
var cards = gridView.querySelectorAll('.plugin-card');
cards.forEach(function(card) {
@@ -2050,7 +2201,12 @@ function filterInstalledPlugins() {
var desc = (card.getAttribute('data-plugin-desc') || '').toLowerCase();
var type = (card.getAttribute('data-plugin-type') || '').toLowerCase();
var combined = name + ' ' + desc + ' ' + type;
var show = terms.length === 0 || terms.every(function(term) { return combined.indexOf(term) !== -1; });
var searchMatch = terms.length === 0 || terms.every(function(term) { return combined.indexOf(term) !== -1; });
var installed = card.getAttribute('data-installed') || 'false';
var enabled = card.getAttribute('data-enabled') || 'false';
var filterMatch = matchesFilter(installed, enabled);
var categoryMatch = matchesCategory(card.getAttribute('data-plugin-type'));
var show = searchMatch && filterMatch && categoryMatch;
card.style.display = show ? '' : 'none';
if (show) visibleCount++;
});
@@ -2065,17 +2221,23 @@ function filterInstalledPlugins() {
var desc = (row.getAttribute('data-plugin-desc') || '').toLowerCase();
var type = (row.getAttribute('data-plugin-type') || '').toLowerCase();
var combined = name + ' ' + desc + ' ' + type;
var show = terms.length === 0 || terms.every(function(term) { return combined.indexOf(term) !== -1; });
var searchMatch = terms.length === 0 || terms.every(function(term) { return combined.indexOf(term) !== -1; });
var installed = row.getAttribute('data-installed') || 'false';
var enabled = row.getAttribute('data-enabled') || 'false';
var filterMatch = matchesFilter(installed, enabled);
var categoryMatch = matchesCategory(row.getAttribute('data-plugin-type'));
var show = searchMatch && filterMatch && categoryMatch;
row.style.display = show ? '' : 'none';
if (show) visibleCount++;
});
}
}
var hasFilterOrSearch = terms.length > 0 || (filter !== 'all') || (cat !== 'all');
if (noResultsGrid) {
noResultsGrid.style.display = (terms.length > 0 && visibleCount === 0) ? 'block' : 'none';
noResultsGrid.style.display = (hasFilterOrSearch && visibleCount === 0) ? 'block' : 'none';
}
if (noResultsTable) {
noResultsTable.style.display = (terms.length > 0 && visibleCount === 0) ? 'table-row' : 'none';
noResultsTable.style.display = (hasFilterOrSearch && visibleCount === 0) ? 'table-row' : 'none';
}
}
@@ -2176,6 +2338,30 @@ function toggleAlphabetFilter() {
toggleBtn.setAttribute('aria-expanded', isExpanded ? 'false' : 'true');
}
function toggleInstalledCategoryFilter() {
const filter = document.getElementById('installedCategoryFilter');
const toggleBtn = document.getElementById('installedCategoryToggleBtn');
if (!filter || !toggleBtn) return;
const isExpanded = toggleBtn.getAttribute('aria-expanded') === 'true';
filter.style.display = isExpanded ? 'none' : 'block';
filter.setAttribute('aria-hidden', isExpanded ? 'true' : 'false');
toggleBtn.setAttribute('aria-expanded', isExpanded ? 'false' : 'true');
}
function filterByCategoryInstalled(category, evt) {
currentInstalledCategory = category;
const btns = document.querySelectorAll('.installed-category-btn');
btns.forEach(function(btn) { btn.classList.remove('active'); });
const clickedBtn = evt && (evt.currentTarget || (evt.target && evt.target.closest('.installed-category-btn')));
if (clickedBtn) clickedBtn.classList.add('active');
else {
btns.forEach(function(btn) {
if ((btn.getAttribute('data-category') || '') === category) btn.classList.add('active');
});
}
try { filterInstalledPlugins(); } catch (e) { console.warn('filterByCategoryInstalled', e); }
}
function upgradePlugin(pluginName, currentVersion, newVersion) {
// Show confirmation dialog with backup warning
const message = `⚠️ WARNING: Plugin Upgrade\n\n` +
@@ -2386,43 +2572,54 @@ function installPlugin(pluginName) {
btn.disabled = true;
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Installing...';
fetch(`/plugins/api/install/${pluginName}/`, {
method: 'POST',
headers: {
'X-CSRFToken': getCookie('csrftoken'),
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
location.reload();
} else {
if (typeof PNotify !== 'undefined') {
new PNotify({
title: 'Installation Failed!',
text: data.error || 'Failed to install plugin',
type: 'error'
});
} else {
alert('Error: ' + (data.error || 'Failed to install plugin'));
}
btn.disabled = false;
btn.innerHTML = originalText;
}
})
.catch(error => {
const headers = {
'X-CSRFToken': getCookie('csrftoken'),
'Content-Type': 'application/json'
};
function showError(msg) {
if (typeof PNotify !== 'undefined') {
new PNotify({
title: 'Error!',
text: 'Failed to install plugin: ' + error.message,
type: 'error'
});
new PNotify({ title: 'Installation Failed!', text: msg || 'Failed to install plugin', type: 'error' });
} else {
alert('Error: Failed to install plugin - ' + error.message);
alert('Error: ' + (msg || 'Failed to install plugin'));
}
btn.disabled = false;
btn.innerHTML = originalText;
}
function tryLocalInstall() {
return fetch(`/plugins/api/install/${pluginName}/`, { method: 'POST', headers: headers })
.then(function(r) { return r.json().then(function(data) { return { response: r, data: data }; }); });
}
function tryStoreInstall() {
return fetch(`/plugins/api/store/install/${pluginName}/`, { method: 'POST', headers: headers })
.then(function(r) { return r.json().then(function(data) { return { response: r, data: data }; }); });
}
tryLocalInstall()
.then(function(result) {
if (result.data.success) {
location.reload();
return;
}
var err = result.data.error || '';
if (result.response.status === 404 || (err && err.indexOf('Plugin source not found') !== -1)) {
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Installing from store...';
return tryStoreInstall();
}
showError(err);
})
.then(function(result) {
if (!result || !result.data) return;
if (result.data.success) {
location.reload();
} else {
showError(result.data.error || 'Failed to install plugin');
}
})
.catch(function(error) {
showError(error && error.message ? error.message : 'Failed to install plugin');
});
}
@@ -2978,7 +3175,14 @@ document.addEventListener('DOMContentLoaded', function() {
// Set initial view without updating hash (only update hash if there was already one)
const hadHash = hash.length > 0;
toggleView(initialView, hadHash);
try {
toggleView(initialView, hadHash);
} catch (e) {
console.warn('plugins: toggleView on load failed', e);
if (storeView) storeView.style.display = 'block';
if (gridView) gridView.style.display = 'none';
if (tableView) tableView.style.display = 'none';
}
} else {
// Elements don't exist (no plugins installed), just show store view directly
if (storeView) {

View File

@@ -13,10 +13,17 @@ from django.urls import path, include
import os
import sys
# Ensure plugin roots are on sys.path first so __import__(plugin_name + '.urls') can find packages
_INSTALLED_PLUGINS_PATH = '/usr/local/CyberCP'
_PLUGIN_SOURCE_PATHS = ['/home/cyberpanel/plugins', '/home/cyberpanel-plugins']
for _p in [_INSTALLED_PLUGINS_PATH] + _PLUGIN_SOURCE_PATHS:
if _p and os.path.isdir(_p) and _p not in sys.path:
sys.path.insert(0, _p)
from . import views
# Installed plugins live under this path (must match pluginInstaller and pluginHolder.views)
INSTALLED_PLUGINS_PATH = '/usr/local/CyberCP'
INSTALLED_PLUGINS_PATH = _INSTALLED_PLUGINS_PATH
# Source paths for plugins (same as pluginHolder.views PLUGIN_SOURCE_PATHS)
# Checked when plugin is not under INSTALLED_PLUGINS_PATH so URLs still work
@@ -95,29 +102,30 @@ urlpatterns = [
path('api/store/upgrade/<str:plugin_name>/', views.upgrade_plugin, name='upgrade_plugin'),
path('api/backups/<str:plugin_name>/', views.get_plugin_backups, name='get_plugin_backups'),
path('api/revert/<str:plugin_name>/', views.revert_plugin, name='revert_plugin'),
path('<str:plugin_name>/help/', views.plugin_help, name='plugin_help'),
path('api/debug-plugins/', views.debug_loaded_plugins, name='debug_loaded_plugins'),
]
# Dynamically include each installed plugin's URLs so /plugins/<plugin_name>/settings/ etc. work
# Only include plugins that are in INSTALLED_APPS so Django can load their models.
from django.conf import settings
_installed_apps = getattr(settings, 'INSTALLED_APPS', ())
# Include each installed plugin's URLs *before* the catch-all so /plugins/<name>/settings/ etc. match
_loaded_plugins = []
_failed_plugins = {}
for _plugin_name, _path_parent in _get_installed_plugin_list():
if _plugin_name not in _installed_apps:
continue
try:
# If plugin is from a source path, ensure it is on sys.path so import works
if _path_parent not in sys.path:
sys.path.insert(0, _path_parent)
__import__(_plugin_name + '.urls')
urlpatterns.append(path(_plugin_name + '/', include(_plugin_name + '.urls')))
except (ImportError, AttributeError) as e:
_loaded_plugins.append(_plugin_name)
except Exception as e:
import traceback
_failed_plugins[_plugin_name] = str(e)
try:
from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as _logging
_logging.writeToFile(
'pluginHolder.urls: Skipping plugin "%s" (urls not loadable): %s'
% (_plugin_name, e)
)
_logging.writeToFile(traceback.format_exc())
except Exception:
pass
urlpatterns.append(path('<str:plugin_name>/help/', views.plugin_help, name='plugin_help'))

View File

@@ -5,6 +5,7 @@ from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods
from plogical.mailUtilities import mailUtilities
import os
import shutil
import subprocess
import shlex
import json
@@ -42,6 +43,17 @@ PLUGIN_SOURCE_PATHS = ['/home/cyberpanel/plugins', '/home/cyberpanel-plugins']
# These plugins show "Built-in" badge and only Settings button (no Deactivate/Uninstall)
BUILTIN_PLUGINS = frozenset(['emailMarketing', 'emailPremium'])
# Core CyberPanel app dirs under /usr/local/CyberCP that must not be counted as "installed plugins"
# (matches pluginHolder.urls so Installed count = store/plugin dirs only, not core apps)
RESERVED_PLUGIN_DIRS = frozenset([
'api', 'backup', 'baseTemplate', 'cloudAPI', 'CLManager', 'containerization', 'CyberCP',
'databases', 'dns', 'dockerManager', 'emailMarketing', 'emailPremium', 'filemanager',
'firewall', 'ftp', 'highAvailability', 'IncBackups', 'loginSystem', 'mailServer',
'managePHP', 'manageSSL', 'manageServices', 'packages', 'pluginHolder', 'plogical',
'pluginInstaller', 'serverLogs', 'serverStatus', 's3Backups', 'tuning', 'userManagment',
'websiteFunctions', 'aiScanner', 'dns', 'help', 'installed',
])
def _get_plugin_source_path(plugin_name):
"""Return the full path to a plugin's source directory, or None if not found."""
for base in PLUGIN_SOURCE_PATHS:
@@ -51,6 +63,30 @@ def _get_plugin_source_path(plugin_name):
return path
return None
def _ensure_plugin_meta_xml(plugin_name):
"""
If plugin is installed (directory exists) but meta.xml is missing,
restore it from source or from GitHub so the grid and version checks work.
"""
installed_dir = os.path.join('/usr/local/CyberCP', plugin_name)
installed_meta = os.path.join(installed_dir, 'meta.xml')
if not os.path.isdir(installed_dir) or os.path.exists(installed_meta):
return
source_path = _get_plugin_source_path(plugin_name)
if source_path:
source_meta = os.path.join(source_path, 'meta.xml')
if os.path.exists(source_meta):
try:
shutil.copy2(source_meta, installed_meta)
logging.writeToFile(f"Restored meta.xml for {plugin_name} from source")
except Exception as e:
logging.writeToFile(f"Could not restore meta.xml for {plugin_name}: {e}")
return
try:
_sync_meta_xml_from_github(plugin_name)
except Exception:
pass
def _get_plugin_state_file(plugin_name):
"""Get the path to the plugin state file"""
if not os.path.exists(PLUGIN_STATE_DIR):
@@ -121,6 +157,15 @@ def installed(request):
errorPlugins = []
processed_plugins = set() # Track which plugins we've already processed
# Repair pass: ensure every installed plugin dir has meta.xml (from source or GitHub) so counts and grid are correct
if os.path.exists(installedPath):
for plugin in os.listdir(installedPath):
if plugin.startswith('.') or plugin in RESERVED_PLUGIN_DIRS:
continue
plugin_dir = os.path.join(installedPath, plugin)
if os.path.isdir(plugin_dir):
_ensure_plugin_meta_xml(plugin)
# First, process plugins from source directories (multiple paths: /home/cyberpanel/plugins, /home/cyberpanel-plugins)
# BUT: Skip plugins that are already installed - we'll process those from the installed location instead
for pluginPath in PLUGIN_SOURCE_PATHS:
@@ -134,20 +179,20 @@ def installed(request):
for plugin in os.listdir(pluginPath):
if plugin in processed_plugins:
continue
# Skip if plugin is already installed - we'll process it from installed location instead
completePath = installedPath + '/' + plugin + '/meta.xml'
if os.path.exists(completePath):
# Plugin is installed, skip source path - DON'T mark as processed yet
# The installed location loop will handle it and mark it as processed
continue
# Skip files (like .zip files) - only process directories
pluginDir = os.path.join(pluginPath, plugin)
if not os.path.isdir(pluginDir):
continue
# Use same "installed" criterion as install endpoint: plugin directory in /usr/local/CyberCP/
installed_dir = os.path.join(installedPath, plugin)
completePath = os.path.join(installedPath, plugin, 'meta.xml')
if os.path.exists(completePath):
# Plugin is fully installed (dir + meta.xml), skip - second loop will add it
continue
data = {}
# Try installed location first, then fallback to source location
completePath = installedPath + '/' + plugin + '/meta.xml'
sourcePath = os.path.join(pluginDir, 'meta.xml')
# Determine which meta.xml to use
@@ -200,9 +245,9 @@ def installed(request):
data['plugin_dir'] = plugin # Plugin directory name
# Set builtin flag (core CyberPanel plugins vs user-installable plugins)
data['builtin'] = plugin in BUILTIN_PLUGINS
# Check if plugin is installed (only if it exists in /usr/local/CyberCP/)
# Source directory presence doesn't mean installed - it just means the source files are available
data['installed'] = os.path.exists(completePath)
# Installed = plugin directory exists (must match install endpoint which uses directory existence)
# Fixes grid showing "Not Installed" when directory exists but meta.xml is missing
data['installed'] = os.path.isdir(installed_dir)
# Get plugin enabled state (only for installed plugins)
if data['installed']:
@@ -247,11 +292,9 @@ def installed(request):
# Special handling for emailMarketing
if plugin == 'emailMarketing':
data['manage_url'] = '/emailMarketing/'
elif os.path.exists(completePath):
# Check if settings route exists, otherwise use main plugin URL
settings_route = f'/plugins/{plugin}/settings/'
elif data['installed']:
# Plugin directory exists; use main plugin URL
main_route = f'/plugins/{plugin}/'
# Default to main route - most plugins have a main route even if no settings
data['manage_url'] = main_route
else:
data['manage_url'] = None
@@ -282,20 +325,14 @@ def installed(request):
errorPlugins.append({'name': plugin, 'error': f'XML parse error: {str(e)}'})
logging.writeToFile(f"Plugin {plugin}: XML parse error - {str(e)}")
# Don't mark as processed if it failed - let installed check handle it
# This ensures plugins that exist in /usr/local/CyberCP/ but have bad source meta.xml still get counted
if not os.path.exists(completePath):
# Only skip if it's not actually installed
if not os.path.isdir(installed_dir):
continue
# If it exists in installed location, don't mark as processed so it gets checked there
continue
except Exception as e:
errorPlugins.append({'name': plugin, 'error': f'Error loading plugin: {str(e)}'})
logging.writeToFile(f"Plugin {plugin}: Error loading - {str(e)}")
# Don't mark as processed if it failed - let installed check handle it
if not os.path.exists(completePath):
# Only skip if it's not actually installed
if not os.path.isdir(installed_dir):
continue
# If it exists in installed location, don't mark as processed so it gets checked there
continue
# Also check for installed plugins that don't have source directories
@@ -311,6 +348,7 @@ def installed(request):
if not os.path.isdir(pluginInstalledDir):
continue
_ensure_plugin_meta_xml(plugin)
metaXmlPath = os.path.join(pluginInstalledDir, 'meta.xml')
if not os.path.exists(metaXmlPath):
continue
@@ -475,29 +513,30 @@ def installed(request):
except Exception as e:
logging.writeToFile(f"Plugin {plugin_name} fallback load error: {str(e)}")
# Calculate installed and active counts
# Double-check by also counting plugins that actually exist in /usr/local/CyberCP/
# Calculate installed and active counts: only count real plugins (have meta.xml, not core apps)
installed_plugins_in_filesystem = set()
if os.path.exists(installedPath):
for plugin in os.listdir(installedPath):
if plugin.startswith('.') or plugin in RESERVED_PLUGIN_DIRS:
continue
pluginInstalledDir = os.path.join(installedPath, plugin)
if os.path.isdir(pluginInstalledDir):
metaXmlPath = os.path.join(pluginInstalledDir, 'meta.xml')
if os.path.exists(metaXmlPath):
installed_plugins_in_filesystem.add(plugin)
if not os.path.isdir(pluginInstalledDir):
continue
if not os.path.exists(os.path.join(pluginInstalledDir, 'meta.xml')):
continue
installed_plugins_in_filesystem.add(plugin)
# Count installed plugins from the list
installed_count = len([p for p in pluginList if p.get('installed', False)])
active_count = len([p for p in pluginList if p.get('installed', False) and p.get('enabled', False)])
# If there's a discrepancy, use the filesystem count as the source of truth
# Use the larger of list count and filesystem count so header never shows less than grid
filesystem_installed_count = len(installed_plugins_in_filesystem)
if filesystem_installed_count != installed_count:
logging.writeToFile(f"WARNING: Plugin count mismatch! List says {installed_count}, filesystem has {filesystem_installed_count}")
logging.writeToFile(f"Plugins in filesystem: {sorted(installed_plugins_in_filesystem)}")
logging.writeToFile(f"Plugins in list with installed=True: {[p.get('plugin_dir') for p in pluginList if p.get('installed', False)]}")
# Use filesystem count as source of truth
installed_count = filesystem_installed_count
list_installed_count = len([p for p in pluginList if p.get('installed', False)])
if filesystem_installed_count != list_installed_count:
logging.writeToFile(f"Plugin count: list installed={list_installed_count}, filesystem with meta.xml={filesystem_installed_count}")
installed_count = max(list_installed_count, filesystem_installed_count)
if active_count > installed_count:
active_count = installed_count
# Debug logging to help identify discrepancies
logging.writeToFile(f"Plugin count: Total={len(pluginList)}, Installed={installed_count}, Active={active_count}")
@@ -609,6 +648,7 @@ def install_plugin(request, plugin_name):
# Set plugin to enabled by default after installation
_set_plugin_state(plugin_name, True)
_ensure_plugin_meta_xml(plugin_name)
logging.writeToFile(f"Plugin {plugin_name} installed successfully (upload)")
return JsonResponse({
'success': True,
@@ -1783,6 +1823,7 @@ def install_from_store(request, plugin_name):
# Set plugin to enabled by default after installation
_set_plugin_state(plugin_name, True)
_ensure_plugin_meta_xml(plugin_name)
return JsonResponse({
'success': True,
'message': f'Plugin {plugin_name} installed successfully from store'
@@ -1813,6 +1854,24 @@ def install_from_store(request, plugin_name):
'error': str(e)
}, status=500)
@csrf_exempt
@require_http_methods(["GET"])
def debug_loaded_plugins(request):
"""Return which plugins have URL routes loaded and which failed (for diagnosing 404s)."""
try:
import pluginHolder.urls as urls_mod
loaded = list(getattr(urls_mod, '_loaded_plugins', []))
failed = dict(getattr(urls_mod, '_failed_plugins', {}))
return JsonResponse({
'success': True,
'loaded': loaded,
'failed': failed,
'loaded_count': len(loaded),
'failed_count': len(failed),
}, json_dumps_params={'indent': 2})
except Exception as e:
return JsonResponse({'success': False, 'error': str(e)}, status=500)
def plugin_help(request, plugin_name):
"""Plugin-specific help page - shows plugin information, version history, and help content"""
mailUtilities.checkHome()

View File

@@ -24,7 +24,10 @@ fi
echo "Upgrading CyberPanel from branch: $BRANCH_NAME"
rm -f /usr/local/cyberpanel_upgrade.sh
wget -O /usr/local/cyberpanel_upgrade.sh https://raw.githubusercontent.com/usmannasir/cyberpanel/$BRANCH_NAME/cyberpanel_upgrade.sh 2>/dev/null
# Use same repo as this script (master3395); fallback to usmannasir for compatibility. Prefer curl with no-cache so --mariadb-version is respected.
curl -sL -H 'Cache-Control: no-cache' -H 'Pragma: no-cache' -o /usr/local/cyberpanel_upgrade.sh "https://raw.githubusercontent.com/master3395/cyberpanel/$BRANCH_NAME/cyberpanel_upgrade.sh" 2>/dev/null || \
wget -q -O /usr/local/cyberpanel_upgrade.sh "https://raw.githubusercontent.com/master3395/cyberpanel/$BRANCH_NAME/cyberpanel_upgrade.sh" 2>/dev/null || \
wget -q -O /usr/local/cyberpanel_upgrade.sh "https://raw.githubusercontent.com/usmannasir/cyberpanel/$BRANCH_NAME/cyberpanel_upgrade.sh" 2>/dev/null
chmod 700 /usr/local/cyberpanel_upgrade.sh
# Pass -b so upgrade script skips branch prompt and uses our branch
# Pass -b and all extra args (e.g. --mariadb-version 12.3, --backup-db, --no-backup-db) to upgrade script
/usr/local/cyberpanel_upgrade.sh -b "$BRANCH_NAME" $EXTRA_ARGS

View File

@@ -0,0 +1,48 @@
# CyberPanel Upgrade Script - Modular Layout for Debugging
## Goal
Split `cyberpanel_upgrade.sh` into modules under `upgrade_modules/` so each file is under 500 lines and easier to debug.
## Directory Layout
- `upgrade_modules/00_common.sh` - Debug_Log, Debug_Log2, Branch_Check, Check_Return, Regenerate_Cert, Retry_Command (DONE)
- `upgrade_modules/01_variables.sh` - Set_Default_Variables (DONE)
- `upgrade_modules/02_checks.sh` - Check_Root, Check_Server_IP, Check_OS, Check_Provider, Check_Argument
- `upgrade_modules/03_mariadb.sh` - Pre_Upgrade_CentOS7_MySQL, Maybe_Backup_MariaDB_Before_Upgrade, Backup_MariaDB_Before_Upgrade, Migrate_MariaDB_To_UTF8
- `upgrade_modules/04_git_url.sh` - Pre_Upgrade_Setup_Git_URL
- `upgrade_modules/05_repository.sh` - Pre_Upgrade_Setup_Repository (~490 lines)
- `upgrade_modules/06_components.sh` - Download_Requirement, Pre_Upgrade_Required_Components
- `upgrade_modules/07_branch_input.sh` - Pre_Upgrade_Branch_Input
- `upgrade_modules/08_main_upgrade.sh` - Main_Upgrade
- `upgrade_modules/09_sync.sh` - Sync_CyberCP_To_Latest
- `upgrade_modules/10_post_tweak.sh` - Post_Upgrade_System_Tweak
- `upgrade_modules/11_display_final.sh` - Post_Install_Display_Final_Info, _br, _bl, _b
## Line Ranges in Current Script
- 00_common: 99-106, 237-263, 264-337
- 01_variables: 27-98
- 02_checks: 107-148, 149-206, 207-236, 352-399
- 03_mariadb: 425-520
- 04_git_url: 400-424
- 05_repository: 521-1011
- 06_components: 1012-1298
- 07_branch_input: 1299-1311
- 08_main_upgrade: 1312-1649
- 09_sync: 1650-1688
- 10_post_tweak: 1691-2023
- 11_display_final: 2024-2118
## Main Script After Refactor
1. Root check, Sudo_Test
2. If upgrade_modules/ exists: source each 00-11; else (one-liner) download modules from GitHub by branch and source
3. Set_Default_Variables, Check_Root, Check_Server_IP, Check_OS, Check_Provider, Check_Argument
4. Branch and MariaDB prompts
5. Pre_Upgrade_Setup_Repository, Pre_Upgrade_Setup_Git_URL, Pre_Upgrade_Required_Components
6. Main_Upgrade, Sync_CyberCP_To_Latest, Post_Upgrade_System_Tweak, Post_Install_Display_Final_Info
## Status
Done: 00_common.sh, 01_variables.sh. Remaining: create 02-11 and refactor main script to loader.

View File

@@ -0,0 +1,104 @@
#!/usr/bin/env bash
# CyberPanel upgrade common helpers (logging, check return, retry, branch check).
# Sourced by cyberpanel_upgrade.sh. Do not run standalone.
Debug_Log() {
echo -e "\n${1}=${2}\n" >> "/var/log/cyberpanel_debug_upgrade_$(date +"%Y-%m-%d")_${Random_Log_Name}.log"
}
Debug_Log2() {
echo -e "\n${1}" >> /var/log/upgradeLogs.txt
}
Branch_Check() {
if [[ "$1" = *.*.* ]]; then
Output=$(awk -v num1="$Base_Number" -v num2="${1//[[:space:]]/}" '
BEGIN {
print "num1", (num1 < num2 ? "<" : ">="), "num2"
}
')
if [[ $Output = *">="* ]]; then
echo -e "\nYou must use version number higher than 2.3.4"
exit
else
raw="${1//[[:space:]]/}"
if [[ "$raw" = v* ]]; then
Branch_Name="$raw"
else
Branch_Name="v$raw"
fi
echo -e "\nSet branch name to $Branch_Name...\n"
fi
else
echo -e "\nPlease input a valid format version number."
exit
fi
}
Check_Return() {
local LAST_EXIT_CODE=$?
if [[ $LAST_EXIT_CODE != "0" ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] ERROR: Command failed with exit code: $LAST_EXIT_CODE" | tee -a /var/log/cyberpanel_upgrade_debug.log
if [[ -n "$1" ]] ; then
echo -e "\n\n\n$1"
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Error message: $1" | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
echo -e "above command failed..."
Debug_Log2 "command failed. For more information read /var/log/installLogs.txt [404]"
if [[ "$2" = "no_exit" ]] || [[ "$3" = "continue" ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Continuing despite error..." | tee -a /var/log/cyberpanel_upgrade_debug.log
else
if [[ "$1" == *"Virtualenv creation failed"* ]] || [[ "$1" == *"Python upgrade.py"* ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] FATAL: Critical error, exiting" | tee -a /var/log/cyberpanel_upgrade_debug.log
exit $LAST_EXIT_CODE
else
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Non-critical error, continuing..." | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
fi
else
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Command succeeded" | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
}
Regenerate_Cert() {
cat <<EOF >/usr/local/CyberCP/cert_conf
[req]
prompt=no
distinguished_name=cyberpanel
[cyberpanel]
commonName = www.example.com
countryName = CP
localityName = CyberPanel
organizationName = CyberPanel
organizationalUnitName = CyberPanel
stateOrProvinceName = CP
emailAddress = mail@example.com
name = CyberPanel
surname = CyberPanel
givenName = CyberPanel
initials = CP
dnQualifier = CyberPanel
[server_exts]
extendedKeyUsage = 1.3.6.1.5.5.7.3.1
EOF
if [[ $1 == "8090" ]]; then
openssl req -x509 -config /usr/local/CyberCP/cert_conf -extensions 'server_exts' -nodes -days 820 -newkey rsa:2048 -keyout /usr/local/lscp/conf/key.pem -out /usr/local/lscp/conf/cert.pem
fi
if [[ $1 == "7080" ]]; then
if [[ -f /usr/local/lsws/admin/conf/webadmin.key ]]; then
key_path="/usr/local/lsws/admin/conf/webadmin.key"
cert_path="/usr/local/lsws/admin/conf/webadmin.crt"
else
key_path="/usr/local/lsws/admin/conf/cert/admin.key"
cert_path="/usr/local/lsws/admin/conf/cert/admin.crt"
fi
openssl req -x509 -config /usr/local/CyberCP/cert_conf -extensions 'server_exts' -nodes -days 820 -newkey rsa:2048 -keyout $key_path -out $cert_path
fi
rm -f /usr/local/CyberCP/cert_conf
}
Retry_Command() {
for i in {1..50}; do
eval "$1" && break || echo -e "\n$1 has failed for $i times\nWait for 3 seconds and try again...\n"; sleep 3;
done
}

View File

@@ -0,0 +1,61 @@
#!/usr/bin/env bash
# CyberPanel upgrade set default variables and paths.
# Sourced by cyberpanel_upgrade.sh.
Set_Default_Variables() {
echo -e "Clearing old log files..."
rm -f /var/log/cyberpanel_upgrade_debug.log
rm -f /var/log/installLogs.txt
rm -f /var/log/upgradeLogs.txt
echo -e "\n\n========================================" > /var/log/cyberpanel_upgrade_debug.log
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Starting CyberPanel Upgrade Script" >> /var/log/cyberpanel_upgrade_debug.log
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Old log files have been cleared" >> /var/log/cyberpanel_upgrade_debug.log
echo -e "========================================\n" >> /var/log/cyberpanel_upgrade_debug.log
rm -Rfv /usr/local/CyberCP/configservercsf 2>/dev/null || true
rm -fv /home/cyberpanel/plugins/configservercsf 2>/dev/null || true
rm -Rfv /usr/local/CyberCP/public/static/configservercsf 2>/dev/null || true
sed -i "/configservercsf/d" /usr/local/CyberCP/CyberCP/settings.py 2>/dev/null || true
sed -i "/configservercsf/d" /usr/local/CyberCP/CyberCP/urls.py 2>/dev/null || true
if [ ! -e /etc/cxs/cxs.pl ]; then
sed -i "/configserver/d" /usr/local/CyberCP/baseTemplate/templates/baseTemplate/index.html 2>/dev/null || true
fi
export LC_CTYPE=en_US.UTF-8
echo -e "\nFetching latest data from CyberPanel server...\n"
echo -e "This may take few seconds..."
Server_Country="Unknown"
Server_OS=""
Server_OS_Version=""
Server_Provider='Undefined'
Temp_Value=$(curl --silent --max-time 30 -4 https://cyberpanel.net/version.txt)
Panel_Version=${Temp_Value:12:3}
Panel_Build=${Temp_Value:25:1}
Branch_Name="v${Panel_Version}.${Panel_Build}"
Base_Number="1.9.3"
Git_User=""
Git_Content_URL=""
Git_Clone_URL=""
MySQL_Version=$(mariadb -V 2>/dev/null | grep -P '\d+.\d+.\d+' -o || mysql -V 2>/dev/null | grep -P '\d+.\d+.\d+' -o)
MySQL_Password=$(cat /etc/cyberpanel/mysqlPassword 2>/dev/null || echo "")
LSWS_Latest_URL="https://cyberpanel.sh/update.litespeedtech.com/ws/latest.php"
LSWS_Tmp=$(curl --silent --max-time 30 -4 "$LSWS_Latest_URL" 2>/dev/null)
LSWS_Stable_Line=$(echo "$LSWS_Tmp" | grep "LSWS_STABLE")
LSWS_Stable_Version=$(expr "$LSWS_Stable_Line" : '.*LSWS_STABLE=\(.*\) BUILD .*')
if [ -z "$LSWS_Stable_Version" ]; then
LSWS_Stable_Version="6.3.4"
fi
Debug_Log2 "Starting Upgrade...1"
rm -rf /root/cyberpanel_upgrade_tmp
mkdir -p /root/cyberpanel_upgrade_tmp
cd /root/cyberpanel_upgrade_tmp || exit
}

View File

@@ -0,0 +1,189 @@
#!/usr/bin/env bash
# CyberPanel upgrade root, server IP, OS, provider, and argument checks. Sourced by cyberpanel_upgrade.sh.
Check_Root() {
echo -e "\nChecking root privileges..."
# If we're actually root (uid 0), allow regardless of SUDO in environment (e.g. curl | sudo bash)
if [[ $(id -u) -eq 0 ]] 2>/dev/null; then
echo -e "\nYou are running as root...\n"
return 0
fi
if echo "$Sudo_Test" | grep SUDO >/dev/null; then
echo -e "\nYou are using SUDO, please run as root user...\n"
echo -e "\nIf you don't have direct access to root user, please run \e[31msudo su -\e[39m command (do NOT miss the \e[31m-\e[39m at end or it will fail) and then run installation command again."
exit 1
fi
echo -e "\nYou must run as root user to install CyberPanel...\n"
echo -e "Run: \e[31msudo su -\e[39m then run this script again, or: curl -sL <url> | sudo bash -s -- <args>"
exit 1
}
Check_Server_IP() {
echo -e "Checking server location...\n"
Server_Country=$(curl --silent --max-time 10 -4 https://cyberpanel.sh/?country)
if [[ ${#Server_Country} != "2" ]] ; then
Server_Country="Unknown"
fi
if [[ "$Debug" = "On" ]] ; then
Debug_Log "Server_Country" "$Server_Country"
fi
if [[ "$*" = *"--mirror"* ]] ; then
Server_Country="CN"
echo -e "Forced to use mirror server due to --mirror argument...\n"
fi
if [[ "$Server_Country" = *"CN"* ]] ; then
Server_Country="CN"
echo -e "Setting up to use mirror server...\n"
fi
}
Check_OS() {
if [[ ! -f /etc/os-release ]] ; then
echo -e "Unable to detect the Operating System...\n"
exit
fi
if ! uname -m | grep -qE 'x86_64|aarch64' ; then
echo -e "x86_64 or ARM system is required...\n"
exit
fi
if grep -q -E "CentOS Linux 7|CentOS Linux 8|CentOS Linux 9|CentOS Stream 9" /etc/os-release ; then
Server_OS="CentOS"
elif grep -q "Red Hat Enterprise Linux" /etc/os-release ; then
Server_OS="RedHat"
elif grep -q -E "CloudLinux 7|CloudLinux 8|CloudLinux 9" /etc/os-release ; then
Server_OS="CloudLinux"
elif grep -q -E "Rocky Linux" /etc/os-release ; then
Server_OS="RockyLinux"
elif grep -q -E "AlmaLinux-8|AlmaLinux-9|AlmaLinux-10" /etc/os-release ; then
Server_OS="AlmaLinux"
# Set specific version for AlmaLinux 9+ to use dnf instead of yum
if grep -q -E "AlmaLinux-9|AlmaLinux-10" /etc/os-release ; then
Server_OS="AlmaLinux9"
fi
elif grep -q -E "Ubuntu 18.04|Ubuntu 20.04|Ubuntu 20.10|Ubuntu 22.04|Ubuntu 24.04|Ubuntu 24.04.3" /etc/os-release ; then
Server_OS="Ubuntu"
elif grep -q -E "Debian GNU/Linux 11|Debian GNU/Linux 12|Debian GNU/Linux 13" /etc/os-release ; then
Server_OS="Ubuntu"
elif grep -q -E "openEuler 20.03|openEuler 22.03" /etc/os-release ; then
Server_OS="openEuler"
else
echo -e "Unable to detect your system..."
echo -e "\nCyberPanel is supported on x86_64 based Ubuntu 18.04, Ubuntu 20.04, Ubuntu 20.10, Ubuntu 22.04, Ubuntu 24.04, Ubuntu 24.04.3, Debian 11, Debian 12, Debian 13, CentOS 7, CentOS 8, CentOS 9, CentOS Stream 9, AlmaLinux 8, AlmaLinux 9, AlmaLinux 10, RockyLinux 8, RockyLinux 9, RHEL 8, RHEL 9, CloudLinux 7, CloudLinux 8, CloudLinux 9, openEuler 20.03, openEuler 22.03...\n"
Debug_Log2 "CyberPanel is supported on x86_64 based Ubuntu 18.04, Ubuntu 20.04, Ubuntu 20.10, Ubuntu 22.04, Ubuntu 24.04, Ubuntu 24.04.3, Debian 11, Debian 12, Debian 13, CentOS 7, CentOS 8, CentOS 9, CentOS Stream 9, AlmaLinux 8, AlmaLinux 9, AlmaLinux 10, RockyLinux 8, RockyLinux 9, RHEL 8, RHEL 9, CloudLinux 7, CloudLinux 8, CloudLinux 9, openEuler 20.03, openEuler 22.03... [404]"
exit
fi
Server_OS_Version=$(grep VERSION_ID /etc/os-release | awk -F[=,] '{print $2}' | tr -d \" | head -c2 | tr -d . )
#to make 20.04 display as 20, etc.
echo -e "System: $Server_OS $Server_OS_Version detected...\n"
if [[ $Server_OS = "CloudLinux" ]] || [[ "$Server_OS" = "AlmaLinux" ]] || [[ "$Server_OS" = "RockyLinux" ]] || [[ "$Server_OS" = "RedHat" ]]; then
# Keep AlmaLinux9 separate for dnf package management
if [[ "$Server_OS" != "AlmaLinux9" ]]; then
Server_OS="CentOS"
#CloudLinux gives version id like 7.8, 7.9, so cut it to show first number only
#treat CloudLinux, Rocky and Alma as CentOS
fi
fi
if [[ "$Debug" = "On" ]] ; then
Debug_Log "Server_OS" "$Server_OS $Server_OS_Version"
fi
}
Check_Provider() {
if hash dmidecode >/dev/null 2>&1; then
if [[ "$(dmidecode -s bios-vendor)" = "Google" ]]; then
Server_Provider="Google Cloud Platform"
elif [[ "$(dmidecode -s bios-vendor)" = "DigitalOcean" ]]; then
Server_Provider="Digital Ocean"
elif [[ "$(dmidecode -s system-product-name | cut -c 1-7)" = "Alibaba" ]]; then
Server_Provider="Alibaba Cloud"
elif [[ "$(dmidecode -s system-manufacturer)" = "Microsoft Corporation" ]]; then
Server_Provider="Microsoft Azure"
elif [[ -d /usr/local/qcloud ]]; then
Server_Provider="Tencent Cloud"
else
Server_Provider="Undefined"
fi
else
Server_Provider='Undefined'
fi
if [[ -f /sys/devices/virtual/dmi/id/product_uuid ]]; then
if [[ "$(cut -c 1-3 /sys/devices/virtual/dmi/id/product_uuid)" = 'EC2' ]] && [[ -d /home/ubuntu ]]; then
Server_Provider='Amazon Web Service'
fi
fi
if [[ "$Debug" = "On" ]] ; then
Debug_Log "Server_Provider" "$Server_Provider"
fi
}
Skip_System_Update=""
# Migrate MariaDB from latin1 to utf8mb4 after upgrade (only when --migrate-to-utf8 and upgrading to 11.x/12.x)
Migrate_MariaDB_To_UTF8_Requested=""
# MariaDB version: any X.Y or X.Y.Z supported; highlighted: 10.11.16, 11.8 LTS, 12.x (default 11.8)
MARIADB_VER="11.8"
MARIADB_VER_REPO="11.8"
Check_Argument() {
# Parse --branch / -b (extract first word after -b or --branch)
if [[ "$*" = *"--branch "* ]]; then
Branch_Name=$(echo "$*" | sed -n 's/.*--branch \([^ ]*\).*/\1/p' | head -1)
[[ -n "$Branch_Name" ]] && Branch_Check "$Branch_Name"
elif [[ "$*" = *"-b "* ]]; then
Branch_Name=$(echo "$*" | sed -n 's/.*-b \([^ ]*\).*/\1/p' | head -1)
[[ -n "$Branch_Name" ]] && Branch_Check "$Branch_Name"
fi
# Parse --repo / -r to use any GitHub user (same URL structure as usmannasir/cyberpanel)
if [[ "$*" = *"--repo "* ]]; then
Git_User_Override=$(echo "$*" | sed -n 's/.*--repo \([^ ]*\).*/\1/p' | head -1)
fi
if [[ "$*" = *"-r "* ]] && [[ -z "$Git_User_Override" ]]; then
Git_User_Override=$(echo "$*" | sed -n 's/.*-r \([^ ]*\).*/\1/p' | head -1)
fi
# Parse --no-system-update to skip yum/dnf update -y (faster upgrade when system is already updated)
if [[ "$*" = *"--no-system-update"* ]]; then
Skip_System_Update="yes"
echo -e "\nUsing --no-system-update: skipping full system package update.\n"
fi
# Parse --backup-db / --no-backup-db: pre-upgrade MariaDB backup. Default when neither set: ask user (may take a while).
# --backup-db = always backup; --no-backup-db = never backup; omit both = prompt [y/N]
Backup_DB_Before_Upgrade=""
if [[ "$*" = *"--backup-db"* ]]; then
Backup_DB_Before_Upgrade="yes"
echo -e "\nUsing --backup-db: will create a full MariaDB backup before upgrade.\n"
elif [[ "$*" = *"--no-backup-db"* ]]; then
Backup_DB_Before_Upgrade="no"
echo -e "\nUsing --no-backup-db: skipping MariaDB pre-upgrade backup.\n"
fi
# Parse --migrate-to-utf8: after upgrading to MariaDB 11.x/12.x, convert DBs/tables from latin1 to utf8mb4 (only if your apps support UTF-8)
if [[ "$*" = *"--migrate-to-utf8"* ]]; then
Migrate_MariaDB_To_UTF8_Requested="yes"
echo -e "\nUsing --migrate-to-utf8: will convert databases to UTF-8 (utf8mb4) after MariaDB upgrade.\n"
fi
# Parse --mariadb-version (any version: 10.6, 10.11, 10.11.16, 11.8, 12.1, 12.2, 12.3, etc.). Default 11.8.
# --mariadb is shorthand for --mariadb-version 10.11
if [[ "$*" = *"--mariadb"* ]] && [[ "$*" != *"--mariadb-version "* ]]; then
MARIADB_VER="10.11"
echo -e "\nUsing --mariadb: MariaDB 10.11 selected (non-interactive).\n"
elif [[ "$*" = *"--mariadb-version "* ]]; then
MARIADB_VER=$(echo "$*" | sed -n 's/.*--mariadb-version \([^ ]*\).*/\1/p' | head -1)
MARIADB_VER="${MARIADB_VER:-11.8}"
fi
# Allow any version; repo paths use major.minor (normalized later)
}

View File

@@ -0,0 +1,88 @@
#!/usr/bin/env bash
# CyberPanel upgrade MariaDB backup, optional UTF-8 migration, CentOS 7 MySQL upgrade.
# Sourced by cyberpanel_upgrade.sh.
Pre_Upgrade_CentOS7_MySQL() {
if [[ "$MySQL_Version" = "10.1" ]]; then
cp /etc/my.cnf /etc/my.cnf.bak
mkdir /etc/cnfbackup
cp -R /etc/my.cnf.d/ /etc/cnfbackup/
yum remove MariaDB-server MariaDB-client galera -y
yum --enablerepo=mariadb -y install MariaDB-server MariaDB-client galera
cp -f /etc/my.cnf.bak /etc/my.cnf
rm -rf /etc/my.cnf.d/
mv /etc/cnfbackup/my.cnf.d /etc/
systemctl enable mariadb 2>/dev/null || systemctl enable mysql
systemctl start mariadb 2>/dev/null || systemctl start mysql
mariadb-upgrade -uroot -p"$MySQL_Password" 2>/dev/null || mysql_upgrade -uroot -p"$MySQL_Password"
fi
mariadb -uroot -p"$MySQL_Password" -e "GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY '$MySQL_Password';flush privileges" 2>/dev/null || mysql -uroot -p"$MySQL_Password" -e "GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY '$MySQL_Password';flush privileges"
}
Maybe_Backup_MariaDB_Before_Upgrade() {
if [[ "$Backup_DB_Before_Upgrade" = "no" ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] MariaDB pre-upgrade backup: skipped (--no-backup-db)." | tee -a /var/log/cyberpanel_upgrade_debug.log
return 0
fi
if [[ "$Backup_DB_Before_Upgrade" = "" ]]; then
echo -e "\nDo you want to backup all databases before MariaDB upgrade? (may take a while) [y/N]: "
read -r -t 60 Tmp_Backup_Choice 2>/dev/null || Tmp_Backup_Choice=""
if [[ "$Tmp_Backup_Choice" =~ ^[yY] ]] || [[ "$Tmp_Backup_Choice" =~ ^[yY][eE][sS] ]]; then
Backup_DB_Before_Upgrade="yes"
else
Backup_DB_Before_Upgrade="no"
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] MariaDB pre-upgrade backup: skipped (user chose no or timeout)." | tee -a /var/log/cyberpanel_upgrade_debug.log
return 0
fi
fi
Backup_MariaDB_Before_Upgrade
}
Backup_MariaDB_Before_Upgrade() {
local pass="" backup_dir="/root/cyberpanel_mariadb_backups" backup_file=""
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Starting MariaDB pre-upgrade backup... (this may take a few minutes)" | tee -a /var/log/cyberpanel_upgrade_debug.log
[[ -f /etc/cyberpanel/mysqlPassword ]] || { echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] MariaDB pre-upgrade backup: skipped (no password file)." | tee -a /var/log/cyberpanel_upgrade_debug.log; return 0; }
if grep -q '"mysqlpassword"' /etc/cyberpanel/mysqlPassword 2>/dev/null; then
pass=$(python3 -c "import json; print(json.load(open('/etc/cyberpanel/mysqlPassword')).get('mysqlpassword',''))" 2>/dev/null)
else
pass=$(head -1 /etc/cyberpanel/mysqlPassword 2>/dev/null | tr -d '\r\n')
fi
[[ -z "$pass" ]] && echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] WARNING: Could not read MariaDB password, skipping pre-upgrade backup." | tee -a /var/log/cyberpanel_upgrade_debug.log && echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] MariaDB pre-upgrade backup: skipped." | tee -a /var/log/cyberpanel_upgrade_debug.log && return 0
mkdir -p "$backup_dir"
backup_file="${backup_dir}/mariadb_backup_before_upgrade_$(date +%Y%m%d_%H%M%S).sql.gz"
if mariadb --skip-ssl -u root -p"$pass" -e "SELECT 1" 2>/dev/null | grep -q 1; then
(mariadb-dump --skip-ssl -u root -p"$pass" --all-databases --single-transaction --routines --triggers --events 2>/dev/null || mysqldump --skip-ssl -u root -p"$pass" --all-databases --single-transaction --routines --triggers --events 2>/dev/null) | gzip > "$backup_file" 2>/dev/null
if [[ -s "$backup_file" ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] MariaDB backup created: $backup_file" | tee -a /var/log/cyberpanel_upgrade_debug.log
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] MariaDB pre-upgrade backup: done." | tee -a /var/log/cyberpanel_upgrade_debug.log
else
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] WARNING: MariaDB backup file empty or failed." | tee -a /var/log/cyberpanel_upgrade_debug.log
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] MariaDB pre-upgrade backup: skipped (dump failed)." | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
else
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] WARNING: Could not connect to MariaDB for backup (skip-ssl). Skipping backup." | tee -a /var/log/cyberpanel_upgrade_debug.log
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] MariaDB pre-upgrade backup: skipped (no connection)." | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
}
Migrate_MariaDB_To_UTF8() {
local pass="" dbs="" db="" t=""
[[ -f /etc/cyberpanel/mysqlPassword ]] || return 0
if grep -q '"mysqlpassword"' /etc/cyberpanel/mysqlPassword 2>/dev/null; then
pass=$(python3 -c "import json; print(json.load(open('/etc/cyberpanel/mysqlPassword')).get('mysqlpassword',''))" 2>/dev/null)
else
pass=$(head -1 /etc/cyberpanel/mysqlPassword 2>/dev/null | tr -d '\r\n')
fi
[[ -z "$pass" ]] && return 0
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Migrating MariaDB to UTF-8 (utf8mb4)..." | tee -a /var/log/cyberpanel_upgrade_debug.log
mariadb --skip-ssl -u root -p"$pass" -e "SET GLOBAL character_set_server = 'utf8mb4'; SET GLOBAL collation_server = 'utf8mb4_unicode_ci';" 2>/dev/null || true
dbs=$(mariadb --skip-ssl -u root -p"$pass" -sN -e "SHOW DATABASES;" 2>/dev/null) || true
for db in $dbs; do
[[ "$db" = "information_schema" ]] || [[ "$db" = "performance_schema" ]] || [[ "$db" = "sys" ]] || [[ "$db" = "mysql" ]] && continue
mariadb --skip-ssl -u root -p"$pass" -e "ALTER DATABASE \`$db\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" 2>/dev/null || true
for t in $(mariadb --skip-ssl -u root -p"$pass" -sN -e "SHOW TABLES FROM \`$db\`;" 2>/dev/null); do
mariadb --skip-ssl -u root -p"$pass" "$db" -e "ALTER TABLE \`$t\` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" 2>/dev/null || true
done
done
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] MariaDB UTF-8 (utf8mb4) migration completed." | tee -a /var/log/cyberpanel_upgrade_debug.log
}

View File

@@ -0,0 +1,27 @@
#!/usr/bin/env bash
# CyberPanel upgrade set Git content and clone URLs (usmannasir or override).
# Sourced by cyberpanel_upgrade.sh.
Pre_Upgrade_Setup_Git_URL() {
if [[ $Server_Country != "CN" ]] ; then
if [[ -n "$Git_User_Override" ]]; then
Git_User="$Git_User_Override"
echo -e "\nUsing GitHub repo: ${Git_User}/cyberpanel (same URL structure as usmannasir)\n"
else
Git_User="usmannasir"
fi
Git_Content_URL="https://raw.githubusercontent.com/${Git_User}/cyberpanel"
Git_Clone_URL="https://github.com/${Git_User}/cyberpanel.git"
else
if [[ -n "$Git_User_Override" ]]; then
Git_User="$Git_User_Override"
else
Git_User="qtwrk"
fi
Git_Content_URL="https://gitee.com/${Git_User}/cyberpanel/raw"
Git_Clone_URL="https://gitee.com/${Git_User}/cyberpanel.git"
fi
if [[ "$Debug" = "On" ]] ; then
Debug_Log "Git_URL" "$Git_Content_URL"
fi
}

View File

@@ -0,0 +1,494 @@
#!/usr/bin/env bash
# CyberPanel upgrade repository setup (CentOS/AlmaLinux/Ubuntu/openEuler). Sourced by cyberpanel_upgrade.sh.
Pre_Upgrade_Setup_Repository() {
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Pre_Upgrade_Setup_Repository started for OS: $Server_OS" | tee -a /var/log/cyberpanel_upgrade_debug.log
if [[ "$Server_OS" = "CentOS" ]] || [[ "$Server_OS" = "AlmaLinux9" ]] ; then
# Reduce dnf/yum timeouts and mirror issues (e.g. ftp.lip6.fr connection timeout)
for dnf_conf in /etc/dnf/dnf.conf /etc/yum.conf; do
if [[ -f "$dnf_conf" ]]; then
grep -q '^timeout=' "$dnf_conf" 2>/dev/null || echo 'timeout=120' >> "$dnf_conf"
grep -q '^minrate=' "$dnf_conf" 2>/dev/null || echo 'minrate=1000' >> "$dnf_conf"
grep -q '^retries=' "$dnf_conf" 2>/dev/null || echo 'retries=5' >> "$dnf_conf"
break
fi
done
# For AlmaLinux 9: switch to repo.almalinux.org baseurl to avoid "Cannot find valid baseurl for repo: appstream"
if [[ "$Server_OS" = "AlmaLinux9" ]] && [[ -d /etc/yum.repos.d ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Fixing AlmaLinux 9 repos (appstream/baseos) for reliable mirror access" | tee -a /var/log/cyberpanel_upgrade_debug.log
ALMA_VER="${Server_OS_Version:-9}"
ARCH="x86_64"
ALMA_BASE="https://repo.almalinux.org/almalinux/${ALMA_VER}"
for repo in /etc/yum.repos.d/almalinux*.repo /etc/yum.repos.d/AlmaLinux*.repo; do
[[ ! -f "$repo" ]] && continue
if grep -q '^mirrorlist=' "$repo" 2>/dev/null; then
sed -i 's|^mirrorlist=|#mirrorlist=|g' "$repo"
sed -i 's|^#\s*baseurl=\(.*repo\.almalinux\.org.*\)|baseurl=\1|' "$repo"
sed -i 's|^#baseurl=\(.*repo\.almalinux\.org.*\)|baseurl=\1|' "$repo"
fi
done
# Ensure appstream/baseos have explicit baseurl; support [appstream], [almalinux-appstream], etc.
for repofile in /etc/yum.repos.d/almalinux.repo /etc/yum.repos.d/almalinux*.repo /etc/yum.repos.d/AlmaLinux*.repo; do
[[ ! -f "$repofile" ]] && continue
for section in appstream almalinux-appstream AppStream; do
if grep -q "^\[${section}\]" "$repofile" 2>/dev/null; then
sed -i "/^\[${section}\]/,/^\[/ { s|^#\?baseurl=.*|baseurl=${ALMA_BASE}/AppStream/${ARCH}/os/|; s|^mirrorlist=.*|#mirrorlist=disabled| }" "$repofile"
if ! sed -n "/^\[${section}\]/,/^\[/p" "$repofile" | grep -q '^baseurl='; then
sed -i "/^\[${section}\]/a baseurl=${ALMA_BASE}/AppStream/${ARCH}/os/" "$repofile"
fi
fi
done
for section in baseos almalinux-baseos BaseOS; do
if grep -q "^\[${section}\]" "$repofile" 2>/dev/null; then
sed -i "/^\[${section}\]/,/^\[/ { s|^#\?baseurl=.*|baseurl=${ALMA_BASE}/BaseOS/${ARCH}/os/|; s|^mirrorlist=.*|#mirrorlist=disabled| }" "$repofile"
if ! sed -n "/^\[${section}\]/,/^\[/p" "$repofile" | grep -q '^baseurl='; then
sed -i "/^\[${section}\]/a baseurl=${ALMA_BASE}/BaseOS/${ARCH}/os/" "$repofile"
fi
fi
done
for section in crb extras; do
if grep -q "^\[${section}\]" "$repofile" 2>/dev/null; then
[[ "$section" = "crb" ]] && path="CRB" || path="extras"
sed -i "/^\[${section}\]/,/^\[/ { s|^#\?baseurl=.*|baseurl=${ALMA_BASE}/${path}/${ARCH}/os/|; s|^mirrorlist=.*|#mirrorlist=disabled| }" "$repofile"
if ! sed -n "/^\[${section}\]/,/^\[/p" "$repofile" | grep -q '^baseurl='; then
sed -i "/^\[${section}\]/a baseurl=${ALMA_BASE}/${path}/${ARCH}/os/" "$repofile"
fi
fi
done
done
# Fallback: create override with same repo IDs (loads last via zz- prefix, overrides broken config)
if ! dnf makecache --quiet 2>/dev/null; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] dnf makecache failed, creating AlmaLinux repo override" | tee -a /var/log/cyberpanel_upgrade_debug.log
cat > /etc/yum.repos.d/zz-almalinux-cyberpanel-fix.repo << EOF
[baseos]
name=AlmaLinux ${ALMA_VER} - BaseOS
baseurl=${ALMA_BASE}/BaseOS/${ARCH}/os/
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9
[appstream]
name=AlmaLinux ${ALMA_VER} - AppStream
baseurl=${ALMA_BASE}/AppStream/${ARCH}/os/
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9
[extras]
name=AlmaLinux ${ALMA_VER} - Extras
baseurl=${ALMA_BASE}/extras/${ARCH}/os/
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9
[crb]
name=AlmaLinux ${ALMA_VER} - CRB
baseurl=${ALMA_BASE}/CRB/${ARCH}/os/
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9
EOF
dnf makecache --quiet 2>/dev/null || true
fi
fi
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Setting up repositories for $Server_OS..." | tee -a /var/log/cyberpanel_upgrade_debug.log
rm -f /etc/yum.repos.d/CyberPanel.repo
rm -f /etc/yum.repos.d/litespeed.repo
if [[ "$Server_Country" = "CN" ]] ; then
curl -o /etc/yum.repos.d/litespeed.repo https://cyberpanel.sh/litespeed/litespeed_cn.repo
else
curl -o /etc/yum.repos.d/litespeed.repo https://cyberpanel.sh/litespeed/litespeed.repo
fi
yum clean all
if [[ -z "$Skip_System_Update" ]]; then
yum update -y
else
echo -e "[$(date +"%Y-%m-%d %H:%M-%S")] Skipping yum update (--no-system-update)" | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
yum autoremove epel-release -y
rm -f /etc/yum.repos.d/epel.repo
rm -f /etc/yum.repos.d/epel.repo.rpmsave
yum autoremove epel-release -y
#all pre-upgrade operation for CentOS both 7/8
if [[ "$Server_OS_Version" = "7" ]] ; then
yum install epel-release -y
yum -y install yum-utils
yum -y groupinstall development
rm -f /etc/yum.repos.d/dovecot.repo
rm -f /etc/yum.repos.d/frank.repo
rm -f /etc/yum.repos.d/ius-archive.repo
rm -f /etc/yum.repos.d/ius.repo
rm -f /etc/yum.repos.d/ius-testing.repo
#rm -f /etc/yum.repos.d/lux.repo
rm -f /etc/yum.repos.d/powerdns-auth-*
rm -f /etc/yum.repos.d/MariaDB.repo
rm -f /etc/yum.repos.d/MariaDB.repo.rpmsave
yum erase gf-* -y
rm -f /etc/yum.repos.d/gf.repo
rm -f /etc/yum.repos.d/gf.repo.rpmsave
rm -f /etc/yum.repos.d/copart-restic-epel-7.repo.repo
rm -f /etc/yum.repos.d/copart-restic-epel-7.repo.rpmsave
rm -f /etc/yum.repos.d/ius-archive.repo
rm -f /etc/yum.repos.d/ius.repo
rm -f /etc/yum.repos.d/ius-testing.repo
yum clean all
curl -o /etc/yum.repos.d/powerdns-auth-43.repo https://cyberpanel.sh/repo.powerdns.com/repo-files/centos-auth-43.repo
Check_Return "yum repo" "no_exit"
# Determine appropriate MariaDB repository based on OS version
if [[ "$Server_OS_Version" = "9" ]] || [[ "$Server_OS_Version" = "10" ]] ; then
MARIADB_REPO="rhel9-amd64"
else
MARIADB_REPO="centos7-amd64"
fi
cat << EOF > /etc/yum.repos.d/MariaDB.repo
# MariaDB $MARIADB_VER_REPO repository list - updated 2026-02
# https://downloads.mariadb.org/mariadb/repositories/
[mariadb]
name = MariaDB $MARIADB_VER_REPO
baseurl = https://mirror.mariadb.org/yum/$MARIADB_VER_REPO/$MARIADB_REPO
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1
EOF
yum install yum-plugin-copr -y
yum copr enable copart/restic -y
rpm -ivh https://cyberpanel.sh/repo.ius.io/ius-release-el7.rpm
if [[ "$Server_Country" = "CN" ]] ; then
sed -i 's|http://yum.mariadb.org|https://cyberpanel.sh/yum.mariadb.org|g' /etc/yum.repos.d/MariaDB.repo
sed -i 's|https://yum.mariadb.org/RPM-GPG-KEY-MariaDB|https://cyberpanel.sh/yum.mariadb.org/RPM-GPG-KEY-MariaDB|g' /etc/yum.repos.d/MariaDB.repo
# use MariaDB Mirror
sed -i 's|https://download.copr.fedorainfracloud.org|https://cyberpanel.sh/download.copr.fedorainfracloud.org|g' /etc/yum.repos.d/_copr_copart-restic.repo
sed -i 's|http://repo.iotti.biz|https://cyberpanel.sh/repo.iotti.biz|g' /etc/yum.repos.d/frank.repo
sed -i "s|mirrorlist=https://mirrorlist.ghettoforge.net/el/7/gf/\$basearch/mirrorlist|baseurl=https://cyberpanel.sh/mirror.ghettoforge.net/distributions/gf/el/7/gf/x86_64/|g" /etc/yum.repos.d/gf.repo
sed -i "s|mirrorlist=https://mirrorlist.ghettoforge.net/el/7/plus/\$basearch/mirrorlist|baseurl=https://cyberpanel.sh/mirror.ghettoforge.net/distributions/gf/el/7/plus/x86_64/|g" /etc/yum.repos.d/gf.repo
sed -i 's|https://repo.ius.io|https://cyberpanel.sh/repo.ius.io|g' /etc/yum.repos.d/ius.repo
sed -i 's|http://repo.iotti.biz|https://cyberpanel.sh/repo.iotti.biz|g' /etc/yum.repos.d/lux.repo
sed -i 's|http://repo.powerdns.com|https://cyberpanel.sh/repo.powerdns.com|g' /etc/yum.repos.d/powerdns-auth-43.repo
sed -i 's|https://repo.powerdns.com|https://cyberpanel.sh/repo.powerdns.com|g' /etc/yum.repos.d/powerdns-auth-43.repo
fi
yum install yum-plugin-priorities -y
yum update -y
yum install -y wget strace htop net-tools telnet curl which bc telnet htop libevent-devel gcc libattr-devel xz-devel gpgme-devel curl-devel git socat openssl-devel MariaDB-shared mariadb-devel python36u python36u-pip python36u-devel bind-utils
Pre_Upgrade_CentOS7_MySQL
#all pre-upgrade operation for CentOS 7
elif [[ "$Server_OS_Version" = "8" ]] ; then
# cat <<EOF >/etc/yum.repos.d/CentOS-PowerTools-CyberPanel.repo
#[powertools-for-cyberpanel]
#name=CentOS Linux \$releasever - PowerTools
#mirrorlist=http://mirrorlist.centos.org/?release=\$releasever&arch=\$basearch&repo=PowerTools&infra=\$infra
#baseurl=http://mirror.centos.org/\$contentdir/\$releasever/PowerTools/\$basearch/os/
#gpgcheck=1
#enabled=1
#gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
#EOF
rm -f /etc/yum.repos.d/CentOS-PowerTools-CyberPanel.repo
if [[ "$Server_Country" = "CN" ]] ; then
dnf --nogpg install -y https://cyberpanel.sh/mirror.ghettoforge.net/distributions/gf/gf-release-latest.gf.el8.noarch.rpm
else
dnf --nogpg install -y https://mirror.ghettoforge.net/distributions/gf/gf-release-latest.gf.el8.noarch.rpm
fi
dnf install epel-release -y
dnf install -y wget strace htop net-tools telnet which bc telnet htop libevent-devel gcc libattr-devel xz-devel mariadb-connector-c-devel curl-devel git platform-python-devel tar socat bind-utils 2>/dev/null || dnf install -y --allowerasing wget strace htop net-tools telnet which bc htop libevent-devel gcc libattr-devel xz-devel mariadb-connector-c-devel curl-devel git platform-python-devel tar socat bind-utils
dnf install gpgme-devel -y 2>/dev/null || true
dnf install python3 -y
elif [[ "$Server_OS_Version" = "9" ]] || [[ "$Server_OS_Version" = "10" ]] ; then
rm -f /etc/yum.repos.d/CentOS-PowerTools-CyberPanel.repo
if [[ "$Server_Country" = "CN" ]] ; then
dnf --nogpg install -y https://cyberpanel.sh/mirror.ghettoforge.net/distributions/gf/gf-release-latest.gf.el9.noarch.rpm
else
dnf --nogpg install -y https://mirror.ghettoforge.net/distributions/gf/gf-release-latest.gf.el9.noarch.rpm
fi
dnf install epel-release -y 2>/dev/null || {
# Fallback when appstream was broken or epel-release not in repo (e.g. AlmaLinux 9)
if [[ "$Server_OS_Version" = "9" ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Installing EPEL from Fedora RPM (epel-release not in repo)..." | tee -a /var/log/cyberpanel_upgrade_debug.log
dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm 2>/dev/null || true
fi
}
# MariaDB repo for EL8/EL9: any version (repo path uses major.minor: 10.11, 11.8, 12.1, 12.2, 12.3, etc.)
if [[ "$Server_OS_Version" = "8" ]] || [[ "$Server_OS_Version" = "9" ]] || [[ "$Server_OS_Version" = "10" ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Configuring MariaDB $MARIADB_VER_REPO repository and upgrading MariaDB..." | tee -a /var/log/cyberpanel_upgrade_debug.log
Maybe_Backup_MariaDB_Before_Upgrade
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Writing MariaDB $MARIADB_VER_REPO repo and installing/upgrading packages..." | tee -a /var/log/cyberpanel_upgrade_debug.log
if [[ "$Server_OS_Version" = "9" ]] || [[ "$Server_OS_Version" = "10" ]]; then
MARIADB_REPO="rhel9-amd64"
else
MARIADB_REPO="rhel8-amd64"
fi
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Configuring MariaDB $MARIADB_VER_REPO repo for EL$Server_OS_Version (version $MARIADB_VER)..." | tee -a /var/log/cyberpanel_upgrade_debug.log
# Remove or backup any existing MariaDB repo that points to a different version, so dnf uses only our repo
for f in /etc/yum.repos.d/mariadb.repo /etc/yum.repos.d/MariaDB.repo.rpmsave; do
if [[ -f "$f" ]] && grep -q '10\.11\|10.6\|10.5' "$f" 2>/dev/null && [[ "$MARIADB_VER_REPO" != "10.11" ]]; then
mv -f "$f" "${f}.bak.cyberpanel" 2>/dev/null && echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Backed up old repo $f to ${f}.bak.cyberpanel (was 10.x, we want $MARIADB_VER_REPO)" | tee -a /var/log/cyberpanel_upgrade_debug.log || true
fi
done
cat << EOF > /etc/yum.repos.d/MariaDB.repo
# MariaDB $MARIADB_VER_REPO repository - CyberPanel upgrade
# https://downloads.mariadb.org/mariadb/repositories/
[mariadb]
name = MariaDB $MARIADB_VER_REPO
baseurl = https://mirror.mariadb.org/yum/$MARIADB_VER_REPO/$MARIADB_REPO
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1
EOF
if [[ "$Server_Country" = "CN" ]]; then
sed -i 's|http://yum.mariadb.org|https://cyberpanel.sh/yum.mariadb.org|g' /etc/yum.repos.d/MariaDB.repo
sed -i 's|https://yum.mariadb.org/RPM-GPG-KEY-MariaDB|https://cyberpanel.sh/yum.mariadb.org/RPM-GPG-KEY-MariaDB|g' /etc/yum.repos.d/MariaDB.repo
fi
dnf clean metadata --disablerepo='*' --enablerepo=mariadb 2>/dev/null || true
# MariaDB 10 -> 11 or 11 -> 12: RPM scriptlet blocks in-place upgrade; do manual stop, remove old server, install target, start, mariadb-upgrade
MARIADB_OLD_10=$(rpm -qa 'MariaDB-server-10*' 2>/dev/null | head -1)
MARIADB_OLD_11=$(rpm -qa 'MariaDB-server-11*' 2>/dev/null | head -1)
# Also detect 11.x by package version (e.g. MariaDB-server-11.8.6-1.el9)
[[ -z "$MARIADB_OLD_11" ]] && MARIADB_OLD_11=$(rpm -qa 'MariaDB-server*' 2>/dev/null | grep -E 'MariaDB-server-11\.' | head -1)
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] MariaDB detected: MARIADB_OLD_10=$MARIADB_OLD_10 MARIADB_OLD_11=$MARIADB_OLD_11 target=$MARIADB_VER_REPO" | tee -a /var/log/cyberpanel_upgrade_debug.log
if [[ -n "$MARIADB_OLD_10" ]] && { [[ "$MARIADB_VER_REPO" =~ ^11\. ]] || [[ "$MARIADB_VER_REPO" =~ ^12\. ]]; }; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] MariaDB 10.x detected; performing manual upgrade to $MARIADB_VER_REPO (stop, remove, install, start, mariadb-upgrade)..." | tee -a /var/log/cyberpanel_upgrade_debug.log
systemctl stop mariadb 2>/dev/null || true
sleep 2
[[ -f /etc/my.cnf ]] && cp -a /etc/my.cnf /etc/my.cnf.bak.cyberpanel 2>/dev/null || true
[[ -d /etc/my.cnf.d ]] && cp -a /etc/my.cnf.d /etc/my.cnf.d.bak.cyberpanel 2>/dev/null || true
rpm -e "$MARIADB_OLD_10" --nodeps 2>/dev/null || true
dnf install -y --enablerepo=mariadb MariaDB-server MariaDB-client MariaDB-devel 2>/dev/null || true
mkdir -p /etc/my.cnf.d
printf "[client]\nskip-ssl = true\n" > /etc/my.cnf.d/cyberpanel-client.cnf 2>/dev/null || true
systemctl start mariadb 2>/dev/null || true
sleep 2
mariadb-upgrade -u root 2>/dev/null || true
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] MariaDB manual upgrade to $MARIADB_VER_REPO completed." | tee -a /var/log/cyberpanel_upgrade_debug.log
elif [[ -n "$MARIADB_OLD_11" ]] && [[ "$MARIADB_VER_REPO" =~ ^12\. ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] MariaDB 11.x detected; performing manual upgrade to $MARIADB_VER_REPO (stop, remove, install, start, mariadb-upgrade)..." | tee -a /var/log/cyberpanel_upgrade_debug.log
systemctl stop mariadb 2>/dev/null || true
sleep 2
[[ -f /etc/my.cnf ]] && cp -a /etc/my.cnf /etc/my.cnf.bak.cyberpanel 2>/dev/null || true
[[ -d /etc/my.cnf.d ]] && cp -a /etc/my.cnf.d /etc/my.cnf.d.bak.cyberpanel 2>/dev/null || true
rpm -e "$MARIADB_OLD_11" --nodeps 2>/dev/null || true
dnf install -y --enablerepo=mariadb MariaDB-server MariaDB-client MariaDB-devel 2>/dev/null || true
mkdir -p /etc/my.cnf.d
printf "[client]\nskip-ssl = true\n" > /etc/my.cnf.d/cyberpanel-client.cnf 2>/dev/null || true
systemctl start mariadb 2>/dev/null || true
sleep 2
mariadb-upgrade -u root 2>/dev/null || true
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] MariaDB manual upgrade to $MARIADB_VER_REPO completed (11->12)." | tee -a /var/log/cyberpanel_upgrade_debug.log
else
# Normal install/upgrade (same version or 10.11)
dnf install -y --enablerepo=mariadb MariaDB-server MariaDB-client MariaDB-devel 2>/dev/null || true
dnf upgrade -y --enablerepo=mariadb MariaDB-server MariaDB-client MariaDB-devel 2>/dev/null || true
systemctl restart mariadb 2>/dev/null || true
# Fallback: if we wanted 12.x but server is still 11.x (RPM scriptlet blocked in-place upgrade), do manual 11->12
if [[ "$MARIADB_VER_REPO" =~ ^12\. ]]; then
STILL_11=$(rpm -qa 'MariaDB-server-11*' 2>/dev/null | head -1)
[[ -z "$STILL_11" ]] && STILL_11=$(rpm -qa 'MariaDB-server*' 2>/dev/null | grep -E 'MariaDB-server-11\.' | head -1)
if [[ -n "$STILL_11" ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] MariaDB server still 11.x after dnf upgrade; performing manual 11->12 upgrade..." | tee -a /var/log/cyberpanel_upgrade_debug.log
systemctl stop mariadb 2>/dev/null || true
sleep 2
[[ -f /etc/my.cnf ]] && cp -a /etc/my.cnf /etc/my.cnf.bak.cyberpanel 2>/dev/null || true
[[ -d /etc/my.cnf.d ]] && cp -a /etc/my.cnf.d /etc/my.cnf.d.bak.cyberpanel 2>/dev/null || true
rpm -e "$STILL_11" --nodeps 2>/dev/null || true
dnf install -y --enablerepo=mariadb MariaDB-server MariaDB-client MariaDB-devel 2>/dev/null || true
mkdir -p /etc/my.cnf.d
printf "[client]\nskip-ssl = true\n" > /etc/my.cnf.d/cyberpanel-client.cnf 2>/dev/null || true
systemctl start mariadb 2>/dev/null || true
sleep 2
mariadb-upgrade -u root 2>/dev/null || true
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] MariaDB manual 11->12 fallback completed." | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
fi
fi
# Allow local client to connect without SSL (11.x client defaults to SSL; 10.x server may not have it)
mkdir -p /etc/my.cnf.d
printf "[client]\nskip-ssl = true\n" > /etc/my.cnf.d/cyberpanel-client.cnf 2>/dev/null || true
# Optional: migrate from latin1 to UTF-8 (utf8mb4) when --migrate-to-utf8 and 11.x/12.x
if [[ "$Migrate_MariaDB_To_UTF8_Requested" = "yes" ]] && { [[ "$MARIADB_VER_REPO" =~ ^11\. ]] || [[ "$MARIADB_VER_REPO" =~ ^12\. ]]; }; then
Migrate_MariaDB_To_UTF8
fi
fi
# AlmaLinux 9 specific package installation
if [[ "$Server_OS" = "AlmaLinux9" ]] ; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Installing AlmaLinux 9 specific packages (Development Tools, PHP deps, MariaDB)..." | tee -a /var/log/cyberpanel_upgrade_debug.log
# Install essential build tools
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Running: dnf groupinstall -y 'Development Tools' (may take a few minutes)..." | tee -a /var/log/cyberpanel_upgrade_debug.log
dnf groupinstall -y 'Development Tools'
# Install PHP dependencies that are missing on AlmaLinux 9
dnf install -y ImageMagick ImageMagick-devel gd gd-devel libicu libicu-devel \
oniguruma oniguruma-devel aspell aspell-devel libc-client libc-client-devel \
libmemcached libmemcached-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++
# Install/upgrade MariaDB from our repo (any version: 10.11, 11.8, 12.x). Manual path for 10->11 and 11->12.
MARIADB_OLD_10_AL9=$(rpm -qa 'MariaDB-server-10*' 2>/dev/null | head -1)
MARIADB_OLD_11_AL9=$(rpm -qa 'MariaDB-server-11*' 2>/dev/null | head -1)
[[ -z "$MARIADB_OLD_11_AL9" ]] && MARIADB_OLD_11_AL9=$(rpm -qa 'MariaDB-server*' 2>/dev/null | grep -E 'MariaDB-server-11\.' | head -1)
if [[ -n "$MARIADB_OLD_10_AL9" ]] && { [[ "$MARIADB_VER_REPO" =~ ^11\. ]] || [[ "$MARIADB_VER_REPO" =~ ^12\. ]]; }; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] MariaDB 10.x detected (AlmaLinux 9); manual upgrade to $MARIADB_VER_REPO..." | tee -a /var/log/cyberpanel_upgrade_debug.log
systemctl stop mariadb 2>/dev/null || true
sleep 2
[[ -f /etc/my.cnf ]] && cp -a /etc/my.cnf /etc/my.cnf.bak.cyberpanel 2>/dev/null || true
[[ -d /etc/my.cnf.d ]] && cp -a /etc/my.cnf.d /etc/my.cnf.d.bak.cyberpanel 2>/dev/null || true
rpm -e "$MARIADB_OLD_10_AL9" --nodeps 2>/dev/null || true
dnf install -y --enablerepo=mariadb MariaDB-server MariaDB-devel 2>/dev/null || dnf install -y mariadb-server mariadb-devel
mkdir -p /etc/my.cnf.d
printf "[client]\nskip-ssl = true\n" > /etc/my.cnf.d/cyberpanel-client.cnf 2>/dev/null || true
systemctl start mariadb 2>/dev/null || true
sleep 2
mariadb-upgrade -u root 2>/dev/null || true
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] MariaDB manual upgrade to $MARIADB_VER_REPO completed (AlmaLinux 9)." | tee -a /var/log/cyberpanel_upgrade_debug.log
elif [[ -n "$MARIADB_OLD_11_AL9" ]] && [[ "$MARIADB_VER_REPO" =~ ^12\. ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] MariaDB 11.x detected (AlmaLinux 9); manual upgrade to $MARIADB_VER_REPO..." | tee -a /var/log/cyberpanel_upgrade_debug.log
systemctl stop mariadb 2>/dev/null || true
sleep 2
[[ -f /etc/my.cnf ]] && cp -a /etc/my.cnf /etc/my.cnf.bak.cyberpanel 2>/dev/null || true
[[ -d /etc/my.cnf.d ]] && cp -a /etc/my.cnf.d /etc/my.cnf.d.bak.cyberpanel 2>/dev/null || true
rpm -e "$MARIADB_OLD_11_AL9" --nodeps 2>/dev/null || true
dnf install -y --enablerepo=mariadb MariaDB-server MariaDB-devel 2>/dev/null || dnf install -y mariadb-server mariadb-devel
mkdir -p /etc/my.cnf.d
printf "[client]\nskip-ssl = true\n" > /etc/my.cnf.d/cyberpanel-client.cnf 2>/dev/null || true
systemctl start mariadb 2>/dev/null || true
sleep 2
mariadb-upgrade -u root 2>/dev/null || true
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] MariaDB manual upgrade to $MARIADB_VER_REPO completed (AlmaLinux 9, 11->12)." | tee -a /var/log/cyberpanel_upgrade_debug.log
else
dnf install -y --enablerepo=mariadb MariaDB-server MariaDB-devel 2>/dev/null || dnf install -y mariadb-server mariadb-devel
dnf upgrade -y --enablerepo=mariadb MariaDB-server MariaDB-devel 2>/dev/null || true
systemctl restart mariadb 2>/dev/null || true
fi
# Allow local client to connect without SSL
mkdir -p /etc/my.cnf.d
printf "[client]\nskip-ssl = true\n" > /etc/my.cnf.d/cyberpanel-client.cnf 2>/dev/null || true
# Install additional required packages (omit curl - AlmaLinux 9 has curl-minimal, avoid conflict)
dnf install -y wget unzip zip rsync firewalld psmisc git python3 python3-pip python3-devel 2>/dev/null || dnf install -y --allowerasing wget unzip zip rsync firewalld psmisc git python3 python3-pip python3-devel
fi
# Omit curl to avoid conflict with curl-minimal on AlmaLinux 9; curl-devel for build is separate
dnf install -y wget strace htop net-tools telnet which bc telnet htop libevent-devel gcc libattr-devel xz-devel mariadb-connector-c-devel curl-devel git platform-python-devel tar socat bind-utils 2>/dev/null || dnf install -y --allowerasing wget strace htop net-tools telnet which bc htop libevent-devel gcc libattr-devel xz-devel mariadb-connector-c-devel curl-devel git platform-python-devel tar socat bind-utils
dnf install gpgme-devel -y 2>/dev/null || true
dnf install python3 -y
fi
elif [[ "$Server_OS" = "Ubuntu" ]] ; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Setting up Ubuntu repositories..." | tee -a /var/log/cyberpanel_upgrade_debug.log
# Ensure nobody group exists (required for various operations)
if ! getent group nobody > /dev/null 2>&1 ; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Creating 'nobody' group..." | tee -a /var/log/cyberpanel_upgrade_debug.log
groupadd nobody
fi
apt update -y
if [[ -z "$Skip_System_Update" ]]; then
export DEBIAN_FRONTEND=noninteractive ; apt-get -o Dpkg::Options::="--force-confold" upgrade -y
else
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Skipping apt upgrade (--no-system-update)" | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
# MariaDB: add official repo and install/upgrade to chosen version on Ubuntu/Debian (any version)
if [[ -n "$MARIADB_VER_REPO" ]]; then
Maybe_Backup_MariaDB_Before_Upgrade
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Configuring MariaDB $MARIADB_VER_REPO repo for Ubuntu/Debian (version $MARIADB_VER)..." | tee -a /var/log/cyberpanel_upgrade_debug.log
curl -LsS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | bash -s -- --mariadb-server-version="$MARIADB_VER_REPO" 2>/dev/null || true
# Must run apt-get update after adding repo so 11.8 packages are visible (otherwise apt keeps 10.11)
apt-get update -qq 2>/dev/null || apt-get update
export DEBIAN_FRONTEND=noninteractive
apt-get install -y mariadb-server mariadb-client 2>/dev/null || true
apt-get install -y -o Dpkg::Options::="--force-confold" mariadb-server mariadb-client 2>/dev/null || true
systemctl restart mariadb 2>/dev/null || systemctl restart mysql 2>/dev/null || true
if [[ "$Migrate_MariaDB_To_UTF8_Requested" = "yes" ]] && { [[ "$MARIADB_VER_REPO" =~ ^11\. ]] || [[ "$MARIADB_VER_REPO" =~ ^12\. ]]; }; then
Migrate_MariaDB_To_UTF8
fi
fi
if [[ "$Server_OS_Version" = "22" ]] || [[ "$Server_OS_Version" = "24" ]] ; then
if [[ "$Server_OS_Version" = "24" ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Installing Ubuntu 24.04 specific packages..." | tee -a /var/log/cyberpanel_upgrade_debug.log
else
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Installing Ubuntu 22.04 specific packages..." | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
# Install Python development packages required for virtualenv on Ubuntu 22.04/24.04
DEBIAN_FRONTEND=noninteractive apt install -y python3-dev python3-venv python3-pip python3-setuptools python3-wheel
DEBIAN_FRONTEND=noninteractive apt install -y dnsutils net-tools htop telnet libcurl4-gnutls-dev libgnutls28-dev libgcrypt20-dev libattr1 libattr1-dev liblzma-dev libgpgme-dev libcurl4-gnutls-dev libssl-dev nghttp2 libnghttp2-dev idn2 libidn2-dev libidn2-0-dev librtmp-dev libpsl-dev nettle-dev libgnutls28-dev libldap2-dev libgssapi-krb5-2 libk5crypto3 libkrb5-dev libcomerr2 libldap2-dev virtualenv git socat vim unzip zip libmariadb-dev-compat libmariadb-dev
else
DEBIAN_FRONTEND=noninteractive apt install -y htop telnet libcurl4-gnutls-dev libgnutls28-dev libgcrypt20-dev libattr1 libattr1-dev liblzma-dev libgpgme-dev libmariadb-dev-compat libmariadb-dev libcurl4-gnutls-dev libssl-dev nghttp2 libnghttp2-dev idn2 libidn2-dev librtmp-dev libpsl-dev nettle-dev libgnutls28-dev libldap2-dev libgssapi-krb5-2 libk5crypto3 libkrb5-dev libcom-err2 libldap2-dev virtualenv git dnsutils
fi
DEBIAN_FRONTEND=noninteractive apt install -y python3-pip
DEBIAN_FRONTEND=noninteractive apt install -y build-essential libssl-dev libffi-dev python3-dev
DEBIAN_FRONTEND=noninteractive apt install -y python3-venv
### fix for pip issue on ubuntu 22 and 24
apt-get remove --purge virtualenv -y
# Handle Ubuntu 24.04's externally-managed-environment policy
if [[ "$Server_OS_Version" = "24" ]]; then
echo -e "Ubuntu 24.04 detected - using apt for virtualenv installation"
DEBIAN_FRONTEND=noninteractive apt-get install -y python3-virtualenv
else
pip uninstall -y virtualenv 2>/dev/null || true
rm -rf /usr/lib/python3/dist-packages/virtualenv*
pip3 install --upgrade virtualenv
fi
if [[ "$Server_OS_Version" = "18" ]] ; then
:
#all pre-upgrade operation for Ubuntu 18
elif [[ "$Server_OS_Version" = "20" ]] ; then
# if ! grep -q "focal" /etc/apt/sources.list.d/dovecot.list ; then
# sed -i 's|ce-2.3-latest/ubuntu/bionic bionic main|ce-2.3-latest/ubuntu/focal focal main|g' /etc/apt/sources.list.d/dovecot.list
# rm -rf /etc/dovecot-backup
# cp -r /etc/dovecot /etc/dovecot-backup
# apt update
# DEBIAN_FRONTEND=noninteractive apt -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" remove -y dovecot-mysql dovecot-pop3d dovecot-imapd
# DEBIAN_FRONTEND=noninteractive apt -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y dovecot-mysql dovecot-pop3d dovecot-imapd
# systemctl restart dovecot
# fi
#fix ubuntu 20 webmail login issue
rm -f /etc/apt/sources.list.d/dovecot.list
apt update
DEBIAN_FRONTEND=noninteractive DEBIAN_PRIORITY=critical apt -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade -y
fi
#all pre-upgrade operation for Ubuntu 20
fi
if [[ "$Server_OS" = "openEuler" ]] ; then
rm -f /etc/yum.repos.d/CyberPanel.repo
rm -f /etc/yum.repos.d/litespeed.repo
yum clean all
yum update -y
dnf install -y wget strace htop net-tools telnet curl which bc telnet htop libevent-devel gcc libattr-devel xz-devel mariadb-devel curl-devel git python3-devel tar socat bind-utils
dnf install gpgme-devel -y
dnf install python3 -y
fi
#all pre-upgrade operation for openEuler
}

View File

@@ -0,0 +1,290 @@
#!/usr/bin/env bash
# CyberPanel upgrade download requirements and required components (venv, pip, recovery). Sourced by cyberpanel_upgrade.sh.
Download_Requirement() {
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Starting Download_Requirement function..." | tee -a /var/log/cyberpanel_upgrade_debug.log
for i in {1..50};
do
if [[ "$Server_OS_Version" = "22" ]] || [[ "$Server_OS_Version" = "24" ]] || [[ "$Server_OS_Version" = "9" ]] || [[ "$Server_OS_Version" = "10" ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Downloading requirements.txt for OS version $Server_OS_Version" | tee -a /var/log/cyberpanel_upgrade_debug.log
if command -v wget >/dev/null 2>&1; then wget -O /usr/local/requirments.txt "${Git_Content_URL}/${Branch_Name}/requirments.txt" 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log; else curl -sL -o /usr/local/requirments.txt "${Git_Content_URL}/${Branch_Name}/requirments.txt" 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log; fi
else
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Downloading requirements-old.txt for OS version $Server_OS_Version" | tee -a /var/log/cyberpanel_upgrade_debug.log
if command -v wget >/dev/null 2>&1; then wget -O /usr/local/requirments.txt "${Git_Content_URL}/${Branch_Name}/requirments-old.txt" 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log; else curl -sL -o /usr/local/requirments.txt "${Git_Content_URL}/${Branch_Name}/requirments-old.txt" 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log; fi
fi
if grep -q "Django==" /usr/local/requirments.txt ; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Requirements file downloaded successfully" | tee -a /var/log/cyberpanel_upgrade_debug.log
# Fix pysftp dependency issue by removing it from requirements
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Fixing pysftp dependency issue..." | tee -a /var/log/cyberpanel_upgrade_debug.log
sed -i 's/^pysftp$/# pysftp - deprecated, using paramiko instead/' /usr/local/requirments.txt
sed -i 's/pysftp/# pysftp - deprecated, using paramiko instead/' /usr/local/requirments.txt
break
else
echo -e "\n Requirement list has failed to download for $i times..."
echo -e "Wait for 30 seconds and try again...\n"
sleep 30
fi
done
#special made function for Gitee.com, for whatever reason sometimes it fails to download this file
}
Pre_Upgrade_Required_Components() {
# Check if CyberCP directory exists but is incomplete/damaged
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Checking CyberCP directory integrity..." | tee -a /var/log/cyberpanel_upgrade_debug.log
# Define essential CyberCP components
CYBERCP_ESSENTIAL_DIRS=(
"/usr/local/CyberCP/CyberCP"
"/usr/local/CyberCP/plogical"
"/usr/local/CyberCP/websiteFunctions"
"/usr/local/CyberCP/manage"
)
CYBERCP_MISSING=0
for dir in "${CYBERCP_ESSENTIAL_DIRS[@]}"; do
if [ ! -d "$dir" ]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] INFO: Essential directory missing (will restore): $dir" | tee -a /var/log/cyberpanel_upgrade_debug.log
CYBERCP_MISSING=1
fi
done
# If essential directories are missing, perform automatic recovery (normal on some upgrade paths)
if [ $CYBERCP_MISSING -eq 1 ]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] INFO: Restoring missing CyberCP directories from repository..." | tee -a /var/log/cyberpanel_upgrade_debug.log
# Backup any remaining configuration files if they exist
if [ -f "/usr/local/CyberCP/CyberCP/settings.py" ]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Backing up existing settings.py..." | tee -a /var/log/cyberpanel_upgrade_debug.log
cp /usr/local/CyberCP/CyberCP/settings.py /tmp/cyberpanel_settings_backup.py
fi
# Clone fresh CyberPanel repository
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Cloning fresh CyberPanel repository for recovery..." | tee -a /var/log/cyberpanel_upgrade_debug.log
cd /usr/local
rm -rf CyberCP_recovery_tmp
if git clone "$Git_Clone_URL" CyberCP_recovery_tmp; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Repository cloned successfully for recovery" | tee -a /var/log/cyberpanel_upgrade_debug.log
# Checkout the appropriate branch
cd CyberCP_recovery_tmp
git checkout "$Branch_Name" 2>/dev/null || git checkout stable
# Copy missing components while preserving existing configurations
for dir in "${CYBERCP_ESSENTIAL_DIRS[@]}"; do
if [ ! -d "$dir" ]; then
# Extract relative path after /usr/local/CyberCP/
relative_path=${dir#/usr/local/CyberCP/}
if [ -d "/usr/local/CyberCP_recovery_tmp/$relative_path" ]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Restoring missing directory: $dir" | tee -a /var/log/cyberpanel_upgrade_debug.log
mkdir -p "$(dirname "$dir")"
cp -r "/usr/local/CyberCP_recovery_tmp/$relative_path" "$dir"
fi
fi
done
# Restore settings.py if it was backed up
if [ -f "/tmp/cyberpanel_settings_backup.py" ]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Restoring backed up settings.py..." | tee -a /var/log/cyberpanel_upgrade_debug.log
cp /tmp/cyberpanel_settings_backup.py /usr/local/CyberCP/CyberCP/settings.py
fi
# Clean up temporary clone
rm -rf /usr/local/CyberCP_recovery_tmp
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Recovery completed. All essential CyberCP directories restored." | tee -a /var/log/cyberpanel_upgrade_debug.log
else
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] ERROR: Failed to clone repository for recovery" | tee -a /var/log/cyberpanel_upgrade_debug.log
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Please run full installation instead of upgrade" | tee -a /var/log/cyberpanel_upgrade_debug.log
exit 1
fi
cd /root/cyberpanel_upgrade_tmp || cd /root
fi
if [ "$Server_OS" = "Ubuntu" ]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Preparing Ubuntu environment for virtualenv..." | tee -a /var/log/cyberpanel_upgrade_debug.log
rm -rf /usr/local/CyberPanel
# For Ubuntu 22.04 and 24.04, handle virtualenv installation properly
if [[ "$Server_OS_Version" = "22" ]] || [[ "$Server_OS_Version" = "24" ]]; then
if [[ "$Server_OS_Version" = "24" ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Ubuntu 24.04: Using apt for virtualenv installation (externally-managed-environment policy)..." | tee -a /var/log/cyberpanel_upgrade_debug.log
# Ubuntu 24.04 has externally-managed-environment, use apt
DEBIAN_FRONTEND=noninteractive apt-get install -y python3-virtualenv python3-venv
else
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Ubuntu 22.04: Installing/upgrading virtualenv with proper dependencies..." | tee -a /var/log/cyberpanel_upgrade_debug.log
# Remove system virtualenv if it exists to avoid conflicts
apt remove -y python3-virtualenv 2>/dev/null || true
# Install latest virtualenv via pip
pip3 install --upgrade pip setuptools wheel
pip3 install --upgrade virtualenv
fi
else
pip3 install --upgrade virtualenv
fi
else
rm -rf /usr/local/CyberPanel
# AlmaLinux 9/10, Rocky 9: use python3 -m venv (no virtualenv pkg needed)
if [[ "$Server_OS" = "AlmaLinux" ]] || [[ "$Server_OS" = "AlmaLinux9" ]] || [[ "$Server_OS" = "RockyLinux" ]]; then
if [[ "$Server_OS_Version" = "9" ]] || [[ "$Server_OS_Version" = "10" ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] AlmaLinux/Rocky $Server_OS_Version: will use python3 -m venv, skipping virtualenv package" | tee -a /var/log/cyberpanel_upgrade_debug.log
else
if [ -e /usr/bin/pip3 ]; then PIP3="/usr/bin/pip3"; else PIP3="pip3.6"; fi
$PIP3 install --default-timeout=3600 virtualenv
Check_Return
fi
else
if [ -e /usr/bin/pip3 ]; then PIP3="/usr/bin/pip3"; else PIP3="pip3.6"; fi
$PIP3 install --default-timeout=3600 virtualenv
Check_Return
fi
fi
if [[ -f /usr/local/CyberPanel/bin/python2 ]]; then
echo -e "\nPython 2 dectected, doing re-setup...\n"
rm -rf /usr/local/CyberPanel/bin
if [[ "$Server_OS" = "Ubuntu" ]] && ([[ "$Server_OS_Version" = "22" ]] || [[ "$Server_OS_Version" = "24" ]]); then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Ubuntu $Server_OS_Version detected, using python3 -m venv..." | tee -a /var/log/cyberpanel_upgrade_debug.log
python3 -m venv --system-site-packages /usr/local/CyberPanel
elif [[ "$Server_OS" = "CentOS" ]] || [[ "$Server_OS" = "AlmaLinux" ]] || [[ "$Server_OS" = "AlmaLinux9" ]] || [[ "$Server_OS" = "RockyLinux" ]]; then
if [[ "$Server_OS_Version" = "9" ]] || [[ "$Server_OS_Version" = "10" ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] AlmaLinux/Rocky $Server_OS_Version detected, using python3 -m venv..." | tee -a /var/log/cyberpanel_upgrade_debug.log
python3 -m venv --system-site-packages /usr/local/CyberPanel
else
PYTHON_PATH=$(which python3 2>/dev/null || which python3.9 2>/dev/null || echo "/usr/bin/python3")
virtualenv -p "$PYTHON_PATH" --system-site-packages /usr/local/CyberPanel
fi
else
virtualenv -p /usr/bin/python3 --system-site-packages /usr/local/CyberPanel
fi
Check_Return
elif [[ -d /usr/local/CyberPanel/bin/ ]]; then
echo -e "\nNo need to re-setup virtualenv at /usr/local/CyberPanel...\n"
else
#!/bin/bash
echo -e "\nNo existing virtualenv found; creating fresh Python environment...\n"
# Attempt to create a virtual environment
if [[ "$Server_OS" = "Ubuntu" ]] && ([[ "$Server_OS_Version" = "22" ]] || [[ "$Server_OS_Version" = "24" ]]); then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Ubuntu $Server_OS_Version detected, using python3 -m venv..." | tee -a /var/log/cyberpanel_upgrade_debug.log
python3 -m venv /usr/local/CyberPanel
elif [[ "$Server_OS" = "CentOS" ]] || [[ "$Server_OS" = "AlmaLinux" ]] || [[ "$Server_OS" = "AlmaLinux9" ]] || [[ "$Server_OS" = "RockyLinux" ]]; then
if [[ "$Server_OS_Version" = "9" ]] || [[ "$Server_OS_Version" = "10" ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] AlmaLinux/Rocky $Server_OS_Version: using python3 -m venv (no virtualenv pkg needed)..." | tee -a /var/log/cyberpanel_upgrade_debug.log
python3 -m venv --system-site-packages /usr/local/CyberPanel
else
PYTHON_PATH=$(which python3 2>/dev/null || which python3.9 2>/dev/null || echo "/usr/bin/python3")
virtualenv -p "$PYTHON_PATH" --system-site-packages /usr/local/CyberPanel
fi
else
virtualenv -p /usr/bin/python3 --system-site-packages /usr/local/CyberPanel
fi
# Check if the virtualenv/venv command failed
if [ $? -ne 0 ]; then
echo "virtualenv command failed."
# Check if the operating system is AlmaLinux
if grep -q "AlmaLinux" /etc/os-release; then
echo "Operating system is AlmaLinux."
# Check if the 'packaging' module is installed via RPM
if rpm -q python3-packaging >/dev/null 2>&1; then
echo "'packaging' module installed via RPM. Proceeding with uninstallation."
# Uninstall the 'packaging' module using RPM
sudo dnf remove python3-packaging -y
# Check if uninstallation was successful
if [ $? -eq 0 ]; then
echo "Successfully uninstalled 'packaging' module."
# Install and upgrade 'packaging' using pip
pip install --upgrade packaging
# Verify the installation
if [ $? -eq 0 ]; then
echo "'packaging' module reinstalled and upgraded successfully."
if [[ "$Server_OS" = "Ubuntu" ]] && ([[ "$Server_OS_Version" = "22" ]] || [[ "$Server_OS_Version" = "24" ]]); then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Ubuntu: using python3 -m venv..." | tee -a /var/log/cyberpanel_upgrade_debug.log
python3 -m venv --system-site-packages /usr/local/CyberPanel
elif [[ "$Server_OS" = "CentOS" ]] || [[ "$Server_OS" = "AlmaLinux" ]] || [[ "$Server_OS" = "AlmaLinux9" ]] || [[ "$Server_OS" = "RockyLinux" ]]; then
if [[ "$Server_OS_Version" = "9" ]] || [[ "$Server_OS_Version" = "10" ]]; then
python3 -m venv --system-site-packages /usr/local/CyberPanel
else
PYTHON_PATH=$(which python3 2>/dev/null || which python3.9 2>/dev/null || echo "/usr/bin/python3")
virtualenv -p "$PYTHON_PATH" --system-site-packages /usr/local/CyberPanel
fi
else
virtualenv -p /usr/bin/python3 --system-site-packages /usr/local/CyberPanel
fi
else
echo "Failed to install 'packaging' module using pip."
fi
else
echo "Failed to uninstall 'packaging' module using RPM."
fi
else
echo "'packaging' module is not installed via RPM. No action taken."
fi
else
echo "Operating system is not AlmaLinux. No action taken."
fi
else
echo "virtualenv command executed successfully."
fi
fi
# shellcheck disable=SC1091
. /usr/local/CyberPanel/bin/activate
pip install --upgrade pip setuptools packaging
Download_Requirement
if [[ "$Server_OS" = "CentOS" ]] ; then
# $PIP3 install --default-timeout=3600 virtualenv==16.7.9
# Check_Return
$PIP3 install --default-timeout=3600 --ignore-installed -r /usr/local/requirments.txt
Check_Return
elif [[ "$Server_OS" = "Ubuntu" ]] ; then
# shellcheck disable=SC1091
. /usr/local/CyberPanel/bin/activate
Check_Return
# pip3 install --default-timeout=3600 virtualenv==16.7.9
# Check_Return
pip3 install --default-timeout=3600 --ignore-installed -r /usr/local/requirments.txt
Check_Return
elif [[ "$Server_OS" = "openEuler" ]] ; then
# pip3 install --default-timeout=3600 virtualenv==16.7.9
# Check_Return
pip3 install --default-timeout=3600 --ignore-installed -r /usr/local/requirments.txt
Check_Return
fi
#virtualenv -p /usr/bin/python3 --system-site-packages /usr/local/CyberPanel
# Check_Return
wget "${Git_Content_URL}/${Branch_Name}/plogical/upgrade.py"
if [[ "$Server_Country" = "CN" ]] ; then
sed -i 's|git clone https://github.com/usmannasir/cyberpanel|echo git cloned|g' upgrade.py
Retry_Command "git clone ${Git_Clone_URL}"
Check_Return "git clone ${Git_Clone_URL}"
# shellcheck disable=SC2086
sed -i 's|https://raw.githubusercontent.com/usmannasir/cyberpanel/stable/install/litespeed/httpd_config.xml|'${Git_Content_URL}/${Branch_Name}'//install/litespeed/httpd_config.xml|g' upgrade.py
sed -i 's|https://cyberpanel.sh/composer.sh|https://gitee.com/qtwrk/cyberpanel/raw/stable/install/composer_cn.sh|g' upgrade.py
fi
}
# (Pre_Upgrade_Setup_Git_URL is defined earlier; this duplicate removed so --repo is respected)

View File

@@ -0,0 +1,16 @@
#!/usr/bin/env bash
# CyberPanel upgrade branch input prompt. Sourced by cyberpanel_upgrade.sh.
Pre_Upgrade_Branch_Input() {
echo -e "\nPress the Enter key to continue with latest version, or enter specific version such as: \e[31m2.3.4\e[39m , \e[31m2.4.4\e[39m ...etc"
echo -e "\nIf nothing is input in 10 seconds, script will proceed with the latest stable version. "
echo -e "\nPlease press the Enter key or specify a version number, or wait for 10 seconds: "
printf "%s" ""
read -r -t 10 Tmp_Input
if [[ $Tmp_Input = "" ]]; then
echo -e "Branch name set to $Branch_Name"
else
Branch_Check "$Tmp_Input"
fi
}

View File

@@ -0,0 +1,341 @@
#!/usr/bin/env bash
# CyberPanel upgrade main upgrade (Python, upgrade.py, venv, WSGI). Sourced by cyberpanel_upgrade.sh.
Main_Upgrade() {
echo -e "\n[$(date +"%Y-%m-%d %H:%M:%S")] Starting Main_Upgrade function..." | tee -a /var/log/cyberpanel_upgrade_debug.log
# Resolve Python for upgrade (avoid FileNotFoundError when /usr/local/CyberPanel/bin/python missing)
CP_PYTHON=""
for py in /usr/local/CyberPanel/bin/python /usr/local/CyberCP/bin/python /usr/bin/python3 /usr/local/bin/python3; do
if [[ -x "$py" ]]; then CP_PYTHON="$py"; break; fi
done
if [[ -z "$CP_PYTHON" ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] ERROR: No Python found for upgrade (tried CyberPanel, CyberCP, python3)" | tee -a /var/log/cyberpanel_upgrade_debug.log
exit 1
fi
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Using Python: $CP_PYTHON" | tee -a /var/log/cyberpanel_upgrade_debug.log
# Ensure ols_binaries_config exists (required by upgrade.py; may be missing when upgrading from older versions)
mkdir -p /usr/local/CyberCP/install
if [[ ! -f /usr/local/CyberCP/install/ols_binaries_config.py ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Downloading ols_binaries_config.py (required for upgrade)..." | tee -a /var/log/cyberpanel_upgrade_debug.log
wget -q -O /usr/local/CyberCP/install/ols_binaries_config.py "${Git_Content_URL}/${Branch_Name}/install/ols_binaries_config.py" 2>/dev/null || \
curl -sL -o /usr/local/CyberCP/install/ols_binaries_config.py "${Git_Content_URL}/${Branch_Name}/install/ols_binaries_config.py" 2>/dev/null || true
fi
if [[ ! -f /usr/local/CyberCP/install/ols_binaries_config.py ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] WARNING: ols_binaries_config.py not found; upgrade.py may fail with ModuleNotFoundError" | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Running: $CP_PYTHON upgrade.py $Branch_Name" | tee -a /var/log/cyberpanel_upgrade_debug.log
# Run upgrade.py and capture output
upgrade_output=$("$CP_PYTHON" upgrade.py "$Branch_Name" 2>&1)
RETURN_CODE=$?
echo "$upgrade_output" | tee -a /var/log/cyberpanel_upgrade_debug.log
# Check for TypeError specifically
if echo "$upgrade_output" | grep -q "TypeError: expected string or bytes-like object"; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] WARNING: TypeError detected in upgrade.py, but continuing..." | tee -a /var/log/cyberpanel_upgrade_debug.log
# Check if upgrade actually completed despite the error
if echo "$upgrade_output" | grep -q "Upgrade Completed"; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Upgrade completed despite TypeError" | tee -a /var/log/cyberpanel_upgrade_debug.log
RETURN_CODE=0
fi
fi
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Python upgrade.py returned code: $RETURN_CODE" | tee -a /var/log/cyberpanel_upgrade_debug.log
# Check if the command was successful (return code 0)
if [ $RETURN_CODE -eq 0 ]; then
echo "Upgrade successful."
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] First upgrade attempt successful" | tee -a /var/log/cyberpanel_upgrade_debug.log
else
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] First upgrade attempt failed with code $RETURN_CODE, starting fallback..." | tee -a /var/log/cyberpanel_upgrade_debug.log
if [ -e /usr/bin/pip3 ]; then
PIP3="/usr/bin/pip3"
else
PIP3="pip3.6"
fi
rm -rf /usr/local/CyberPanelTemp
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Creating temporary virtual environment for fallback upgrade..." | tee -a /var/log/cyberpanel_upgrade_debug.log
# Try python3 -m venv first (more reliable on Ubuntu 22.04)
if python3 -m venv --system-site-packages /usr/local/CyberPanelTemp 2>/dev/null; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Temporary virtualenv created with python3 -m venv" | tee -a /var/log/cyberpanel_upgrade_debug.log
else
# Fallback to virtualenv command
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Trying virtualenv command for temporary environment..." | tee -a /var/log/cyberpanel_upgrade_debug.log
virtualenv -p /usr/bin/python3 --system-site-packages /usr/local/CyberPanelTemp 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
# shellcheck disable=SC1091
. /usr/local/CyberPanelTemp/bin/activate
wget -O /usr/local/requirments-old.txt "${Git_Content_URL}/${Branch_Name}/requirments-old.txt"
if [[ "$Server_OS" = "CentOS" ]] ; then
# $PIP3 install --default-timeout=3600 virtualenv==16.7.9
# Check_Return
$PIP3 install --default-timeout=3600 --ignore-installed -r /usr/local/requirments-old.txt
Check_Return
elif [[ "$Server_OS" = "Ubuntu" ]] ; then
# shellcheck disable=SC1091
. /usr/local/CyberPanelTemp/bin/activate
Check_Return
pip3 install --default-timeout=3600 --ignore-installed -r /usr/local/requirments-old.txt
Check_Return
elif [[ "$Server_OS" = "openEuler" ]] ; then
pip3 install --default-timeout=3600 --ignore-installed -r /usr/local/requirments-old.txt
Check_Return
fi
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Running fallback: /usr/local/CyberPanelTemp/bin/python upgrade.py $Branch_Name" | tee -a /var/log/cyberpanel_upgrade_debug.log
/usr/local/CyberPanelTemp/bin/python upgrade.py "$Branch_Name" 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log
FALLBACK_CODE=$?
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Fallback upgrade returned code: $FALLBACK_CODE" | tee -a /var/log/cyberpanel_upgrade_debug.log
Check_Return
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Removing temporary environment..." | tee -a /var/log/cyberpanel_upgrade_debug.log
rm -rf /usr/local/CyberPanelTemp
fi
echo -e "\n[$(date +"%Y-%m-%d %H:%M:%S")] Starting post-upgrade cleanup..." | tee -a /var/log/cyberpanel_upgrade_debug.log
# Check if we need to recreate due to Python 2
NEEDS_RECREATE=0
if [[ -f /usr/local/CyberCP/bin/python2 ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Found Python 2 in CyberCP, will recreate with Python 3..." | tee -a /var/log/cyberpanel_upgrade_debug.log
NEEDS_RECREATE=1
fi
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Removing old CyberCP virtual environment directories..." | tee -a /var/log/cyberpanel_upgrade_debug.log
rm -rf /usr/local/CyberCP/bin
rm -rf /usr/local/CyberCP/lib
rm -rf /usr/local/CyberCP/lib64
rm -rf /usr/local/CyberCP/pyvenv.cfg
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Checking CyberCP virtual environment status after cleanup..." | tee -a /var/log/cyberpanel_upgrade_debug.log
# After removing directories, we always need to recreate
if [[ $NEEDS_RECREATE -eq 1 ]] || [[ ! -d /usr/local/CyberCP/bin ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Creating/recreating CyberCP virtual environment with Python 3..." | tee -a /var/log/cyberpanel_upgrade_debug.log
# First ensure the directory exists
mkdir -p /usr/local/CyberCP
# For Ubuntu 22.04+, we need to handle virtualenv differently
VENV_SUCCESS=0
# First try using python3 -m venv (more reliable on Ubuntu 22.04)
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Attempting to create virtual environment using python3 -m venv..." | tee -a /var/log/cyberpanel_upgrade_debug.log
virtualenv_output=$(python3 -m venv --system-site-packages /usr/local/CyberCP 2>&1)
VENV_CODE=$?
echo "$virtualenv_output" | tee -a /var/log/cyberpanel_upgrade_debug.log
if [[ $VENV_CODE -eq 0 ]] && [[ -f /usr/local/CyberCP/bin/activate ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Virtual environment created successfully using python3 -m venv" | tee -a /var/log/cyberpanel_upgrade_debug.log
VENV_SUCCESS=1
else
# If that fails, try virtualenv command
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] python3 -m venv failed, trying virtualenv command..." | tee -a /var/log/cyberpanel_upgrade_debug.log
# On Ubuntu 22.04, we need to ensure proper virtualenv installation
if [[ "$Server_OS" = "Ubuntu" ]] && [[ "$Server_OS_Version" = "22" ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Ubuntu 22.04 detected, ensuring virtualenv is properly installed..." | tee -a /var/log/cyberpanel_upgrade_debug.log
pip3 install --upgrade virtualenv 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log
elif [[ "$Server_OS" = "CentOS" ]] && ([[ "$Server_OS_Version" = "9" ]] || [[ "$Server_OS_Version" = "10" ]]); then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] AlmaLinux/Rocky Linux 9/10 detected, ensuring virtualenv is properly installed..." | tee -a /var/log/cyberpanel_upgrade_debug.log
pip3 install --upgrade virtualenv 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log
elif [[ "$Server_OS" = "AlmaLinux9" ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] AlmaLinux 9 detected, ensuring virtualenv is properly installed..." | tee -a /var/log/cyberpanel_upgrade_debug.log
pip3 install --upgrade virtualenv 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
# Find the correct python3 path
if [[ "$Server_OS" = "CentOS" ]] && ([[ "$Server_OS_Version" = "9" ]] || [[ "$Server_OS_Version" = "10" ]]); then
PYTHON_PATH=$(which python3 2>/dev/null || which python3.9 2>/dev/null || echo "/usr/bin/python3")
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Using Python path: $PYTHON_PATH" | tee -a /var/log/cyberpanel_upgrade_debug.log
virtualenv_output=$(virtualenv -p "$PYTHON_PATH" /usr/local/CyberCP 2>&1)
elif [[ "$Server_OS" = "AlmaLinux9" ]]; then
PYTHON_PATH=$(which python3 2>/dev/null || which python3.9 2>/dev/null || echo "/usr/bin/python3")
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] AlmaLinux 9 - Using Python path: $PYTHON_PATH" | tee -a /var/log/cyberpanel_upgrade_debug.log
virtualenv_output=$(virtualenv -p "$PYTHON_PATH" /usr/local/CyberCP 2>&1)
else
virtualenv_output=$(virtualenv -p /usr/bin/python3 /usr/local/CyberCP 2>&1)
fi
VENV_CODE=$?
echo "$virtualenv_output" | tee -a /var/log/cyberpanel_upgrade_debug.log
# Check if TypeError occurred (common on Ubuntu 22.04)
if echo "$virtualenv_output" | grep -q "TypeError"; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] WARNING: TypeError detected, attempting workaround..." | tee -a /var/log/cyberpanel_upgrade_debug.log
# Try alternative method using explicit system-site-packages
virtualenv_output=$(virtualenv --python=/usr/bin/python3 --system-site-packages /usr/local/CyberCP 2>&1)
VENV_CODE=$?
echo "$virtualenv_output" | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
if [[ -f /usr/local/CyberCP/bin/activate ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Virtual environment created successfully" | tee -a /var/log/cyberpanel_upgrade_debug.log
VENV_SUCCESS=1
VENV_CODE=0
fi
fi
if [[ $VENV_SUCCESS -eq 0 ]]; then
VENV_CODE=1
fi
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Virtualenv creation returned code: $VENV_CODE" | tee -a /var/log/cyberpanel_upgrade_debug.log
if [[ $VENV_CODE -ne 0 ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] FATAL: Virtualenv creation failed with code $VENV_CODE" | tee -a /var/log/cyberpanel_upgrade_debug.log
echo -e "Virtualenv creation failed. Please check the logs at /var/log/cyberpanel_upgrade_debug.log"
exit $VENV_CODE
fi
else
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] CyberCP virtualenv already exists, skipping recreation" | tee -a /var/log/cyberpanel_upgrade_debug.log
echo -e "\nNo need to re-setup virtualenv at /usr/local/CyberCP...\n"
fi
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Removing old requirements file..." | tee -a /var/log/cyberpanel_upgrade_debug.log
rm -f /usr/local/requirments.txt
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Downloading new requirements..." | tee -a /var/log/cyberpanel_upgrade_debug.log
Download_Requirement
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Installing Python packages..." | tee -a /var/log/cyberpanel_upgrade_debug.log
if [ "$Server_OS" = "Ubuntu" ]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Ubuntu detected, activating virtual environment..." | tee -a /var/log/cyberpanel_upgrade_debug.log
# shellcheck disable=SC1091
. /usr/local/CyberCP/bin/activate 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log
ACTIVATE_CODE=$?
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Activate returned code: $ACTIVATE_CODE" | tee -a /var/log/cyberpanel_upgrade_debug.log
Check_Return
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Upgrading setuptools and packaging..." | tee -a /var/log/cyberpanel_upgrade_debug.log
pip install --upgrade setuptools packaging 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Installing requirements..." | tee -a /var/log/cyberpanel_upgrade_debug.log
pip3 install --default-timeout=3600 --ignore-installed -r /usr/local/requirments.txt 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log
PIP_CODE=$?
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Pip install returned code: $PIP_CODE" | tee -a /var/log/cyberpanel_upgrade_debug.log
Check_Return
else
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Non-Ubuntu OS, activating virtual environment..." | tee -a /var/log/cyberpanel_upgrade_debug.log
# shellcheck disable=SC1091
source /usr/local/CyberCP/bin/activate 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log
ACTIVATE_CODE=$?
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Activate returned code: $ACTIVATE_CODE" | tee -a /var/log/cyberpanel_upgrade_debug.log
Check_Return
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Installing requirements..." | tee -a /var/log/cyberpanel_upgrade_debug.log
/usr/local/CyberCP/bin/pip3 install --default-timeout=3600 --ignore-installed -r /usr/local/requirments.txt 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log
PIP_CODE=$?
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Pip install returned code: $PIP_CODE" | tee -a /var/log/cyberpanel_upgrade_debug.log
Check_Return
fi
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Verifying Django installation..." | tee -a /var/log/cyberpanel_upgrade_debug.log
# Test if Django is installed
if ! /usr/local/CyberCP/bin/python -c "import django" 2>/dev/null; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] WARNING: Django not found, installing requirements again..." | tee -a /var/log/cyberpanel_upgrade_debug.log
# Re-activate virtual environment
source /usr/local/CyberCP/bin/activate
# Install MySQL/MariaDB development headers for mysqlclient Python package
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Installing MySQL/MariaDB development headers..." | tee -a /var/log/cyberpanel_upgrade_debug.log
if [[ "$Server_OS" = "Ubuntu" ]] || [[ "$Server_OS" = "Debian" ]]; then
# Ubuntu/Debian
apt-get update -y
apt-get install -y libmariadb-dev libmariadb-dev-compat pkg-config build-essential
elif [[ "$Server_OS" =~ ^(CentOS|RHEL|AlmaLinux|RockyLinux|CloudLinux) ]]; then
# RHEL-based systems
if command -v dnf >/dev/null 2>&1; then
# Remove conflicting packages first
dnf remove -y mariadb mariadb-client-utils mariadb-server || true
dnf remove -y MariaDB-server MariaDB-client MariaDB-devel || true
# Install development packages with conflict resolution
dnf install -y --allowerasing --skip-broken --nobest mariadb-devel pkgconfig gcc python3-devel || \
dnf install -y --allowerasing --skip-broken --nobest mysql-devel pkgconfig gcc python3-devel || \
dnf install -y --allowerasing --skip-broken --nobest mariadb-devel mariadb-connector-c-devel pkgconfig gcc python3-devel
else
yum install -y mariadb-devel pkgconfig gcc python3-devel
fi
fi
# Check if mysql.h is available and create symlink if needed
if [[ ! -f "/usr/include/mysql/mysql.h" ]] && [[ -f "/usr/include/mariadb/mysql.h" ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Creating mysql.h symlink for compatibility..." | tee -a /var/log/cyberpanel_upgrade_debug.log
mkdir -p /usr/include/mysql
ln -sf /usr/include/mariadb/mysql.h /usr/include/mysql/mysql.h
fi
# Re-install requirements
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Re-installing Python requirements..." | tee -a /var/log/cyberpanel_upgrade_debug.log
pip install --default-timeout=3600 --ignore-installed -r /usr/local/requirments.txt 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log
else
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Django is properly installed" | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Installing WSGI-LSAPI with optimized compilation..." | tee -a /var/log/cyberpanel_upgrade_debug.log
# Save current directory
UPGRADE_CWD=$(pwd)
cd /tmp || exit
rm -rf wsgi-lsapi-2.1*
wget -q https://www.litespeedtech.com/packages/lsapi/wsgi-lsapi-2.1.tgz 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log
tar xf wsgi-lsapi-2.1.tgz
cd wsgi-lsapi-2.1 || exit
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Configuring WSGI..." | tee -a /var/log/cyberpanel_upgrade_debug.log
PYTHON_CFG="${CP_PYTHON:-/usr/bin/python3}"
[[ -x "$PYTHON_CFG" ]] || PYTHON_CFG="/usr/bin/python3"
"$PYTHON_CFG" ./configure.py 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log
# Fix Makefile to use proper optimization flags to avoid _FORTIFY_SOURCE warnings
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Optimizing Makefile for proper compilation..." | tee -a /var/log/cyberpanel_upgrade_debug.log
if [[ -f Makefile ]]; then
# Replace -O0 -g3 with -O2 -g to satisfy _FORTIFY_SOURCE
sed -i 's/-O0 -g3/-O2 -g/g' Makefile
# Ensure we have proper optimization flags
if grep -q "CFLAGS" Makefile && ! grep -qF '-O2' Makefile; then
sed -i 's/CFLAGS =/CFLAGS = -O2/' Makefile
fi
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Makefile optimized for proper compilation" | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Compiling WSGI with optimized flags..." | tee -a /var/log/cyberpanel_upgrade_debug.log
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] (Upstream WSGI source may show harmless strncpy/gstate warnings; build can still succeed.)" | tee -a /var/log/cyberpanel_upgrade_debug.log
make clean 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log
make 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Installing lswsgi binary..." | tee -a /var/log/cyberpanel_upgrade_debug.log
rm -f /usr/local/CyberCP/bin/lswsgi
cp lswsgi /usr/local/CyberCP/bin/
chmod +x /usr/local/CyberCP/bin/lswsgi
# Return to original directory
cd "$UPGRADE_CWD" || cd /root
# Final verification
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Running final verification..." | tee -a /var/log/cyberpanel_upgrade_debug.log
if /usr/local/CyberCP/bin/python -c "import django" 2>/dev/null && [[ -f /usr/local/CyberCP/bin/lswsgi ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] All components successfully installed!" | tee -a /var/log/cyberpanel_upgrade_debug.log
else
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] WARNING: Some components may be missing, check logs" | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Main_Upgrade function completed" | tee -a /var/log/cyberpanel_upgrade_debug.log
}
# Sync /usr/local/CyberCP to the latest commit of the upgrade branch so Version Management
# page shows Current commit matching Latest (avoids "please upgrade" when upgrade already ran).
# Backs up and restores CyberCP/settings.py so production DB/config are not overwritten by the repo.

View File

@@ -0,0 +1,43 @@
#!/usr/bin/env bash
# CyberPanel upgrade sync CyberCP to latest commit. Sourced by cyberpanel_upgrade.sh.
Sync_CyberCP_To_Latest() {
if [[ ! -d /usr/local/CyberCP/.git ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] No .git in /usr/local/CyberCP, skipping sync" | tee -a /var/log/cyberpanel_upgrade_debug.log
return 0
fi
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Syncing /usr/local/CyberCP to latest commit for branch: $Branch_Name" | tee -a /var/log/cyberpanel_upgrade_debug.log
# Backup production settings so sync does not overwrite DB credentials / local config
if [[ -f /usr/local/CyberCP/CyberCP/settings.py ]]; then
cp /usr/local/CyberCP/CyberCP/settings.py /tmp/cyberpanel_settings_backup.py
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Backed up settings.py for restore after sync" | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
(
cd /usr/local/CyberCP
git fetch origin 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log
if git show-ref -q "refs/remotes/origin/$Branch_Name"; then
git checkout -B "$Branch_Name" "origin/$Branch_Name" 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log
else
git checkout "$Branch_Name" 2>/dev/null || true
git pull --ff-only origin "$Branch_Name" 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log || true
fi
)
local sync_code=$?
# Restore production settings so panel keeps working (DB, secrets, etc.)
if [[ -f /tmp/cyberpanel_settings_backup.py ]]; then
cp /tmp/cyberpanel_settings_backup.py /usr/local/CyberCP/CyberCP/settings.py
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Restored settings.py after sync" | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
# LiteSpeed serves /static/ from public/static/; ensure it has latest baseTemplate static files (e.g. dashboard JS)
if [[ -d /usr/local/CyberCP/public/static ]] && [[ -d /usr/local/CyberCP/baseTemplate/static/baseTemplate ]]; then
rsync -a /usr/local/CyberCP/baseTemplate/static/baseTemplate/ /usr/local/CyberCP/public/static/baseTemplate/ 2>/dev/null || \
cp -r /usr/local/CyberCP/baseTemplate/static/baseTemplate/* /usr/local/CyberCP/public/static/baseTemplate/ 2>/dev/null || true
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Synced baseTemplate static to public/static" | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
if [[ $sync_code -eq 0 ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Sync completed. Current HEAD: $(git -C /usr/local/CyberCP rev-parse HEAD 2>/dev/null || echo 'unknown')" | tee -a /var/log/cyberpanel_upgrade_debug.log
else
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Sync returned code $sync_code (non-fatal)" | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
return 0
}

View File

@@ -0,0 +1,336 @@
#!/usr/bin/env bash
# CyberPanel upgrade post-upgrade system tweaks (PHP, LSWS, SnappyMail, etc.). Sourced by cyberpanel_upgrade.sh.
Post_Upgrade_System_Tweak() {
if [[ "$Server_OS" = "CentOS" ]] ; then
#for cenots 7/8
if [[ "$Server_OS_Version" = "7" ]] ; then
sed -i 's|error_reporting = E_ALL \&amp; ~E_DEPRECATED \&amp; ~E_STRICT|error_reporting = E_ALL \& ~E_DEPRECATED \& ~E_STRICT|g' /usr/local/lsws/{lsphp72,lsphp73}/etc/php.ini
#fix php.ini &amp; issue
if ! yum list installed lsphp74-devel ; then
yum install -y lsphp74-devel
fi
if [[ ! -f /usr/local/lsws/lsphp74/lib64/php/modules/zip.so ]] ; then
if yum list installed libzip-devel >/dev/null 2>&1 ; then
yum remove -y libzip-devel
fi
yum install -y https://cyberpanel.sh/misc/libzip-0.11.2-6.el7.psychotic.x86_64.rpm
yum install -y https://cyberpanel.sh/misc/libzip-devel-0.11.2-6.el7.psychotic.x86_64.rpm
yum install lsphp74-devel
if [[ ! -d /usr/local/lsws/lsphp74/tmp ]]; then
mkdir /usr/local/lsws/lsphp74/tmp
fi
/usr/local/lsws/lsphp74/bin/pecl channel-update pecl.php.net
/usr/local/lsws/lsphp74/bin/pear config-set temp_dir /usr/local/lsws/lsphp74/tmp
if /usr/local/lsws/lsphp74/bin/pecl install zip ; then
echo "extension=zip.so" >/usr/local/lsws/lsphp74/etc/php.d/20-zip.ini
chmod 755 /usr/local/lsws/lsphp74/lib64/php/modules/zip.so
else
echo -e "\nlsphp74-zip compilation failed..."
fi
#fix old legacy lsphp74-zip issue on centos 7
fi
#for centos 7
elif [[ "$Server_OS_Version" = "8" ]] ; then
:
#for centos 8
fi
fi
if [[ "$Server_OS" = "Ubuntu" ]] ; then
if ! dpkg -l lsphp74-dev >/dev/null 2>&1 ; then
apt install -y lsphp74-dev
fi
if [[ ! -f /usr/sbin/ipset ]] ; then
ln -s /sbin/ipset /usr/sbin/ipset
fi
#for ubuntu 18/20
if [[ "$Server_OS_Version" = "18" ]] ; then
:
#for ubuntu 18
elif [[ "$Server_OS_Version" = "20" ]] ; then
:
#for ubuntu 20
fi
fi
sed -i "s|lsws-5.3.8|lsws-$LSWS_Stable_Version|g" /usr/local/CyberCP/serverStatus/serverStatusUtil.py
sed -i "s|lsws-5.4.2|lsws-$LSWS_Stable_Version|g" /usr/local/CyberCP/serverStatus/serverStatusUtil.py
sed -i "s|lsws-5.3.5|lsws-$LSWS_Stable_Version|g" /usr/local/CyberCP/serverStatus/serverStatusUtil.py
sed -i "s|lsws-6.0|lsws-$LSWS_Stable_Version|g" /usr/local/CyberCP/serverStatus/serverStatusUtil.py
sed -i "s|lsws-6.3.4|lsws-$LSWS_Stable_Version|g" /usr/local/CyberCP/serverStatus/serverStatusUtil.py
if [[ "$Server_Country" = "CN" ]] ; then
sed -i 's|https://www.litespeedtech.com/|https://cyberpanel.sh/www.litespeedtech.com/|g' /usr/local/CyberCP/serverStatus/serverStatusUtil.py
sed -i 's|http://license.litespeedtech.com/|https://cyberpanel.sh/license.litespeedtech.com/|g' /usr/local/CyberCP/serverStatus/serverStatusUtil.py
fi
sed -i 's|python2|python|g' /usr/bin/adminPass
chmod 700 /usr/bin/adminPass
rm -f /usr/bin/php
ln -s /usr/local/lsws/lsphp74/bin/php /usr/bin/php
if [[ -f /etc/cyberpanel/webadmin_passwd ]]; then
chmod 600 /etc/cyberpanel/webadmin_passwd
fi
chown lsadm:lsadm /usr/local/lsws/admin/conf/htpasswd
chmod 600 /usr/local/lsws/admin/conf/htpasswd
if [[ -f /etc/pure-ftpd/pure-ftpd.conf ]]; then
sed -i 's|NoAnonymous no|NoAnonymous yes|g' /etc/pure-ftpd/pure-ftpd.conf
fi
Tmp_Output=$(timeout 3 openssl s_client -connect 127.0.0.1:8090 2>/dev/null)
if echo "$Tmp_Output" | grep -q "mail@example.com" ; then
# it is using default installer generated cert
Regenerate_Cert 8090
fi
Tmp_Output=$(timeout 3 openssl s_client -connect 127.0.0.1:7080 2>/dev/null)
if echo "$Tmp_Output" | grep -q "mail@example.com" ; then
Regenerate_Cert 7080
fi
if [[ ! -f /usr/bin/cyberpanel_utility ]]; then
wget -q -O /usr/bin/cyberpanel_utility https://cyberpanel.sh/misc/cyberpanel_utility.sh
chmod 700 /usr/bin/cyberpanel_utility
fi
if [[ -f /etc/cyberpanel/watchdog.sh ]] ; then
watchdog kill
rm -f /etc/cyberpanel/watchdog.sh
rm -f /usr/local/bin/watchdog
wget -O /etc/cyberpanel/watchdog.sh "${Git_Content_URL}/${Branch_Name}/CPScripts/watchdog.sh"
chmod 700 /etc/cyberpanel/watchdog.sh
ln -s /etc/cyberpanel/watchdog.sh /usr/local/bin/watchdog
watchdog status
fi
rm -f /usr/local/composer.sh
rm -f /usr/local/requirments.txt
chown -R cyberpanel:cyberpanel /usr/local/CyberCP/lib
chown -R cyberpanel:cyberpanel /usr/local/CyberCP/lib64
# Fix missing lsphp binary in /usr/local/lscp/fcgi-bin/ after upgrade
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Checking and restoring lsphp binary if missing..." | tee -a /var/log/cyberpanel_upgrade_debug.log
if [[ ! -f /usr/local/lscp/fcgi-bin/lsphp ]] || [[ ! -s /usr/local/lscp/fcgi-bin/lsphp ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] lsphp binary missing or empty, attempting to restore..." | tee -a /var/log/cyberpanel_upgrade_debug.log
# Ensure fcgi-bin directory exists
mkdir -p /usr/local/lscp/fcgi-bin
# Find the latest available PHP version and use it
PHP_RESTORED=0
# Try to find the latest lsphp version (check from newest to oldest)
# Priority: 85 (beta), 84, 83, 82, 81, 80, 74
for PHP_VER in 85 84 83 82 81 80 74; do
if [[ -f /usr/local/lsws/lsphp${PHP_VER}/bin/lsphp ]]; then
# Try to create symlink first (preferred)
if ln -sf /usr/local/lsws/lsphp${PHP_VER}/bin/lsphp /usr/local/lscp/fcgi-bin/lsphp 2>/dev/null; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] lsphp symlink created from lsphp${PHP_VER}" | tee -a /var/log/cyberpanel_upgrade_debug.log
else
# If symlink fails, copy the file
cp -f /usr/local/lsws/lsphp${PHP_VER}/bin/lsphp /usr/local/lscp/fcgi-bin/lsphp
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] lsphp binary copied from lsphp${PHP_VER}" | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
chown root:root /usr/local/lscp/fcgi-bin/lsphp
chmod 755 /usr/local/lscp/fcgi-bin/lsphp
PHP_RESTORED=1
break
fi
done
# If no lsphp version found, try php binary as fallback
if [[ $PHP_RESTORED -eq 0 ]]; then
for PHP_VER in 83 82 81 80 74 73 72; do
if [[ -f /usr/local/lsws/lsphp${PHP_VER}/bin/php ]]; then
# Try to create symlink first (preferred)
if ln -sf /usr/local/lsws/lsphp${PHP_VER}/bin/php /usr/local/lscp/fcgi-bin/lsphp 2>/dev/null; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] lsphp symlink created from php${PHP_VER} (lsphp fallback)" | tee -a /var/log/cyberpanel_upgrade_debug.log
else
# If symlink fails, copy the file
cp -f /usr/local/lsws/lsphp${PHP_VER}/bin/php /usr/local/lscp/fcgi-bin/lsphp
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] lsphp binary copied from php${PHP_VER} (lsphp fallback)" | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
chown root:root /usr/local/lscp/fcgi-bin/lsphp
chmod 755 /usr/local/lscp/fcgi-bin/lsphp
PHP_RESTORED=1
break
fi
done
fi
# If no lsphp version found, try admin_php5 as fallback
if [[ $PHP_RESTORED -eq 0 ]]; then
if [[ -f /usr/local/lscp/admin/fcgi-bin/admin_php5 ]]; then
cp -f /usr/local/lscp/admin/fcgi-bin/admin_php5 /usr/local/lscp/fcgi-bin/lsphp
chown root:root /usr/local/lscp/fcgi-bin/lsphp
chmod 755 /usr/local/lscp/fcgi-bin/lsphp
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] lsphp binary restored from admin_php5 (fallback)" | tee -a /var/log/cyberpanel_upgrade_debug.log
elif [[ -f /usr/local/lscp/admin/fcgi-bin/admin_php ]]; then
cp -f /usr/local/lscp/admin/fcgi-bin/admin_php /usr/local/lscp/fcgi-bin/lsphp
chown root:root /usr/local/lscp/fcgi-bin/lsphp
chmod 755 /usr/local/lscp/fcgi-bin/lsphp
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] lsphp binary restored from admin_php (fallback)" | tee -a /var/log/cyberpanel_upgrade_debug.log
elif [[ -f /usr/local/lsws/admin/fcgi-bin/admin_php5 ]]; then
cp -f /usr/local/lsws/admin/fcgi-bin/admin_php5 /usr/local/lscp/fcgi-bin/lsphp
chown root:root /usr/local/lscp/fcgi-bin/lsphp
chmod 755 /usr/local/lscp/fcgi-bin/lsphp
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] lsphp binary restored from lsws admin_php5 (fallback)" | tee -a /var/log/cyberpanel_upgrade_debug.log
else
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] ERROR: Could not find any PHP binary to restore lsphp" | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
fi
# Create symlinks if they don't exist
if [[ -f /usr/local/lscp/fcgi-bin/lsphp ]]; then
if [[ ! -f /usr/local/lscp/fcgi-bin/lsphp4 ]]; then
ln -sf ./lsphp /usr/local/lscp/fcgi-bin/lsphp4
fi
if [[ ! -f /usr/local/lscp/fcgi-bin/lsphp5 ]]; then
ln -sf ./lsphp /usr/local/lscp/fcgi-bin/lsphp5
fi
fi
fi
# Fix missing lscpd binary in /usr/local/lscp/bin/ after upgrade
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Checking and restoring lscpd binary if missing..." | tee -a /var/log/cyberpanel_upgrade_debug.log
if [[ ! -f /usr/local/lscp/bin/lscpd ]] || [[ ! -s /usr/local/lscp/bin/lscpd ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] lscpd binary missing or empty, attempting to restore..." | tee -a /var/log/cyberpanel_upgrade_debug.log
# Ensure lscp bin directory exists
mkdir -p /usr/local/lscp/bin
# Select the correct lscpd binary based on OS and version
lscpd_selection='lscpd-0.3.1'
# Check if this is an ARM system
if uname -a | grep -q 'aarch64'; then
lscpd_selection='lscpd.aarch64'
else
# For x86_64 systems, check Ubuntu version
if [[ "$Server_OS" = "Ubuntu" ]] && [[ -f /etc/lsb-release ]]; then
ubuntu_version=$(grep 'DISTRIB_RELEASE' /etc/lsb-release | cut -d'=' -f2 | cut -d'.' -f1)
if [[ "$ubuntu_version" = "22" ]] || [[ "$ubuntu_version" = "24" ]]; then
lscpd_selection='lscpd.0.4.0'
fi
fi
fi
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Selected lscpd binary: $lscpd_selection" | tee -a /var/log/cyberpanel_upgrade_debug.log
# Copy the selected binary from CyberCP to lscp bin
if [[ -f /usr/local/CyberCP/${lscpd_selection} ]]; then
cp -f /usr/local/CyberCP/${lscpd_selection} /usr/local/lscp/bin/${lscpd_selection}
rm -f /usr/local/lscp/bin/lscpd
mv /usr/local/lscp/bin/${lscpd_selection} /usr/local/lscp/bin/lscpd
chmod 755 /usr/local/lscp/bin/lscpd
chown root:root /usr/local/lscp/bin/lscpd
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] lscpd binary restored successfully from ${lscpd_selection}" | tee -a /var/log/cyberpanel_upgrade_debug.log
else
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] ERROR: Could not find lscpd source binary ${lscpd_selection} in /usr/local/CyberCP/" | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
else
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] lscpd binary exists and is valid" | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
if [[ "$Server_OS_Version" = "9" ]] || [[ "$Server_OS_Version" = "10" ]] || [[ "$Server_OS_Version" = "18" ]] || [[ "$Server_OS_Version" = "8" ]] || [[ "$Server_OS_Version" = "20" ]] || [[ "$Server_OS_Version" = "24" ]]; then
echo "PYTHONHOME=/usr" > /usr/local/lscp/conf/pythonenv.conf
else
# Uncomment and use the following lines if necessary for other OS versions
# rsync -av --ignore-existing /usr/lib64/python3.9/ /usr/local/CyberCP/lib64/python3.9/
# Check_Return
:
fi
# Fix SnappyMail directory permissions for Ubuntu 24.04 and other systems
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Checking SnappyMail directories..." | tee -a /var/log/cyberpanel_upgrade_debug.log
# Migrate data from old rainloop folder to new snappymail folder (2.4.4 -> 2.5.5 upgrade)
if [ -d "/usr/local/lscp/cyberpanel/rainloop/data" ] && [ "$(ls -A /usr/local/lscp/cyberpanel/rainloop/data 2>/dev/null)" ]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Migrating rainloop data to snappymail..." | tee -a /var/log/cyberpanel_upgrade_debug.log
# Check if snappymail data already exists with content
if [ -d "/usr/local/lscp/cyberpanel/snappymail/data" ] && [ -d "/usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/configs" ]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] SnappyMail data already exists, skipping migration" | tee -a /var/log/cyberpanel_upgrade_debug.log
else
# Create SnappyMail data directories if they don't exist
mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/configs/
mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/domains/
mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/storage/
mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/temp/
mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/cache/
# Migrate data using rsync (preserves permissions and ownership)
rsync -av --ignore-existing /usr/local/lscp/cyberpanel/rainloop/data/ /usr/local/lscp/cyberpanel/snappymail/data/ 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log
if [ $? -eq 0 ]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Successfully migrated rainloop data to snappymail" | tee -a /var/log/cyberpanel_upgrade_debug.log
# Update include.php to use snappymail path
if [ -f "/usr/local/CyberCP/public/snappymail/include.php" ]; then
sed -i 's|/usr/local/lscp/cyberpanel/rainloop/data|/usr/local/lscp/cyberpanel/snappymail/data|g' /usr/local/CyberCP/public/snappymail/include.php
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Updated include.php to use snappymail data path" | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
else
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] WARNING: Data migration completed with errors" | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
fi
else
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] No old rainloop data found, creating new SnappyMail directories..." | tee -a /var/log/cyberpanel_upgrade_debug.log
# Create SnappyMail data directories if they don't exist
mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/configs/
mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/domains/
mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/storage/
mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/temp/
mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/cache/
fi
# Ensure proper ownership for SnappyMail data directories
if id -u lscpd >/dev/null 2>&1; then
chown -R lscpd:lscpd /usr/local/lscp/cyberpanel/snappymail/
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Set SnappyMail ownership to lscpd:lscpd" | tee -a /var/log/cyberpanel_upgrade_debug.log
else
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] WARNING: lscpd user not found, skipping ownership change" | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
# Set proper permissions for SnappyMail data directories (group writable)
chmod -R 775 /usr/local/lscp/cyberpanel/snappymail/data/
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Set SnappyMail data directory permissions to 775 (group writable)" | tee -a /var/log/cyberpanel_upgrade_debug.log
# Ensure web server users are in the lscpd group for access
usermod -a -G lscpd nobody 2>/dev/null || true
# Fix SnappyMail public directory ownership (critical fix)
chown -R lscpd:lscpd /usr/local/CyberCP/public/snappymail/data 2>/dev/null || true
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Added web server users to lscpd group and fixed SnappyMail ownership" | tee -a /var/log/cyberpanel_upgrade_debug.log
# Force phpMyAdmin to use 127.0.0.1 (TCP) so it shows the same MariaDB version as CLI (main instance on 3306)
if [ -f /usr/local/CyberCP/public/phpmyadmin/config.inc.php ]; then
if ! grep -q "\$cfg\['Servers'\]\[\$i\]\['host'\] = '127.0.0.1'" /usr/local/CyberCP/public/phpmyadmin/config.inc.php 2>/dev/null; then
sed -i "/SignonURL/a \$cfg['Servers'][\$i]['host'] = '127.0.0.1';\n\$cfg['Servers'][\$i]['port'] = '3306';" /usr/local/CyberCP/public/phpmyadmin/config.inc.php 2>/dev/null || true
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Set phpMyAdmin server host to 127.0.0.1" | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
fi
if [ -f /usr/local/CyberCP/public/phpmyadmin/phpmyadminsignin.php ]; then
sed -i "/trim.*\$_POST.*host.*localhost/s/'localhost'/'127.0.0.1'/g" /usr/local/CyberCP/public/phpmyadmin/phpmyadminsignin.php 2>/dev/null || true
grep -q "127.0.0.1" /usr/local/CyberCP/public/phpmyadmin/phpmyadminsignin.php && echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] phpMyAdmin signon default host set to 127.0.0.1" | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
systemctl restart lscpd
}

View File

@@ -0,0 +1,122 @@
#!/usr/bin/env bash
# CyberPanel upgrade final display (banner, next steps). Sourced by cyberpanel_upgrade.sh.
Post_Install_Display_Final_Info() {
echo -e "\n"
# Fixed box width (109 chars). ASCII-only borders (| - +) so right edge renders solid in all terminals.
BOX_W=109
# 109 dashes for top/bottom border (no Unicode = so line is consistently filled)
_br() { echo "+-------------------------------------------------------------------------------------------------------------+"; }
_bl() { echo "+-------------------------------------------------------------------------------------------------------------+"; }
_b() { local s="$1"; [[ ${#s} -gt $BOX_W ]] && s="${s:0:BOX_W}"; printf '|%-*s|\n' "$BOX_W" "$s"; }
_br
_b ""
_b " █████████ █████ ███████████ ████"
_b " ███▒▒▒▒▒███ ▒▒███ ▒▒███▒▒▒▒▒███ ▒▒███"
_b " ███ ▒▒▒ █████ ████ ▒███████ ██████ ████████ ▒███ ▒███ ██████ ████████ ██████ ▒███"
_b " ▒███ ▒▒███ ▒███ ▒███▒▒███ ███▒▒███▒▒███▒▒███ ▒██████████ ▒▒▒▒▒███ ▒▒███▒▒███ ███▒▒███ ▒███"
_b " ▒███ ▒███ ▒███ ▒███ ▒███▒███████ ▒███ ▒▒▒ ▒███▒▒▒▒▒▒ ███████ ▒███ ▒███ ▒███████ ▒███"
_b " ▒▒███ ███ ▒███ ▒███ ▒███ ▒███▒███▒▒▒ ▒███ ▒███ ███▒▒███ ▒███ ▒███ ▒███▒▒▒ ▒███"
_b " ▒▒█████████ ▒▒███████ ████████ ▒▒██████ █████ █████ ▒▒████████ ████ █████▒▒██████ █████"
_b " ▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒███ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒"
_b " ███ ▒███"
_b " ▒▒██████"
_b " ▒▒▒▒▒▒"
_b " *** UPGRADE COMPLETED SUCCESSFULLY! ***"
_b ""
_bl
Panel_Port=$(cat /usr/local/lscp/conf/bind.conf)
if [[ $Panel_Port = "" ]] ; then
Panel_Port="8090"
fi
# Resolve server IP for remote access URL (avoid empty Remote: https://:2087)
if [[ -z "$SERVER_IP" ]]; then
SERVER_IP=$(hostname -I 2>/dev/null | awk '{print $1}')
fi
if [[ -z "$SERVER_IP" ]]; then
SERVER_IP=$(ip -4 route get 1 2>/dev/null | awk '/src/ {print $7; exit}')
fi
if [[ -z "$SERVER_IP" ]]; then
SERVER_IP=$(curl -s --max-time 3 ifconfig.me 2>/dev/null || curl -s --max-time 3 icanhazip.com 2>/dev/null)
fi
if [[ -z "$SERVER_IP" ]]; then
SERVER_IP="YOUR_SERVER_IP"
fi
# Actual MariaDB server version (what phpMyAdmin will show)
# Actual server version (use --skip-ssl: 11.x client requires SSL by default, 10.x server may not offer it)
MARIADB_ACTUAL_VER=""
if command -v mariadb >/dev/null 2>&1; then
MARIADB_ACTUAL_VER=$(mariadb --skip-ssl -e "SELECT @@version;" -sN 2>/dev/null | head -1)
fi
[[ -z "$MARIADB_ACTUAL_VER" ]] && command -v mysql >/dev/null 2>&1 && MARIADB_ACTUAL_VER=$(mysql --skip-ssl -e "SELECT @@version;" -sN 2>/dev/null | head -1)
[[ -z "$MARIADB_ACTUAL_VER" ]] && MARIADB_ACTUAL_VER="${MARIADB_VER:-unknown}"
# Test if CyberPanel is accessible
echo -e "\n🔍 Testing CyberPanel accessibility..."
# Check if lscpd service is running
if systemctl is-active --quiet lscpd 2>/dev/null; then
_br
_b ""
_b " ACCESS YOUR CYBERPANEL:"
_b ""
_b " Local: https://127.0.0.1:${Panel_Port#*:}"
_b " Remote: https://${SERVER_IP}:${Panel_Port#*:}"
_b ""
_b " Default Login: admin / 1234567890"
_b " >> Please change the default password immediately!"
_b ""
_bl
# Binary confirmation + versions (ASCII-only so box alignment is correct)
echo -e "\n"
_br
_b ""
_b " UPGRADE STATUS: [====================================================] 100%"
_b ""
_b " [OK] All components installed successfully"
_b " [OK] Python dependencies resolved"
_b " [OK] WSGI-LSAPI compiled with optimizations"
_b " [OK] CyberPanel service is running"
_b " [OK] Web interface is accessible"
_b ""
_b " CyberPanel: ${Branch_Name:-unknown}"
_b " Database (MariaDB): ${MARIADB_ACTUAL_VER}"
_b ""
_b " *** UPGRADE COMPLETED SUCCESSFULLY! ***"
_b ""
_bl
else
echo -e "CyberPanel may not be running properly. Please check the logs."
echo -e "\n"
_br
_b ""
_b " UPGRADE COMPLETED WITH WARNINGS"
_b ""
_b " - CyberPanel files have been updated"
_b " - Some services may need manual restart"
_b " - Please check logs at /var/log/cyberpanel_upgrade_debug.log"
_b ""
_b " Try running: systemctl restart lscpd"
_b ""
_bl
fi
echo -e "\n📋 Next Steps:"
echo -e " 1. Access your CyberPanel at the URL above"
echo -e " 2. Change the default admin password"
echo -e " 3. Configure your domains and websites"
echo -e " 4. Check system status in the dashboard"
echo -e " 5. Check DB version with: mariadb -V (use mariadb, not mysql, to avoid deprecation warning)"
echo -e " 6. Pre-upgrade DB backup (if created): /root/cyberpanel_mariadb_backups/"
echo -e " 7. One-liner: --backup-db (always backup DB), --no-backup-db (skip); omit = prompt. --migrate-to-utf8 for UTF-8 (only if your apps support it)"
echo -e " 8. If you downgrade to MariaDB 10.11.16, server charset stays latin1 for backward compatibility."
echo -e "\n🧹 Cleaning up temporary files..."
rm -rf /root/cyberpanel_upgrade_tmp
echo -e "✅ Cleanup completed\n"
}