Files
Linux-Server-Management-Too…/MULTI_CONTROL_PANEL_ARCHITECTURE.md
T
cschantz e805bac2a6 ARCHITECTURE: Multi-Control-Panel Design Standards
Created comprehensive architecture and quick reference documentation.

NEW DOCUMENTS:

1. MULTI_CONTROL_PANEL_ARCHITECTURE.md (6500+ words)

   Defines MANDATORY patterns for all future development:
   - Core principles (never hardcode, use abstractions, conditionals)
   - Standard library usage (system-detect.sh, user-manager.sh)
   - Path mapping reference (all panels)
   - Standard code patterns (log discovery, docroot, domain→user)
   - Module classification (A/B/C/D)
   - Testing requirements
   - Code review checklist
   - Migration guide
   - Common mistakes to avoid

   Every developer must follow these patterns!

2. CONTROL_PANEL_QUICK_REFERENCE.md (8000+ words)

   Fast lookup while coding:
   - Panel detection methods
   - Complete file system path mappings
   - Configuration file locations
   - CLI tools & API commands
   - Database prefix patterns (CRITICAL for InterWorx!)
   - PHP configuration per panel
   - Email, FTP, security features
   - WordPress detection patterns
   - Process ownership
   - Code snippets for common tasks
   - Panel-specific quirks/gotchas
   - Migration implications

   Covers: cPanel, Plesk, InterWorx, Standalone

PURPOSE:
These documents establish a STANDARD ARCHITECTURE before completing
InterWorx support. All modules will be refactored to follow these
patterns, making it trivial to add DirectAdmin, CyberPanel, etc.

KEY PATTERNS ESTABLISHED:
- Never hardcode paths → use SYS_LOG_DIR, get_user_info()
- Wrap API calls → check SYS_CONTROL_PANEL first
- Design for extension → case statements for panels
- Test on all platforms → cPanel regression required

MODULE CLASSIFICATION:
- Class A: Panel agnostic (no special handling)
- Class B: Needs system detection (SYS_LOG_DIR)
- Class C: Needs user/domain management (get_user_info)
- Class D: Panel-specific (document limitations)

CRITICAL GOTCHAS DOCUMENTED:
- InterWorx database prefix uses DOMAIN not USERNAME!
- Plesk has no shared hosting (domain-centric)
- cPanel addon domains share public_html
- InterWorx logs are per-domain in user home

NEXT STEPS:
1. Update existing modules to follow patterns
2. Complete InterWorx support systematically
3. Expand Plesk support
4. Add DirectAdmin/CyberPanel

This is the foundation for true multi-panel architecture!
2025-11-19 19:52:16 -05:00

15 KiB

Multi-Control-Panel Architecture

Version: 1.0 Date: 2025-11-19 Status: ACTIVE STANDARD

Executive Summary

This document defines the standard architecture for building control panel-agnostic tools in the Server Management Toolkit. All new code and refactored modules MUST follow these patterns to ensure compatibility with cPanel, Plesk, InterWorx, and future control panels.


Supported Control Panels

Current Support Levels:

  • cPanel - Full support (primary platform)
  • Plesk - ⚠️ Partial support (needs expansion)
  • InterWorx - 🚧 In progress (Phases 1-3 complete)
  • Standalone - Basic support (no control panel)

Future Targets:

  • DirectAdmin
  • CyberPanel
  • Webmin/Virtualmin

Core Principles

1. Never Hardcode Paths

# ❌ BAD - Hardcoded cPanel path
LOG_DIR="/var/log/apache2/domlogs"
docroot="/home/$user/public_html"

# ✅ GOOD - Use system detection
LOG_DIR="${SYS_LOG_DIR}"  # From system-detect.sh
eval $(get_user_info "$username")  # Returns $HOME_DIR, $PRIMARY_DOMAIN
docroot="${HOME_DIR}/${PRIMARY_DOMAIN}/html"  # Constructed dynamically

2. Use Abstraction Libraries

