2025-09-11 20:04:09 +02:00
{% extends "baseTemplate/index.html" %}
{% load i18n %}
{% load static %}
{% block title %}{% trans "Plugin Development Guide - CyberPanel" %}{% endblock %}
{% block header_scripts %}
< style >
.docs-wrapper {
background: transparent;
padding: 20px;
}
.docs-container {
max-width: 1200px;
margin: 0 auto;
}
.docs-header {
background: var(--bg-primary, white);
border-radius: 12px;
padding: 25px;
margin-bottom: 25px;
box-shadow: var(--shadow-md, 0 2px 8px rgba(0,0,0,0.08));
border: 1px solid var(--border-primary, #e8e9ff);
}
.docs-content {
background: var(--bg-primary, white);
border-radius: 12px;
padding: 25px;
box-shadow: var(--shadow-md, 0 2px 8px rgba(0,0,0,0.08));
border: 1px solid var(--border-primary, #e8e9ff);
}
.docs-nav {
display: flex;
gap: 15px;
margin-bottom: 30px;
flex-wrap: wrap;
}
.nav-button {
background: var(--bg-secondary, #f8f9ff);
color: var(--text-primary, #2f3640);
border: 1px solid var(--border-primary, #e8e9ff);
padding: 12px 20px;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s ease;
font-weight: 500;
text-decoration: none;
display: flex;
align-items: center;
gap: 8px;
}
.nav-button:hover {
background: #5856d6;
color: white;
text-decoration: none;
transform: translateY(-2px);
}
.nav-button.active {
background: #5856d6;
color: white;
}
.docs-section {
display: none;
}
.docs-section.active {
display: block;
}
.section-title {
font-size: 24px;
font-weight: 700;
color: var(--text-primary, #2f3640);
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 2px solid #5856d6;
}
.section-content {
line-height: 1.6;
color: var(--text-secondary, #64748b);
}
.section-content h1,
.section-content h2,
.section-content h3 {
color: var(--text-primary, #2f3640);
margin-top: 30px;
margin-bottom: 15px;
}
.section-content h1 {
font-size: 28px;
border-bottom: 2px solid #5856d6;
padding-bottom: 10px;
}
.section-content h2 {
font-size: 22px;
color: #5856d6;
}
.section-content h3 {
font-size: 18px;
}
.section-content code {
background: var(--bg-secondary, #f8f9ff);
padding: 2px 6px;
border-radius: 4px;
font-family: 'Courier New', monospace;
font-size: 14px;
color: #e83e8c;
}
.section-content pre {
background: var(--bg-secondary, #f8f9ff);
padding: 20px;
border-radius: 8px;
overflow-x: auto;
border: 1px solid var(--border-primary, #e8e9ff);
margin: 15px 0;
}
.section-content pre code {
background: none;
padding: 0;
color: var(--text-primary, #2f3640);
}
.section-content ul,
.section-content ol {
margin: 15px 0;
padding-left: 25px;
}
.section-content li {
margin: 8px 0;
}
.section-content blockquote {
border-left: 4px solid #5856d6;
padding-left: 20px;
margin: 20px 0;
font-style: italic;
color: var(--text-secondary, #64748b);
}
.feature-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
margin: 20px 0;
}
.feature-item {
background: var(--bg-secondary, #f8f9ff);
padding: 20px;
border-radius: 8px;
border: 1px solid var(--border-primary, #e8e9ff);
}
.feature-item h4 {
color: #5856d6;
margin-bottom: 10px;
font-size: 16px;
}
.back-button {
background: #6c757d;
color: white;
border: none;
padding: 10px 20px;
border-radius: 6px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
text-decoration: none;
display: inline-flex;
align-items: center;
gap: 8px;
margin-bottom: 20px;
}
.back-button:hover {
background: #5a6268;
color: white;
text-decoration: none;
}
.toc {
background: var(--bg-secondary, #f8f9ff);
padding: 20px;
border-radius: 8px;
margin-bottom: 30px;
border: 1px solid var(--border-primary, #e8e9ff);
}
.toc h3 {
color: #5856d6;
margin-bottom: 15px;
}
.toc ul {
list-style: none;
padding: 0;
margin: 0;
}
.toc li {
margin: 8px 0;
}
.toc a {
color: var(--text-secondary, #64748b);
text-decoration: none;
transition: color 0.3s ease;
}
.toc a:hover {
color: #5856d6;
}
@media (max-width: 768px) {
.docs-wrapper {
padding: 15px;
}
.docs-nav {
flex-direction: column;
}
.nav-button {
justify-content: center;
}
.feature-list {
grid-template-columns: 1fr;
}
}
< / style >
{% endblock %}
{% block content %}
< div class = "docs-wrapper" >
< div class = "docs-container" >
<!-- Docs Header -->
< div class = "docs-header" >
< h1 >
< i class = "fas fa-book" style = "margin-right: 12px; color: #5856d6;" > < / i >
{% trans "Plugin Development Documentation" %}
< / h1 >
< p > {% trans "Complete guide for developing, installing, and managing CyberPanel plugins" %}< / p >
< / div >
<!-- Navigation -->
< div class = "docs-nav" >
< a href = "#" class = "nav-button active" data-section = "quick-guide" >
< i class = "fas fa-rocket" > < / i >
{% trans "Quick Start" %}
< / a >
< a href = "#" class = "nav-button" data-section = "official-guide" >
< i class = "fas fa-graduation-cap" > < / i >
{% trans "Official Guide" %}
< / a >
< a href = "#" class = "nav-button" data-section = "full-guide" >
< i class = "fas fa-book-open" > < / i >
{% trans "Advanced Guide" %}
< / a >
2025-09-11 20:17:54 +02:00
< a href = "#" class = "nav-button" data-section = "os-compatibility" >
< i class = "fas fa-desktop" > < / i >
{% trans "OS Compatibility" %}
< / a >
2025-09-11 20:04:09 +02:00
< a href = "{% url 'testPlugin:plugin_home' %}" class = "nav-button" >
< i class = "fas fa-arrow-left" > < / i >
{% trans "Back to Plugin" %}
< / a >
< / div >
<!-- Quick Installation Guide -->
< div class = "docs-section active" id = "quick-guide" >
< div class = "docs-content" >
< h1 class = "section-title" > Quick Installation Guide - CyberPanel Test Plugin< / h1 >
< div class = "feature-list" >
< div class = "feature-item" >
< h4 > 🚀 One-Command Installation< / h4 >
< p > Install the test plugin with a single command using curl or wget.< / p >
< / div >
< div class = "feature-item" >
< h4 > 📦 Manual Installation< / h4 >
< p > Download and install manually with step-by-step instructions.< / p >
< / div >
< div class = "feature-item" >
< h4 > ⚙️ Easy Management< / h4 >
< p > Simple install/uninstall process with proper cleanup.< / p >
< / div >
< / div >
< h2 > One-Command Installation< / h2 >
< pre > < code > # Install the test plugin with a single command
curl -sSL https://raw.githubusercontent.com/cyberpanel/testPlugin/main/install.sh | bash< / code > < / pre >
< h2 > Manual Installation< / h2 >
< ol >
< li > < strong > Download the plugin< / strong >
< pre > < code > git clone https://github.com/cyberpanel/testPlugin.git
cd testPlugin< / code > < / pre >
< / li >
< li > < strong > Run the installation script< / strong >
< pre > < code > chmod +x install.sh
./install.sh< / code > < / pre >
< / li >
< li > < strong > Access the plugin< / strong >
< ul >
< li > URL: < code > https://your-domain:8090/testPlugin/< / code > < / li >
< li > Login with your CyberPanel admin credentials< / li >
< / ul >
< / li >
< / ol >
< h2 > Features Included< / h2 >
< div class = "feature-list" >
< div class = "feature-item" >
< h4 > ✅ Enable/Disable Toggle< / h4 >
< p > Toggle the plugin on/off with a beautiful switch< / p >
< / div >
< div class = "feature-item" >
< h4 > ✅ Test Button< / h4 >
< p > Click to show popup messages from the side< / p >
< / div >
< div class = "feature-item" >
< h4 > ✅ Settings Page< / h4 >
< p > Configure custom messages and preferences< / p >
< / div >
< div class = "feature-item" >
< h4 > ✅ Activity Logs< / h4 >
< p > View all plugin activities with filtering< / p >
< / div >
< div class = "feature-item" >
< h4 > ✅ Inline Integration< / h4 >
< p > Loads within CyberPanel interface< / p >
< / div >
< div class = "feature-item" >
< h4 > ✅ Responsive Design< / h4 >
< p > Works perfectly on all devices< / p >
< / div >
< / div >
< h2 > Uninstallation< / h2 >
< pre > < code > # Uninstall the plugin
./install.sh --uninstall< / code > < / pre >
< h2 > Troubleshooting< / h2 >
< p > If you encounter any issues:< / p >
< ol >
< li > < strong > Check CyberPanel logs< / strong >
< pre > < code > tail -f /home/cyberpanel/logs/cyberpanel.log< / code > < / pre >
< / li >
< li > < strong > Restart CyberPanel services< / strong >
< pre > < code > systemctl restart lscpd
systemctl restart cyberpanel< / code > < / pre >
< / li >
< li > < strong > Verify installation< / strong >
< pre > < code > ls -la /home/cyberpanel/plugins/testPlugin
ls -la /usr/local/CyberCP/testPlugin< / code > < / pre >
< / li >
< / ol >
< blockquote >
< strong > Note:< / strong > This plugin is designed for testing and development purposes. Always backup your system before installing any plugins.
< / blockquote >
< / div >
< / div >
<!-- Official CyberPanel Plugin Development Guide -->
< div class = "docs-section" id = "official-guide" >
< div class = "docs-content" >
< h1 class = "section-title" > Getting Started with CyberPanel Plugin Development< / h1 >
< div class = "feature-list" >
< div class = "feature-item" >
< h4 > 🎯 Official Documentation< / h4 >
< p > Based on the official CyberPanel plugin development guide from the CyberPanel team.< / p >
< / div >
< div class = "feature-item" >
< h4 > 📚 Step-by-Step Tutorial< / h4 >
< p > Complete walkthrough from development environment setup to plugin installation.< / p >
< / div >
< div class = "feature-item" >
< h4 > 🔧 Signal Integration< / h4 >
< p > Learn how to hook into CyberPanel events and respond to core functionality.< / p >
< / div >
< / div >
< blockquote >
2025-09-13 17:44:37 +02:00
< strong > Source:< / strong > This guide is based on the official CyberPanel documentation and the < a href = "https://github.com/usmannasir/beautiful_names" target = "_blank" rel = "noopener" > beautiful_names plugin repository< / a > .
2025-09-11 20:04:09 +02:00
< / blockquote >
< h2 > Prerequisites< / h2 >
< ul >
< li > < strong > Python< / strong > - Clear understanding of Python Programming Language< / li >
< li > < strong > Django< / strong > - Experience with Django framework< / li >
< li > < strong > HTML (Basic)< / strong > - Basic HTML knowledge< / li >
< li > < strong > CSS (Basic)< / strong > - Basic CSS knowledge< / li >
< / ul >
< p > < strong > Note:< / strong > You can use plain JavaScript in your plugins or any JavaScript framework. You just have to follow the norms of Django framework, because CyberPanel plugin is just another Django app.< / p >
< h2 > Step 1: Set up your Development Environment< / h2 >
< h3 > Clone CyberPanel Repository< / h3 >
< pre > < code > git clone https://github.com/usmannasir/cyberpanel/ --single-branch v1.7.2-plugin< / code > < / pre >
< h3 > Create a Django App< / h3 >
< pre > < code > cd v1.7.2-plugin
django-admin startapp pluginName< / code > < / pre >
< p > Choose your plugin name wisely as it's of great importance. Once the Django app is created, you need to define a meta file for your plugin so that CyberPanel can read information about your plugin.< / p >
< h3 > Create Meta File< / h3 >
< pre > < code > cd pluginName
nano meta.xml< / code > < / pre >
< p > Paste the following content in the meta.xml file:< / p >
< pre > < code > < ?xml version="1.0" encoding="UTF-8"?>
< cyberpanelPluginConfig>
< name> customplugin< /name>
< type> plugin< /type>
< description> Plugin to make custom changes< /description>
< version> 0< /version>
< /cyberpanelPluginConfig> < / code > < / pre >
< h2 > Step 2: Creating a Signal File and Adjusting Settings< / h2 >
< h3 > Create Signals File< / h3 >
< p > Create a signals.py file (you can name it anything, but signals.py is recommended). You can leave this file empty for now.< / p >
< h3 > Configure apps.py< / h3 >
< p > In your apps.py file, you need to import the signals file inside the ready function:< / p >
< pre > < code > def ready(self):
import signals< / code > < / pre >
< h3 > Configure __init__.py< / h3 >
< p > You need to specify a default_app_config variable in this file:< / p >
< pre > < code > default_app_config = 'examplePlugin.apps.ExamplepluginConfig'< / code > < / pre >
< h3 > Create urls.py< / h3 >
< p > Inside your app root directory, create urls.py and paste this content:< / p >
< pre > < code > from django.conf.urls import url
import views
urlpatterns = [
url(r'^$', views.examplePlugin, name='examplePlugin'),
]< / code > < / pre >
< p > < strong > Important:< / strong > Replace < code > examplePlugin< / code > with your plugin name. This URL definition is very important for CyberPanel to register your plugin page.< / p >
< h3 > Optional Files< / h3 >
< p > You can create these optional files for database model management:< / p >
< ul >
< li > < strong > pre_install< / strong > - Executed before installation of plugin< / li >
< li > < strong > post_install< / strong > - Executed after installation of plugin< / li >
< / ul >
< p > If your file is Python code, don't forget to include this line at the top:< / p >
< pre > < code > #!/usr/local/CyberCP/bin/python2< / code > < / pre >
< h2 > Step 3: Responding to Events< / h2 >
2025-09-13 17:44:37 +02:00
< p > To plug into events fired by CyberPanel core, you can respond to various events happening in the core. Visit the < a href = "http://cyberpanel.net/docs/2-list-of-signals-events-files/" target = "_blank" rel = "noopener" > signal file documentation< / a > for a complete list of events.< / p >
2025-09-11 20:04:09 +02:00
< h3 > Example Events< / h3 >
< ul >
< li > < strong > preWebsiteCreation< / strong > - Fired before CyberPanel starts the creation of website< / li >
< li > < strong > postWebsiteDeletion< / strong > - Fired after core finished the deletion of website< / li >
< / ul >
< h3 > Responding to Events< / h3 >
< p > Here's how you can respond to the < code > postWebsiteDeletion< / code > event:< / p >
< pre > < code > from django.dispatch import receiver
from django.http import HttpResponse
from websiteFunctions.signals import postWebsiteDeletion
from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging
@receiver(postWebsiteDeletion)
def rcvr(sender, **kwargs):
request = kwargs['request']
logging.writeToFile('Hello World from Example Plugin.')
return HttpResponse('Hello World from Example Plugin.')< / code > < / pre >
< h3 > Return Values< / h3 >
< ul >
< li > < strong > HttpResponse object< / strong > - CyberPanel core will stop further processing and return your response to browser< / li >
< li > < strong > int 200< / strong > - CyberPanel core will continue processing, assuming the event was successfully executed< / li >
< / ul >
< h2 > Step 4: Packing, Shipping and Installing Plugin< / h2 >
< h3 > Package Your Plugin< / h3 >
< p > After completing your plugin, zip your Django app. The zip file name should be your plugin name (e.g., < code > examplePlugin.zip< / code > ), otherwise installation will fail.< / p >
< h3 > Installation< / h3 >
< p > First, upload your plugin to < code > /usr/local/CyberCP/pluginInstaller< / code > :< / p >
< pre > < code > cd /usr/local/CyberCP/pluginInstaller
python pluginInstaller.py install --pluginName examplePlugin< / code > < / pre >
< h3 > Uninstall< / h3 >
< pre > < code > cd /usr/local/CyberCP/pluginInstaller
python pluginInstaller.py remove --pluginName examplePlugin< / code > < / pre >
< h2 > Beautiful Names Plugin Example< / h2 >
2025-09-13 17:44:37 +02:00
< p > CyberPanel has released an official plugin called < a href = "https://github.com/usmannasir/beautiful_names" target = "_blank" rel = "noopener" > Beautiful Names< / a > that removes the < code > admin_< / code > prefix from Package and FTP account names. This plugin serves as a great example of how to create CyberPanel plugins.< / p >
2025-09-11 20:04:09 +02:00
< h3 > Installation of Beautiful Names< / h3 >
< pre > < code > cd /usr/local/CyberCP/pluginInstaller
wget https://cyberpanel.net/beautifulNames.zip
python pluginInstaller.py install --pluginName beautifulNames< / code > < / pre >
< h3 > Uninstall Beautiful Names< / h3 >
< pre > < code > cd /usr/local/CyberCP/pluginInstaller
python pluginInstaller.py remove --pluginName beautifulNames< / code > < / pre >
< h2 > Plugin Installation Facility< / h2 >
< p > The plugin installation facility is in beta and not available with the official install yet. To install plugins, you need to install CyberPanel via the test version:< / p >
< pre > < code > sh < (curl https://mirror.cyberpanel.net/install-test.sh || wget -O - https://mirror.cyberpanel.net/install-test.sh)< / code > < / pre >
< h2 > Additional Resources< / h2 >
< ul >
2025-09-13 17:44:37 +02:00
< li > < a href = "http://cyberpanel.net/docs/2-list-of-signals-events-files/" target = "_blank" rel = "noopener" > Complete List of Signals and Events< / a > < / li >
< li > < a href = "https://github.com/usmannasir/beautiful_names" target = "_blank" rel = "noopener" > Beautiful Names Plugin Repository< / a > < / li >
< li > < a href = "https://github.com/usmannasir/cyberpanel" target = "_blank" rel = "noopener" > CyberPanel GitHub Repository< / a > < / li >
2025-09-11 20:04:09 +02:00
< / ul >
< blockquote >
< strong > Note:< / strong > This guide is based on the official CyberPanel documentation. For the most up-to-date information, always refer to the official sources.
< / blockquote >
< / div >
< / div >
<!-- Full Development Guide -->
< div class = "docs-section" id = "full-guide" >
< div class = "docs-content" >
< h1 class = "section-title" > CyberPanel Plugin Development Guide< / h1 >
< div class = "toc" >
< h3 > Table of Contents< / h3 >
< ul >
< li > < a href = "#install-plugins" > How to Install Plugins< / a > < / li >
< li > < a href = "#uninstall-plugins" > How to Uninstall Plugins< / a > < / li >
< li > < a href = "#meta-xml" > How to Add meta.xml< / a > < / li >
< li > < a href = "#add-buttons" > How to Add Buttons for Pages< / a > < / li >
< li > < a href = "#add-toggles" > How to Add Toggles< / a > < / li >
< li > < a href = "#install-uninstall-buttons" > How to Add Install/Uninstall Buttons< / a > < / li >
< li > < a href = "#enable-disable-buttons" > How to Add Enable/Disable Buttons< / a > < / li >
< li > < a href = "#avoid-sidebar-breaking" > How to Avoid Breaking the Sidebar< / a > < / li >
< li > < a href = "#inline-loading" > How to Make Plugins Load Inline< / a > < / li >
< li > < a href = "#plugin-structure" > Plugin Structure Overview< / a > < / li >
< li > < a href = "#best-practices" > Best Practices< / a > < / li >
< li > < a href = "#troubleshooting" > Troubleshooting< / a > < / li >
< / ul >
< / div >
< div id = "install-plugins" >
< h2 > How to Install Plugins< / h2 >
< h3 > Method 1: Using the Installation Script (Recommended)< / h3 >
< pre > < code > # Download and run the installation script
curl -sSL https://raw.githubusercontent.com/cyberpanel/testPlugin/main/install.sh | bash
# Or download first, then run
wget https://raw.githubusercontent.com/cyberpanel/testPlugin/main/install.sh
chmod +x install.sh
./install.sh< / code > < / pre >
< h3 > Method 2: Manual Installation< / h3 >
< ol >
< li > < strong > Create Plugin Directory Structure< / strong >
< pre > < code > mkdir -p /home/cyberpanel/plugins/yourPlugin
mkdir -p /usr/local/CyberCP/yourPlugin< / code > < / pre >
< / li >
< li > < strong > Copy Plugin Files< / strong >
< pre > < code > cp -r yourPlugin/* /usr/local/CyberCP/yourPlugin/
chown -R cyberpanel:cyberpanel /usr/local/CyberCP/yourPlugin
chmod -R 755 /usr/local/CyberCP/yourPlugin< / code > < / pre >
< / li >
< li > < strong > Create Symlink< / strong >
< pre > < code > ln -sf /usr/local/CyberCP/yourPlugin /home/cyberpanel/plugins/yourPlugin< / code > < / pre >
< / li >
< li > < strong > Update Django Settings< / strong >
< p > Add your plugin to < code > INSTALLED_APPS< / code > in < code > /usr/local/CyberCP/cyberpanel/settings.py< / code > :< / p >
< pre > < code > INSTALLED_APPS = [
# ... existing apps ...
'yourPlugin',
]< / code > < / pre >
< / li >
< li > < strong > Update URL Configuration< / strong >
< p > Add your plugin URLs in < code > /usr/local/CyberCP/cyberpanel/urls.py< / code > :< / p >
< pre > < code > urlpatterns = [
# ... existing patterns ...
path("yourPlugin/", include("yourPlugin.urls")),
]< / code > < / pre >
< / li >
< li > < strong > Run Migrations< / strong >
< pre > < code > cd /usr/local/CyberCP
python3 manage.py makemigrations yourPlugin
python3 manage.py migrate yourPlugin< / code > < / pre >
< / li >
< li > < strong > Collect Static Files< / strong >
< pre > < code > python3 manage.py collectstatic --noinput< / code > < / pre >
< / li >
< li > < strong > Restart Services< / strong >
< pre > < code > systemctl restart lscpd
systemctl restart cyberpanel< / code > < / pre >
< / li >
< / ol >
< / div >
< div id = "uninstall-plugins" >
< h2 > How to Uninstall Plugins< / h2 >
< h3 > Method 1: Using the Installation Script< / h3 >
< pre > < code > # Run with uninstall flag
./install.sh --uninstall< / code > < / pre >
< h3 > Method 2: Manual Uninstallation< / h3 >
< ol >
< li > < strong > Remove Plugin Files< / strong >
< pre > < code > rm -rf /usr/local/CyberCP/yourPlugin
rm -f /home/cyberpanel/plugins/yourPlugin< / code > < / pre >
< / li >
< li > < strong > Remove from Django Settings< / strong >
< pre > < code > sed -i '/yourPlugin/d' /usr/local/CyberCP/cyberpanel/settings.py< / code > < / pre >
< / li >
< li > < strong > Remove from URLs< / strong >
< pre > < code > sed -i '/yourPlugin/d' /usr/local/CyberCP/cyberpanel/urls.py< / code > < / pre >
< / li >
< li > < strong > Restart Services< / strong >
< pre > < code > systemctl restart lscpd
systemctl restart cyberpanel< / code > < / pre >
< / li >
< / ol >
< / div >
< div id = "meta-xml" >
< h2 > How to Add meta.xml< / h2 >
< p > Create a < code > meta.xml< / code > file in your plugin root directory:< / p >
< pre > < code > < ?xml version="1.0" encoding="UTF-8"?>
< plugin>
< name> Your Plugin Name< /name>
< type> Utility< /type>
< description> Your plugin description< /description>
< version> 1.0.0< /version>
< author> Your Name< /author>
< website> https://your-website.com< /website>
< license> MIT< /license>
< dependencies>
< python> 3.6+< /python>
< django> 2.2+< /django>
< /dependencies>
< permissions>
< admin> true< /admin>
< user> false< /user>
< /permissions>
< settings>
< enable_toggle> true< /enable_toggle>
< test_button> true< /test_button>
< popup_messages> true< /popup_messages>
< inline_integration> true< /inline_integration>
< /settings>
< /plugin> < / code > < / pre >
< h3 > Required Fields:< / h3 >
< ul >
< li > < code > name< / code > : Plugin display name< / li >
< li > < code > type< / code > : Plugin category (Utility, Security, Performance, etc.)< / li >
< li > < code > description< / code > : Plugin description< / li >
< li > < code > version< / code > : Plugin version< / li >
< / ul >
< h3 > Optional Fields:< / h3 >
< ul >
< li > < code > author< / code > : Plugin author< / li >
< li > < code > website< / code > : Plugin website< / li >
< li > < code > license< / code > : License type< / li >
< li > < code > dependencies< / code > : Required dependencies< / li >
< li > < code > permissions< / code > : Access permissions< / li >
< li > < code > settings< / code > : Plugin-specific settings< / li >
< / ul >
< / div >
< div id = "add-buttons" >
< h2 > How to Add Buttons for Pages< / h2 >
< h3 > 1. In Your Template< / h3 >
< pre > < code > < !-- Primary Action Button -->
< button class="btn-test" id="your-button">
< i class="fas fa-icon"> < /i>
Button Text
< /button>
< !-- Secondary Button -->
< a href="{% url 'yourPlugin:your_view' %}" class="btn-secondary">
< i class="fas fa-icon"> < /i>
Button Text
< /a>
< !-- Danger Button -->
< button class="btn-danger" id="danger-button">
< i class="fas fa-trash"> < /i>
Delete
< /button> < / code > < / pre >
< h3 > 2. CSS Styles< / h3 >
< pre > < code > .btn-test {
background: linear-gradient(135deg, #5856d6, #4a90e2);
color: white;
border: none;
padding: 12px 24px;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 8px;
}
.btn-test:hover {
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(88,86,214,0.3);
}
.btn-test:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none;
}< / code > < / pre >
< h3 > 3. JavaScript Event Handling< / h3 >
< pre > < code > document.getElementById('your-button').addEventListener('click', function() {
// Your button logic here
fetch('/yourPlugin/your-endpoint/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': getCSRFToken()
},
body: JSON.stringify({data: 'value'})
})
.then(response => response.json())
.then(data => {
if (data.status === 1) {
showNotification('success', 'Success', data.message);
} else {
showNotification('error', 'Error', data.error_message);
}
});
});< / code > < / pre >
< / div >
< div id = "add-toggles" >
< h2 > How to Add Toggles< / h2 >
< h3 > 1. HTML Structure< / h3 >
< pre > < code > < div class="control-group">
< label for="plugin-toggle" class="toggle-label">
Enable Feature
< /label>
< label class="toggle-switch">
< input type="checkbox" id="plugin-toggle" {% if feature_enabled %}checked{% endif %}>
< span class="slider"> < /span>
< /label>
< /div> < / code > < / pre >
< h3 > 2. CSS Styles< / h3 >
< pre > < code > .toggle-switch {
position: relative;
display: inline-block;
width: 60px;
height: 34px;
}
.toggle-switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
transition: .4s;
border-radius: 34px;
}
.slider:before {
position: absolute;
content: "";
height: 26px;
width: 26px;
left: 4px;
bottom: 4px;
background-color: white;
transition: .4s;
border-radius: 50%;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
}
input:checked + .slider {
background-color: #5856d6;
}
input:checked + .slider:before {
transform: translateX(26px);
}< / code > < / pre >
< h3 > 3. JavaScript Handling< / h3 >
< pre > < code > document.getElementById('plugin-toggle').addEventListener('change', function() {
fetch('/yourPlugin/toggle/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': getCSRFToken()
}
})
.then(response => response.json())
.then(data => {
if (data.status === 1) {
showNotification('success', 'Toggle Updated', data.message);
} else {
showNotification('error', 'Error', data.error_message);
// Revert toggle state
this.checked = !this.checked;
}
});
});< / code > < / pre >
< / div >
< div id = "install-uninstall-buttons" >
< h2 > How to Add Install/Uninstall Buttons< / h2 >
< h3 > 1. In Your Plugin Template< / h3 >
< pre > < code > < div class="plugin-actions">
< button class="btn-install" id="install-plugin">
< i class="fas fa-download"> < /i>
Install Plugin
< /button>
< button class="btn-uninstall" id="uninstall-plugin">
< i class="fas fa-trash"> < /i>
Uninstall Plugin
< /button>
< /div> < / code > < / pre >
< h3 > 2. CSS Styles< / h3 >
< pre > < code > .plugin-actions {
display: flex;
gap: 10px;
margin-top: 20px;
}
.btn-install {
background: #10b981;
color: white;
border: none;
padding: 10px 20px;
border-radius: 6px;
cursor: pointer;
transition: all 0.3s ease;
}
.btn-uninstall {
background: #ef4444;
color: white;
border: none;
padding: 10px 20px;
border-radius: 6px;
cursor: pointer;
transition: all 0.3s ease;
}
.btn-install:hover {
background: #059669;
transform: translateY(-2px);
}
.btn-uninstall:hover {
background: #dc2626;
transform: translateY(-2px);
}< / code > < / pre >
< h3 > 3. JavaScript Implementation< / h3 >
< pre > < code > // Install button
document.getElementById('install-plugin').addEventListener('click', function() {
if (confirm('Are you sure you want to install this plugin?')) {
this.disabled = true;
this.innerHTML = '< i class="fas fa-spinner fa-spin"> < /i> Installing...';
fetch('/yourPlugin/install/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': getCSRFToken()
}
})
.then(response => response.json())
.then(data => {
if (data.status === 1) {
showNotification('success', 'Installation Complete', data.message);
location.reload();
} else {
showNotification('error', 'Installation Failed', data.error_message);
}
})
.finally(() => {
this.disabled = false;
this.innerHTML = '< i class="fas fa-download"> < /i> Install Plugin';
});
}
});
// Uninstall button
document.getElementById('uninstall-plugin').addEventListener('click', function() {
if (confirm('Are you sure you want to uninstall this plugin? This action cannot be undone.')) {
this.disabled = true;
this.innerHTML = '< i class="fas fa-spinner fa-spin"> < /i> Uninstalling...';
fetch('/yourPlugin/uninstall/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': getCSRFToken()
}
})
.then(response => response.json())
.then(data => {
if (data.status === 1) {
showNotification('success', 'Uninstallation Complete', data.message);
setTimeout(() => location.reload(), 2000);
} else {
showNotification('error', 'Uninstallation Failed', data.error_message);
}
})
.finally(() => {
this.disabled = false;
this.innerHTML = '< i class="fas fa-trash"> < /i> Uninstall Plugin';
});
}
});< / code > < / pre >
< / div >
< div id = "enable-disable-buttons" >
< h2 > How to Add Enable/Disable Plugin Buttons< / h2 >
< h3 > 1. Model for Plugin State< / h3 >
< pre > < code > # models.py
from django.db import models
from django.contrib.auth.models import User
class PluginSettings(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
plugin_enabled = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
unique_together = ['user']< / code > < / pre >
< h3 > 2. View for Toggle< / h3 >
< pre > < code > # views.py
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
from .models import PluginSettings
@require_http_methods(["POST"])
def toggle_plugin(request):
try:
settings, created = PluginSettings.objects.get_or_create(
user=request.user,
defaults={'plugin_enabled': True}
)
settings.plugin_enabled = not settings.plugin_enabled
settings.save()
return JsonResponse({
'status': 1,
'enabled': settings.plugin_enabled,
'message': f'Plugin {"enabled" if settings.plugin_enabled else "disabled"} successfully'
})
except Exception as e:
return JsonResponse({'status': 0, 'error_message': str(e)})< / code > < / pre >
< h3 > 3. Template Implementation< / h3 >
< pre > < code > < div class="plugin-controls">
< label for="plugin-toggle" class="toggle-label">
Enable Plugin
< /label>
< label class="toggle-switch">
< input type="checkbox" id="plugin-toggle" {% if plugin_enabled %}checked{% endif %}>
< span class="slider"> < /span>
< /label>
< /div> < / code > < / pre >
< h3 > 4. JavaScript Handling< / h3 >
< pre > < code > document.getElementById('plugin-toggle').addEventListener('change', function() {
fetch('/yourPlugin/toggle/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': getCSRFToken()
}
})
.then(response => response.json())
.then(data => {
if (data.status === 1) {
showNotification('success', 'Plugin Toggle', data.message);
// Update UI elements based on enabled state
updatePluginUI(data.enabled);
} else {
showNotification('error', 'Error', data.error_message);
this.checked = !this.checked; // Revert toggle
}
});
});
function updatePluginUI(enabled) {
const buttons = document.querySelectorAll('.plugin-button');
buttons.forEach(button => {
button.disabled = !enabled;
});
const statusIndicator = document.querySelector('.status-indicator');
if (statusIndicator) {
statusIndicator.textContent = enabled ? 'Enabled' : 'Disabled';
statusIndicator.className = `status-indicator ${enabled ? 'enabled' : 'disabled'}`;
}
}< / code > < / pre >
< / div >
< div id = "avoid-sidebar-breaking" >
< h2 > How to Avoid Breaking the CyberPanel Sidebar< / h2 >
< h3 > 1. Use CyberPanel's Base Template< / h3 >
< p > Always extend the base template:< / p >
< pre > < code > {% extends "baseTemplate/index.html" %}
{% load i18n %}
{% load static %}
{% block title %}{% trans "Your Plugin - CyberPanel" %}{% endblock %}
{% block content %}
< !-- Your plugin content here -->
{% endblock %}< / code > < / pre >
< h3 > 2. Don't Modify the Sidebar HTML< / h3 >
< p > Never directly modify the sidebar HTML. Instead, use CyberPanel's built-in navigation system.< / p >
< h3 > 3. Use Proper CSS Scoping< / h3 >
< pre > < code > /* Good: Scoped to your plugin */
.your-plugin-wrapper {
/* Your styles here */
}
/* Bad: Global styles that might affect sidebar */
.sidebar {
/* Don't do this */
}< / code > < / pre >
< h3 > 4. Use CyberPanel's CSS Variables< / h3 >
< pre > < code > .your-plugin-element {
background: var(--bg-primary, white);
color: var(--text-primary, #2f3640);
border: 1px solid var(--border-primary, #e8e9ff);
}< / code > < / pre >
< h3 > 5. Test Responsive Design< / h3 >
< p > Ensure your plugin works on all screen sizes without breaking the sidebar:< / p >
< pre > < code > @media (max-width: 768px) {
.your-plugin-wrapper {
padding: 15px;
}
/* Don't modify sidebar behavior */
}< / code > < / pre >
< / div >
< div id = "inline-loading" >
< h2 > How to Make Plugins Load Inline< / h2 >
< h3 > 1. Use CyberPanel's httpProc< / h3 >
< pre > < code > # views.py
from plogical.httpProc import httpProc
def your_view(request):
context = {
'data': 'your_data',
'plugin_enabled': True
}
proc = httpProc(request, 'yourPlugin/your_template.html', context, 'admin')
return proc.render()< / code > < / pre >
< h3 > 2. Template Structure< / h3 >
< pre > < code > {% extends "baseTemplate/index.html" %}
{% load i18n %}
{% load static %}
{% block title %}{% trans "Your Plugin - CyberPanel" %}{% endblock %}
{% block header_scripts %}
< style>
/* Your plugin-specific styles */
.your-plugin-wrapper {
background: transparent;
padding: 20px;
}
.your-plugin-container {
max-width: 1200px;
margin: 0 auto;
}
< /style>
{% endblock %}
{% block content %}
< div class="your-plugin-wrapper">
< div class="your-plugin-container">
< !-- Your plugin content here -->
< /div>
< /div>
{% endblock %}< / code > < / pre >
< h3 > 3. URL Configuration< / h3 >
< pre > < code > # urls.py
from django.urls import path
from . import views
app_name = 'yourPlugin'
urlpatterns = [
path('', views.your_view, name='your_view'),
path('settings/', views.settings_view, name='settings'),
# ... other URLs
]< / code > < / pre >
< h3 > 4. Main URLs Integration< / h3 >
< pre > < code > # In /usr/local/CyberCP/cyberpanel/urls.py
urlpatterns = [
# ... existing patterns ...
path("yourPlugin/", include("yourPlugin.urls")),
]< / code > < / pre >
< / div >
< div id = "plugin-structure" >
< h2 > Plugin Structure Overview< / h2 >
< pre > < code > yourPlugin/
├── __init__.py
├── admin.py
├── apps.py
├── models.py
├── views.py
├── urls.py
├── signals.py
├── meta.xml
├── install.sh
├── templates/
│ └── yourPlugin/
│ ├── plugin_home.html
│ ├── plugin_settings.html
│ └── plugin_logs.html
├── static/
│ └── yourPlugin/
│ ├── css/
│ │ └── yourPlugin.css
│ └── js/
│ └── yourPlugin.js
└── migrations/
└── __init__.py< / code > < / pre >
< / div >
< div id = "best-practices" >
< h2 > Best Practices< / h2 >
< h3 > 1. Security< / h3 >
< ul >
< li > Always validate user input< / li >
< li > Use CSRF protection< / li >
< li > Sanitize data before displaying< / li >
< li > Use proper authentication decorators< / li >
< / ul >
< h3 > 2. Performance< / h3 >
< ul >
< li > Use database indexes for frequently queried fields< / li >
< li > Implement caching where appropriate< / li >
< li > Optimize database queries< / li >
< li > Minimize JavaScript and CSS< / li >
< / ul >
< h3 > 3. User Experience< / h3 >
< ul >
< li > Provide clear feedback for all actions< / li >
< li > Use loading states for long operations< / li >
< li > Implement proper error handling< / li >
< li > Make the interface responsive< / li >
< / ul >
< h3 > 4. Code Quality< / h3 >
< ul >
< li > Follow Django best practices< / li >
< li > Use meaningful variable names< / li >
< li > Add proper documentation< / li >
< li > Write unit tests< / li >
< / ul >
< h3 > 5. Integration< / h3 >
< ul >
< li > Use CyberPanel's existing components< / li >
< li > Follow the established design patterns< / li >
< li > Maintain consistency with the UI< / li >
< li > Test thoroughly before release< / li >
< / ul >
< / div >
< div id = "troubleshooting" >
< h2 > Troubleshooting< / h2 >
< h3 > Common Issues< / h3 >
< h4 > 1. Plugin not showing in installed plugins< / h4 >
< ul >
< li > Check if meta.xml exists and is valid< / li >
< li > Verify the plugin is in INSTALLED_APPS< / li >
< li > Ensure proper file permissions< / li >
< / ul >
< h4 > 2. Template not found errors< / h4 >
< ul >
< li > Check template path in views.py< / li >
< li > Verify template files exist< / li >
< li > Ensure proper directory structure< / li >
< / ul >
< h4 > 3. Static files not loading< / h4 >
< ul >
< li > Run < code > python3 manage.py collectstatic< / code > < / li >
< li > Check STATIC_URL configuration< / li >
< li > Verify file permissions< / li >
< / ul >
< h4 > 4. Database migration errors< / h4 >
< ul >
< li > Check model definitions< / li >
< li > Run < code > python3 manage.py makemigrations< / code > < / li >
< li > Verify database connectivity< / li >
< / ul >
< h4 > 5. Permission denied errors< / h4 >
< ul >
< li > Check file ownership (cyberpanel:cyberpanel)< / li >
< li > Verify file permissions (755 for directories, 644 for files)< / li >
< li > Ensure proper SELinux context if applicable< / li >
< / ul >
< h3 > Debug Steps< / h3 >
< h4 > 1. Check CyberPanel logs< / h4 >
< pre > < code > tail -f /home/cyberpanel/logs/cyberpanel.log< / code > < / pre >
< h4 > 2. Check Django logs< / h4 >
< pre > < code > tail -f /home/cyberpanel/logs/django.log< / code > < / pre >
< h4 > 3. Verify plugin installation< / h4 >
< pre > < code > ls -la /home/cyberpanel/plugins/
ls -la /usr/local/CyberCP/yourPlugin/< / code > < / pre >
< h4 > 4. Test database connectivity< / h4 >
< pre > < code > cd /usr/local/CyberCP
python3 manage.py shell< / code > < / pre >
< h4 > 5. Check service status< / h4 >
< pre > < code > systemctl status lscpd
systemctl status cyberpanel< / code > < / pre >
< / div >
< blockquote >
< strong > Conclusion:< / strong > This guide provides comprehensive instructions for developing CyberPanel plugins. Follow the best practices and troubleshooting steps to ensure your plugins integrate seamlessly with CyberPanel while maintaining security and performance standards.
< / blockquote >
< / div >
< / div >
< / div >
2025-09-11 20:17:54 +02:00
< / div >
<!-- OS Compatibility Guide -->
< div class = "docs-section" id = "os-compatibility" >
< div class = "docs-content" >
< h1 class = "section-title" > Operating System Compatibility< / h1 >
< div class = "feature-list" >
< div class = "feature-item" >
< h4 > 🌐 Multi-OS Support< / h4 >
< p > Comprehensive support for all CyberPanel-supported operating systems.< / p >
< / div >
< div class = "feature-item" >
< h4 > 🔍 Automatic Detection< / h4 >
< p > Intelligent OS detection and configuration for seamless installation.< / p >
< / div >
< div class = "feature-item" >
< h4 > 🧪 Compatibility Testing< / h4 >
< p > Built-in compatibility testing to verify system requirements.< / p >
< / div >
< / div >
< h2 > Supported Operating Systems< / h2 >
< div class = "compatibility-grid" >
< div class = "os-card" >
< h3 > Ubuntu< / h3 >
< ul >
< li > ✅ Ubuntu 22.04 (Full Support)< / li >
< li > ✅ Ubuntu 20.04 (Full Support)< / li >
< li > ✅ Debian 11+ (Compatible)< / li >
< / ul >
< p > < strong > Package Manager:< / strong > apt-get< / p >
< p > < strong > Web Server:< / strong > apache2< / p >
< / div >
< div class = "os-card" >
< h3 > RHEL-based< / h3 >
< ul >
< li > ✅ AlmaLinux 8, 9, 10< / li >
< li > ✅ RockyLinux 8, 9< / li >
< li > ✅ RHEL 8, 9< / li >
< li > ✅ CentOS 9< / li >
< / ul >
< p > < strong > Package Manager:< / strong > dnf/yum< / p >
< p > < strong > Web Server:< / strong > httpd< / p >
< / div >
< div class = "os-card" >
< h3 > CloudLinux< / h3 >
< ul >
< li > ✅ CloudLinux 8< / li >
< li > ✅ CloudLinux 7 (Limited)< / li >
< / ul >
< p > < strong > Package Manager:< / strong > yum< / p >
< p > < strong > Web Server:< / strong > httpd< / p >
< / div >
< / div >
< h2 > Python Compatibility< / h2 >
< p > The plugin requires Python 3.6+ and automatically detects the correct Python executable:< / p >
< div class = "code-block" >
< pre > < code > # Detection order:
1. python3.12
2. python3.11
3. python3.10
4. python3.9
5. python3.8
6. python3.7
7. python3.6
8. python3
9. python (fallback)< / code > < / pre >
< / div >
< h2 > Installation Compatibility< / h2 >
< p > The installation script automatically detects your operating system and configures the plugin accordingly:< / p >
< div class = "code-block" >
< pre > < code > # Automatic detection includes:
- OS name and version
- Python executable path
- Package manager (apt-get, dnf, yum)
- Service manager (systemctl, service)
- Web server (apache2, httpd)
- User and group permissions< / code > < / pre >
< / div >
< h2 > Compatibility Testing< / h2 >
< p > Run the built-in compatibility test to verify your system:< / p >
< div class = "code-block" >
< pre > < code > # Navigate to plugin directory
cd /usr/local/CyberCP/testPlugin
# Run compatibility test
python3 test_os_compatibility.py
# Or make it executable and run
chmod +x test_os_compatibility.py
./test_os_compatibility.py< / code > < / pre >
< / div >
< h2 > Test Results< / h2 >
< p > The compatibility test checks:< / p >
< ul >
< li > ✅ OS detection and version< / li >
< li > ✅ Python installation and version< / li >
< li > ✅ Package manager availability< / li >
< li > ✅ Service manager functionality< / li >
< li > ✅ Web server configuration< / li >
< li > ✅ File permissions and ownership< / li >
< li > ✅ Network connectivity< / li >
< li > ✅ CyberPanel integration< / li >
< / ul >
< h2 > OS-Specific Configurations< / h2 >
< h3 > Ubuntu/Debian Systems< / h3 >
< div class = "code-block" >
< pre > < code > # Package Manager: apt-get
# Python: python3
# Pip: pip3
# Service Manager: systemctl
# Web Server: apache2
# User/Group: cyberpanel:cyberpanel
# Installation commands
sudo apt-get update
sudo apt-get install -y python3 python3-pip python3-venv git curl
sudo apt-get install -y build-essential python3-dev< / code > < / pre >
< / div >
< h3 > RHEL-based Systems< / h3 >
< div class = "code-block" >
< pre > < code > # Package Manager: dnf (RHEL 8+) / yum (RHEL 7)
# Python: python3
# Pip: pip3
# Service Manager: systemctl
# Web Server: httpd
# User/Group: cyberpanel:cyberpanel
# Installation commands (RHEL 8+)
sudo dnf install -y python3 python3-pip python3-devel git curl
sudo dnf install -y gcc gcc-c++ make
# Installation commands (RHEL 7)
sudo yum install -y python3 python3-pip python3-devel git curl
sudo yum install -y gcc gcc-c++ make< / code > < / pre >
< / div >
< h3 > CloudLinux< / h3 >
< div class = "code-block" >
< pre > < code > # Package Manager: yum
# Python: python3
# Pip: pip3
# Service Manager: systemctl
# Web Server: httpd
# User/Group: cyberpanel:cyberpanel
# Installation commands
sudo yum install -y python3 python3-pip python3-devel git curl
sudo yum install -y gcc gcc-c++ make
# CageFS configuration
cagefsctl --enable cyberpanel
cagefsctl --update< / code > < / pre >
< / div >
< h2 > Security Compatibility< / h2 >
< h3 > SELinux (RHEL-based systems)< / h3 >
< div class = "code-block" >
< pre > < code > # Check SELinux status
sestatus
# Set proper context for plugin files
setsebool -P httpd_can_network_connect 1
chcon -R -t httpd_exec_t /usr/local/CyberCP/testPlugin/< / code > < / pre >
< / div >
< h3 > AppArmor (Ubuntu/Debian)< / h3 >
< div class = "code-block" >
< pre > < code > # Check AppArmor status
aa-status
# Allow Apache to access plugin files
aa-complain apache2< / code > < / pre >
< / div >
< h3 > Firewall Configuration< / h3 >
< div class = "code-block" >
< pre > < code > # Ubuntu/Debian (ufw)
sudo ufw allow 8090/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# RHEL-based (firewalld)
sudo firewall-cmd --permanent --add-port=8090/tcp
sudo firewall-cmd --permanent --add-port=80/tcp
sudo firewall-cmd --permanent --add-port=443/tcp
sudo firewall-cmd --reload< / code > < / pre >
< / div >
< h2 > Troubleshooting< / h2 >
< h3 > Common Issues< / h3 >
< div class = "troubleshooting-section" >
< h4 > Python not found< / h4 >
< div class = "code-block" >
< pre > < code > # Ubuntu/Debian
sudo apt-get update
sudo apt-get install -y python3 python3-pip
# RHEL-based
sudo dnf install -y python3 python3-pip
# or
sudo yum install -y python3 python3-pip< / code > < / pre >
< / div >
< h4 > Permission denied< / h4 >
< div class = "code-block" >
< pre > < code > sudo chown -R cyberpanel:cyberpanel /home/cyberpanel/plugins
sudo chown -R cyberpanel:cyberpanel /usr/local/CyberCP/testPlugin< / code > < / pre >
< / div >
< h4 > Service not starting< / h4 >
< div class = "code-block" >
< pre > < code > sudo systemctl daemon-reload
sudo systemctl restart lscpd
sudo systemctl restart apache2 # Ubuntu/Debian
sudo systemctl restart httpd # RHEL-based< / code > < / pre >
< / div >
< / div >
< h2 > Debug Commands< / h2 >
< div class = "code-block" >
< pre > < code > # Check OS information
cat /etc/os-release
uname -a
# Check Python installation
python3 --version
which python3
which pip3
# Check services
systemctl status lscpd
systemctl status apache2 # Ubuntu/Debian
systemctl status httpd # RHEL-based
# Check file permissions
ls -la /home/cyberpanel/plugins/
ls -la /usr/local/CyberCP/testPlugin/
# Check CyberPanel logs
tail -f /home/cyberpanel/logs/cyberpanel.log
tail -f /home/cyberpanel/logs/django.log< / code > < / pre >
< / div >
< blockquote >
< strong > Note:< / strong > The plugin is designed to work seamlessly across all supported operating systems. If you encounter any compatibility issues, please run the compatibility test and check the troubleshooting section above.
< / blockquote >
< / div >
< / div >
2025-09-11 20:04:09 +02:00
2025-09-11 20:17:54 +02:00
< script >
2025-09-11 20:04:09 +02:00
document.addEventListener('DOMContentLoaded', function() {
const navButtons = document.querySelectorAll('.nav-button[data-section]');
const sections = document.querySelectorAll('.docs-section');
navButtons.forEach(button => {
button.addEventListener('click', function(e) {
e.preventDefault();
// Remove active class from all buttons and sections
navButtons.forEach(btn => btn.classList.remove('active'));
sections.forEach(section => section.classList.remove('active'));
// Add active class to clicked button
this.classList.add('active');
// Show corresponding section
const targetSection = document.getElementById(this.dataset.section);
if (targetSection) {
targetSection.classList.add('active');
}
});
});
// Smooth scrolling for anchor links
const anchorLinks = document.querySelectorAll('a[href^="#"]');
anchorLinks.forEach(link => {
link.addEventListener('click', function(e) {
e.preventDefault();
const targetId = this.getAttribute('href').substring(1);
const targetElement = document.getElementById(targetId);
if (targetElement) {
targetElement.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
}
});
});
// Initialize with quick-guide active
const quickGuideButton = document.querySelector('[data-section="quick-guide"]');
if (quickGuideButton) {
quickGuideButton.classList.add('active');
}
const quickGuideSection = document.getElementById('quick-guide');
if (quickGuideSection) {
quickGuideSection.classList.add('active');
}
});
< / script >
{% endblock %}