# ❌ BAD - Direct control panel-specific code
user=$(grep -l "DNS.*$domain" /var/cpanel/users/* 2>/dev/null | ...)

# ✅ GOOD - Use user-manager.sh abstraction
eval $(get_user_info "$username")
# Now you have: $USER_EXISTS, $USERNAME, $PRIMARY_DOMAIN, $ALL_DOMAINS, etc.

3. Conditional Panel-Specific Features

# ❌ BAD - Assumes cPanel exists
whmapi1 cphulkd_list_blocks

# ✅ GOOD - Conditional with graceful fallback
if [ "$SYS_CONTROL_PANEL" = "cpanel" ]; then
    whmapi1 cphulkd_list_blocks
else
    echo "CPHulk is cPanel-specific, skipping..."
fi

4. Design for Extension

# ✅ GOOD - Easy to add new panels
case "$SYS_CONTROL_PANEL" in
    cpanel)
        # cPanel-specific logic
        ;;
    plesk)
        # Plesk-specific logic
        ;;
    interworx)
        # InterWorx-specific logic
        ;;
    directadmin)
        # Future: DirectAdmin logic
        ;;
    *)
        echo "Unsupported control panel: $SYS_CONTROL_PANEL"
        return 1
        ;;
esac

Standard Library Usage

system-detect.sh

Purpose: Runtime detection of control panel, OS, paths, and system resources Exports:

  • SYS_CONTROL_PANEL - Control panel type (cpanel, plesk, interworx, none)
  • SYS_LOG_DIR - Apache/web server log directory
  • SYS_USER_HOME_BASE - Base directory for user homes
  • SYS_WEB_SERVER - Web server type (apache, nginx, litespeed)
  • SYS_FIREWALL - Firewall type (csf, firewalld, iptables, ufw)
  • SYS_CSF_ACTIVE - CSF availability flag

Usage:

# Automatically sourced when loading common-functions.sh
source "$SCRIPT_DIR/lib/common-functions.sh"
source "$SCRIPT_DIR/lib/system-detect.sh"

# Variables are now available
if [ "$SYS_CONTROL_PANEL" = "cpanel" ]; then
    # cPanel-specific code
fi

user-manager.sh

Purpose: Control panel-agnostic user/domain/database management Functions:

get_user_info()

eval $(get_user_info "username")
# Returns (via eval):
# - USER_EXISTS=yes/no
# - USERNAME=username
# - PRIMARY_DOMAIN=example.com
# - ALL_DOMAINS=space-separated list
# - EMAIL=user@example.com
# - HOME_DIR=/home/username
# - DISK_USED=1024M

get_user_domains()

domains=$(get_user_domains "username")
# Returns newline-separated list of domains

get_user_databases()

databases=$(get_user_databases "username")
# Returns newline-separated list of databases
# Note: InterWorx uses domain prefix, not username!

Critical Note: Database prefixes differ!

  • cPanel: username_dbname
  • InterWorx: first8charsOfDomain_dbname
  • Plesk: dbname (user-scoped)

Path Mapping Reference

Resource cPanel Plesk InterWorx Standalone
User Home /home/user /var/www/vhosts/domain /home/user /home/user
Document Root /home/user/public_html /var/www/vhosts/domain/httpdocs /home/user/domain.com/html /var/www/html
Access Logs /var/log/apache2/domlogs/domain /var/www/vhosts/system/domain/logs /home/user/var/domain/logs/access_log /var/log/httpd/access_log
Error Logs /var/log/apache2/domlogs/domain-error_log /var/www/vhosts/system/domain/logs/error_log /home/user/var/domain/logs/error_log /var/log/httpd/error_log
PHP Error Logs /home/user/public_html/error_log /var/www/vhosts/domain/httpdocs/error_log /home/user/domain/html/error_log N/A
User Config /var/cpanel/users/user Plesk DB listaccounts.pex or vhost configs N/A
Domain Config /var/cpanel/userdata/user/domain Plesk DB /etc/httpd/conf.d/vhost_domain.conf N/A
Mail Dir /home/user/mail /var/qmail/mailnames/domain /home/user/var/domain/mail /var/mail
Cron Jobs /var/spool/cron/user /var/spool/cron/user /var/spool/cron/user /var/spool/cron/user
SSL Certs /etc/letsencrypt/live/domain /etc/letsencrypt/live/domain /etc/letsencrypt/live/domain /etc/letsencrypt/live/domain
Database Prefix username_ No prefix first8chars_ N/A

Standard Patterns

Pattern 1: Log File Discovery

discover_logs() {
    local log_files=()

    if [ "$SYS_CONTROL_PANEL" = "interworx" ]; then
        # InterWorx: Per-domain logs in user home
        while IFS= read -r logfile; do
            [ -f "$logfile" ] && log_files+=("$logfile")
        done < <(find /home/*/var/*/logs -type f -name "access_log" 2>/dev/null)

    elif [ "$SYS_CONTROL_PANEL" = "plesk" ]; then
        # Plesk: Centralized per-domain logs
        while IFS= read -r logfile; do
            [ -f "$logfile" ] && log_files+=("$logfile")
        done < <(find /var/www/vhosts/system/*/logs -type f -name "access_log" 2>/dev/null)

    elif [ "$SYS_CONTROL_PANEL" = "cpanel" ] && [ -n "$SYS_LOG_DIR" ]; then
        # cPanel: Centralized domlogs
        while IFS= read -r logfile; do
            [ -f "$logfile" ] && log_files+=("$logfile")
        done < <(find "$SYS_LOG_DIR" -type f ! -name "*-bytes_log" ! -name "*error_log" 2>/dev/null)

    else
        # Standalone: Main access log only
        [ -f "/var/log/httpd/access_log" ] && log_files+=("/var/log/httpd/access_log")
        [ -f "/var/log/apache2/access.log" ] && log_files+=("/var/log/apache2/access.log")
    fi

    echo "${log_files[@]}"
}

Pattern 2: Document Root Discovery

get_docroot() {
    local domain="$1"
    local username="$2"  # Optional, helps with InterWorx

    case "$SYS_CONTROL_PANEL" in
        cpanel)
            # cPanel: public_html
            echo "/home/${username}/public_html"
            ;;
        plesk)
            # Plesk: httpdocs
            echo "/var/www/vhosts/${domain}/httpdocs"
            ;;
        interworx)
            # InterWorx: domain.com/html
            echo "/home/${username}/${domain}/html"
            ;;
        *)
            # Standalone: Assume standard
            echo "/var/www/html"
            ;;
    esac
}

Pattern 3: Domain→User Mapping

get_user_for_domain() {
    local domain="$1"

    case "$SYS_CONTROL_PANEL" in
        cpanel)
            # cPanel: /etc/userdatadomains
            grep "^${domain}:" /etc/userdatadomains 2>/dev/null | cut -d: -f2 | awk -F'==' '{print $1}'
            ;;
        plesk)
            # Plesk: Use CLI
            plesk bin subscription --info "$domain" 2>/dev/null | grep "Owner" | awk '{print $2}'
            ;;
        interworx)
            # InterWorx: Parse vhost configs
            grep -l "ServerName ${domain}" /etc/httpd/conf.d/vhost_*.conf 2>/dev/null | head -1 | \
                xargs grep "SuexecUserGroup" 2>/dev/null | awk '{print $2}'
            ;;
        *)
            echo "Unsupported"
            return 1
            ;;
    esac
}

Pattern 4: Control Panel API Calls

# Always wrap API calls in control panel checks
ban_ip_via_panel() {
    local ip="$1"

    case "$SYS_CONTROL_PANEL" in
        cpanel)
            if command -v whmapi1 &>/dev/null; then
                whmapi1 cphulkd_blacklist ip="$ip"
            else
                echo "cPanel WHM API not available"
                return 1
            fi
            ;;
        plesk)
            if command -v plesk &>/dev/null; then
                plesk bin ip --ban "$ip"
            else
                echo "Plesk CLI not available"
                return 1
            fi
            ;;
        interworx)
            # InterWorx has no built-in IP ban API
            # Fall back to firewall
            echo "InterWorx has no native IP ban, using firewall"
            return 2
            ;;
        *)
            echo "No control panel API available"
            return 1
            ;;
    esac
}

Testing Requirements

Every Module Must Be Tested On:

  1. cPanel - Regression testing (ensure no breakage)
  2. Standalone - No control panel environment
  3. ⚠️ Plesk - If Plesk support claimed
  4. ⚠️ InterWorx - If InterWorx support claimed

Test Checklist:

  • Module loads without errors on all platforms
  • Paths are correctly detected
  • User/domain functions work correctly
  • Graceful degradation when panel-specific features unavailable
  • Error messages are helpful and mention control panel
  • No hardcoded paths remain
  • API calls are wrapped in panel checks

Code Review Checklist

Before committing any module changes, verify:

  • No hardcoded paths (/var/cpanel, /usr/local/cpanel, /var/log/apache2/domlogs, public_html)
  • Uses SYS_LOG_DIR from system-detect.sh
  • Uses get_user_info() / get_user_domains() from user-manager.sh
  • API calls wrapped in if [ "$SYS_CONTROL_PANEL" = "cpanel" ]
  • Document root constructed dynamically
  • Error messages include control panel info for debugging
  • Tested with bash -n script.sh (syntax check)
  • Added to INTERWORX_COMPATIBILITY_AUDIT.md if applicable

Module Classification

Class A: Control Panel Agnostic

Can work on any system

  • hardware-health-check.sh
  • tail-secure-log.sh
  • tail-mail-log.sh
  • firewall-activity-monitor.sh
  • ssh-attack-monitor.sh

Requirements: None special

Class B: Requires System Detection

Needs paths but no user/domain management

  • network-bandwidth-analyzer.sh
  • tail-apache-access.sh
  • tail-apache-error.sh
  • web-traffic-monitor.sh

Requirements:

  • Source system-detect.sh
  • Use SYS_LOG_DIR

Class C: Requires User/Domain Management

Needs to map users/domains

  • bot-analyzer.sh
  • website-error-analyzer.sh
  • 500-error-tracker.sh
  • malware-scanner.sh
  • wordpress-cron-manager.sh

Requirements:

  • Source system-detect.sh
  • Source user-manager.sh
  • Use get_user_info() / get_user_domains()

Class D: Control Panel-Specific

Only works on specific panels

  • enable-cphulk.sh (cPanel only)
  • acronis-* (cPanel specific)

Requirements:

  • Check SYS_CONTROL_PANEL at startup
  • Exit gracefully if wrong panel
  • Document panel requirement in help text

Migration Guide

Converting Existing Module to Multi-Panel:

  1. Add Library Imports
# At top of script, after shebang
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
source "$SCRIPT_DIR/lib/common-functions.sh"
source "$SCRIPT_DIR/lib/system-detect.sh"
source "$SCRIPT_DIR/lib/user-manager.sh"  # If Class C
  1. Replace Hardcoded Paths
# Find all hardcoded paths
grep -n "/var/cpanel\|/usr/local/cpanel\|public_html\|domlogs" yourscript.sh

# Replace with system variables or functions
  1. Wrap API Calls
# Find all API calls
grep -n "whmapi\|uapi\|cpapi" yourscript.sh

# Wrap in conditional checks
  1. Add Control Panel Cases
# For panel-specific logic, use case statements
case "$SYS_CONTROL_PANEL" in
    cpanel) ... ;;
    plesk) ... ;;
    interworx) ... ;;
    *) ... ;;
esac
  1. Test Syntax
bash -n yourscript.sh
  1. Update Documentation
  • Add to INTERWORX_COMPATIBILITY_AUDIT.md
  • Note supported panels in script header
  • Update help text

Common Mistakes to Avoid

Mistake #1: Using Command Existence as Panel Detection

# BAD - Command might exist on other panels
if command -v whmapi1 &>/dev/null; then
    # Assume cPanel
fi

Fix: Always check SYS_CONTROL_PANEL

# GOOD
if [ "$SYS_CONTROL_PANEL" = "cpanel" ] && command -v whmapi1 &>/dev/null; then
    # Definitely cPanel and API available
fi

Mistake #2: Assuming File Locations

# BAD - Only works on cPanel
domains=$(grep "^DNS" /var/cpanel/users/$user | awk '{print $2}')

Fix: Use abstraction

# GOOD
domains=$(get_user_domains "$user")

Mistake #3: Hardcoding Document Root Structure

# BAD - Assumes cPanel's public_html
find /home/*/public_html -name "wp-config.php"

Fix: Use dynamic paths

# GOOD
case "$SYS_CONTROL_PANEL" in
    cpanel)    find /home/*/public_html -name "wp-config.php" ;;
    interworx) find /home/*/*/html -name "wp-config.php" ;;
    plesk)     find /var/www/vhosts/*/httpdocs -name "wp-config.php" ;;
esac

Mistake #4: Silent Failures

# BAD - Fails silently on non-cPanel
whmapi1 some_command

Fix: Check and report

# GOOD
if [ "$SYS_CONTROL_PANEL" = "cpanel" ]; then
    whmapi1 some_command
else
    print_warning "This feature requires cPanel (current: $SYS_CONTROL_PANEL)"
    return 1
fi

Future Enhancements

Planned Improvements:

  1. Panel-specific feature matrix - Document what features work on which panels
  2. Automated testing framework - Docker containers for each panel
  3. Panel capability detection - Runtime feature detection
  4. Plugin architecture - Easy addition of new panel support

Control Panel Support Roadmap:

  • Phase 1-3: InterWorx (IN PROGRESS)
  • Phase 4: Plesk expansion (fill gaps)
  • Phase 5: DirectAdmin
  • Phase 6: CyberPanel

Questions and Support

Q: What if a feature is impossible on a specific panel? A: Document it, detect it, and fail gracefully with a clear message.

Q: Should I support all panels in every module? A: No. Class D modules can be panel-specific. Just document it.

Q: What about backward compatibility? A: Always maintain cPanel compatibility. It's the primary platform.

Q: How do I test without access to all panels? A: At minimum: syntax check + cPanel regression. InterWorx/Plesk testing is nice-to-have.


Version History

  • 1.0 (2025-11-19) - Initial standard established
    • Defined core principles
    • Created pattern library
    • Established testing requirements
    • Documented common mistakes