From e805bac2a6f5b086bb547f87ea115a1e1d519185 Mon Sep 17 00:00:00 2001 From: cschantz Date: Wed, 19 Nov 2025 19:52:16 -0500 Subject: [PATCH] ARCHITECTURE: Multi-Control-Panel Design Standards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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! --- CONTROL_PANEL_QUICK_REFERENCE.md | 495 +++++++++++++++++++++++++ MULTI_CONTROL_PANEL_ARCHITECTURE.md | 537 ++++++++++++++++++++++++++++ 2 files changed, 1032 insertions(+) create mode 100644 CONTROL_PANEL_QUICK_REFERENCE.md create mode 100644 MULTI_CONTROL_PANEL_ARCHITECTURE.md diff --git a/CONTROL_PANEL_QUICK_REFERENCE.md b/CONTROL_PANEL_QUICK_REFERENCE.md new file mode 100644 index 0000000..04c4932 --- /dev/null +++ b/CONTROL_PANEL_QUICK_REFERENCE.md @@ -0,0 +1,495 @@ +# Control Panel Quick Reference Guide +**Version:** 1.0 +**Purpose:** Fast lookup of control panel differences while coding + +--- + +## Quick Panel Detection + +```bash +# cPanel +[ -f "/usr/local/cpanel/version" ] # Version file +[ -f "/etc/userdatadomains" ] # User/domain mapping +command -v whmapi1 # WHM API + +# Plesk +[ -f "/usr/local/psa/version" ] # Version file +command -v plesk # Plesk CLI + +# InterWorx +[ -d "/usr/local/interworx" ] # Install directory +[ -f "/etc/interworx/iworx.ini" ] # Config file +[ -x "/usr/local/interworx/bin/listaccounts.pex" ] # CLI tool +``` + +--- + +## File System Paths + +### User Home Directories +| Panel | Path | Notes | +|-------|------|-------| +| **cPanel** | `/home/username` | Standard Linux | +| **Plesk** | `/var/www/vhosts/domain.com` | Domain-centric | +| **InterWorx** | `/home/username` | Standard Linux | + +### Document Roots +| Panel | Primary Site | Addon Domain | Subdomain | +|-------|-------------|--------------|-----------| +| **cPanel** | `/home/user/public_html` | `/home/user/public_html/addon` | `/home/user/public_html/sub` | +| **Plesk** | `/var/www/vhosts/domain/httpdocs` | N/A (separate subscription) | `/var/www/vhosts/domain/sub.domain/httpdocs` | +| **InterWorx** | `/home/user/domain.com/html` | `/home/user/addon.com/html` | `/home/user/domain.com/sub/html` | + +### Access Logs +| Panel | Location | Filename Pattern | +|-------|----------|------------------| +| **cPanel** | `/var/log/apache2/domlogs/` or `/usr/local/apache/domlogs/` | `domain.com`, `domain.com-ssl_log` | +| **Plesk** | `/var/www/vhosts/system/domain.com/logs/` | `access_log`, `access_ssl_log` | +| **InterWorx** | `/home/user/var/domain.com/logs/` | `access_log` (combined HTTP+HTTPS) | + +### Error Logs +| Panel | Location | Notes | +|-------|----------|-------| +| **cPanel** | `/var/log/apache2/domlogs/domain-error_log` | Centralized per-domain | +| **Plesk** | `/var/www/vhosts/system/domain.com/logs/error_log` | Per-domain | +| **InterWorx** | `/home/user/var/domain.com/logs/error_log` | Per-domain in user home | + +### PHP Error Logs +| Panel | Location | Notes | +|-------|----------|-------| +| **cPanel** | `/home/user/public_html/error_log` | In document root | +| **Plesk** | `/var/www/vhosts/domain/httpdocs/error_log` | In document root | +| **InterWorx** | `/home/user/domain.com/html/error_log` | In document root | + +### SSL Certificates +| Panel | Location | Format | +|-------|----------|--------| +| **cPanel** | `/etc/letsencrypt/live/domain.com/` or `/var/cpanel/ssl/` | Let's Encrypt or AutoSSL | +| **Plesk** | `/etc/letsencrypt/live/domain.com/` | Let's Encrypt | +| **InterWorx** | `/etc/letsencrypt/live/domain.com/` | Let's Encrypt | + +### Mail Directories +| Panel | Location | Structure | +|-------|----------|-----------| +| **cPanel** | `/home/user/mail/domain.com/account/` | Per-domain folders | +| **Plesk** | `/var/qmail/mailnames/domain.com/account/` | Qmail structure | +| **InterWorx** | `/home/user/var/domain.com/mail/account/` | Per-domain in user home | + +### Cron Jobs +| Panel | Location | Format | +|-------|----------|--------| +| **cPanel** | `/var/spool/cron/username` | Standard crontab | +| **Plesk** | `/var/spool/cron/username` | Standard crontab | +| **InterWorx** | `/var/spool/cron/username` | Standard crontab | + +--- + +## Configuration Files + +### User Configuration +| Panel | Location | Format | Contains | +|-------|----------|--------|----------| +| **cPanel** | `/var/cpanel/users/username` | Key-value | DNS, IP, disk quota, domains | +| **Plesk** | Plesk Database | SQL | All config in MySQL/PostgreSQL | +| **InterWorx** | NodeWorx Database + vhost configs | Mixed | listaccounts.pex CLI or DB queries | + +### Domain Configuration +| Panel | Location | Format | Contains | +|-------|----------|--------|----------| +| **cPanel** | `/var/cpanel/userdata/user/domain.com` | Apache-like | DocumentRoot, ServerAlias, PHP handlers | +| **Plesk** | Plesk Database | SQL | Vhost config in database | +| **InterWorx** | `/etc/httpd/conf.d/vhost_domain.com.conf` | Apache vhost | Auto-generated from templates | + +### Apache Main Config +| Panel | Include Location | How Domains Added | +|-------|------------------|-------------------| +| **cPanel** | `/etc/apache2/conf.d/includes/` | Auto-generated from userdata | +| **Plesk** | `/etc/httpd/conf.d/zz*.conf` | Generated from Plesk DB | +| **InterWorx** | `/etc/httpd/conf.d/vhost_*.conf` | One file per domain | + +--- + +## Database Management + +### Database Prefixes +| Panel | Prefix Pattern | Example | Max Prefix Length | +|-------|----------------|---------|-------------------| +| **cPanel** | `username_` | `johndoe_wordpress` | 16 chars total (7 for username + _ + 8 for dbname) | +| **Plesk** | None (user-scoped) | `wordpress` | No prefix | +| **InterWorx** | `first8charsOfDomain_` | `examplec_wordpress` | First 8 chars of domain (dots removed) | + +### MySQL User Prefixes +| Panel | User Pattern | Example | Notes | +|-------|--------------|---------|-------| +| **cPanel** | `username_` | `johndoe_wpuser` | Same as database prefix | +| **Plesk** | None | `wpuser` | Scoped to database | +| **InterWorx** | `first8charsOfDomain_` | `examplec_wpuser` | Same as database prefix | + +### Database File Locations +| Panel | Data Directory | Notes | +|-------|----------------|-------| +| **cPanel** | `/var/lib/mysql/` | Standard MySQL | +| **Plesk** | `/var/lib/mysql/` | Standard MySQL | +| **InterWorx** | `/var/lib/mysql/` | Standard MySQL | + +--- + +## CLI Tools & APIs + +### WHM/Root Level APIs +| Panel | Tool | Example Command | Auth Required | +|-------|------|-----------------|---------------| +| **cPanel** | `whmapi1` | `whmapi1 listaccts` | Root or API token | +| **Plesk** | `plesk bin server` | `plesk bin server --info` | Root | +| **InterWorx** | `nodeworx` | `nodeworx -u -n -c Siteworx -a listAccounts` | Root + setup | + +### User-Level APIs +| Panel | Tool | Example Command | Auth Required | +|-------|------|-----------------|---------------| +| **cPanel** | `uapi` | `uapi --user=john DomainInfo list_domains` | User or API token | +| **Plesk** | `plesk bin subscription` | `plesk bin subscription --list` | Root | +| **InterWorx** | `siteworx` | `siteworx -u -n -c Siteworx -a listDomains` | User + setup | + +### Account Listing +| Panel | Command | Output Format | +|-------|---------|---------------| +| **cPanel** | `whmapi1 listaccts` | JSON | +| **cPanel** | `/etc/trueuserdomains` | Text: `domain.com: username` | +| **cPanel** | `/etc/userdatadomains` | Text: `domain: user==owner==main==domain==docroot` | +| **Plesk** | `plesk bin subscription --list` | Text list of domains | +| **InterWorx** | `/usr/local/interworx/bin/listaccounts.pex` | Text: `username domain.com` | + +### Domain Listing (for specific user) +| Panel | Command | Output | +|-------|---------|--------| +| **cPanel** | `grep "^DNS" /var/cpanel/users/$user` | DNS records from user file | +| **cPanel** | `grep ":${user}==" /etc/userdatadomains` | All domains for user | +| **Plesk** | `plesk bin subscription --list` | All subscriptions (filter by owner) | +| **InterWorx** | `listaccounts.pex` then parse vhosts | Username + primary domain | + +### Database Listing +| Panel | Command | Notes | +|-------|---------|-------| +| **cPanel** | `mysql -e "SHOW DATABASES" \| grep "^${username}_"` | Filter by prefix | +| **Plesk** | `plesk bin database --list` | All databases (filter by domain) | +| **InterWorx** | `mysql -e "SHOW DATABASES" \| grep "^${domain_prefix}_"` | **Use domain prefix!** | + +--- + +## PHP Configuration + +### PHP Handler Types +| Panel | Handlers Supported | Default | Location | +|-------|-------------------|---------|----------| +| **cPanel** | DSO, suPHP, FastCGI, FPM | EasyApache 4 FPM | `/opt/cpanel/ea-php*/` | +| **Plesk** | Apache module, FPM, FastCGI | FPM | `/opt/plesk/php/*/` | +| **InterWorx** | mod_php, FPM, FastCGI | FPM | `/etc/php-fpm.d/` | + +### PHP.INI Locations +| Panel | Global | Per-Domain | Per-Directory | +|-------|--------|------------|---------------| +| **cPanel** | `/opt/cpanel/ea-php*/root/etc/php.ini` | `/home/user/.php.ini` | `/home/user/public_html/.user.ini` | +| **Plesk** | `/etc/php.ini` | `/var/www/vhosts/system/domain/conf/php.ini` | `.user.ini` in directory | +| **InterWorx** | `/etc/php.ini` | `/home/user/domain/conf/php.ini` | `.user.ini` in directory | + +### PHP Version Selection +| Panel | Mechanism | Granularity | +|-------|-----------|-------------| +| **cPanel** | MultiPHP Manager (WHM) or `.htaccess` | Per-domain or per-directory | +| **Plesk** | Plesk Panel or plesk CLI | Per-domain or per-subdirectory | +| **InterWorx** | SiteWorx Panel or php-fpm pools | Per-domain | + +--- + +## Email Configuration + +### Mail Server Software +| Panel | MTA | POP3/IMAP | Webmail | +|-------|-----|-----------|---------| +| **cPanel** | Exim | Dovecot | Horde, RoundCube, SquirrelMail | +| **Plesk** | Postfix or Qmail | Dovecot or Courier | RoundCube, Horde | +| **InterWorx** | Postfix | Dovecot | RoundCube, SquirrelMail | + +### Email Account Locations +| Panel | Config Location | Password Storage | +|-------|-----------------|------------------| +| **cPanel** | `/home/user/etc/domain/passwd` | Shadow file in etc/ | +| **Plesk** | Plesk Database | Database | +| **InterWorx** | `/home/user/var/domain/mail/` | Database + files | + +--- + +## FTP Configuration + +### FTP Server +| Panel | FTP Daemon | Config Location | +|-------|------------|-----------------| +| **cPanel** | Pure-FTPd or ProFTPD | `/etc/pure-ftpd.conf` or `/etc/proftpd.conf` | +| **Plesk** | ProFTPD | `/etc/proftpd.conf` | +| **InterWorx** | ProFTPD | `/etc/proftpd.conf` | + +### FTP Account Listing +| Panel | Location | Format | +|-------|----------|--------| +| **cPanel** | `/etc/proftpd/$user` or Pure-FTPd DB | Config files or virtual users | +| **Plesk** | Plesk Database | SQL | +| **InterWorx** | `/etc/proftpd.conf` includes | Parsed from config | + +--- + +## Security Features + +### Brute Force Protection +| Panel | Feature | How it Works | CLI Access | +|-------|---------|--------------|------------| +| **cPanel** | cPHulk | Tracks failed logins, bans IPs | `whmapi1 cphulkd_*` | +| **Plesk** | fail2ban | Monitors logs, uses iptables | `fail2ban-client` | +| **InterWorx** | ModSecurity + fail2ban | WAF + log monitoring | `fail2ban-client` | + +### Firewall Integration +| Panel | Default Firewall | Location | +|-------|-----------------|----------| +| **cPanel** | CSF (optional) or firewalld | `/etc/csf/` or `firewall-cmd` | +| **Plesk** | firewalld or iptables | `firewall-cmd` or `/etc/sysconfig/iptables` | +| **InterWorx** | firewalld or iptables | `firewall-cmd` or `/etc/sysconfig/iptables` | + +### ModSecurity +| Panel | Enabled by Default | Config Location | +|-------|-------------------|-----------------| +| **cPanel** | Optional (EasyApache 4) | `/etc/apache2/conf.d/modsec/` | +| **Plesk** | Optional (Extensions) | `/etc/httpd/conf.d/mod_security.conf` | +| **InterWorx** | Optional | `/etc/httpd/conf.d/mod_security.conf` | + +--- + +## Backup Systems + +### Native Backup Tools +| Panel | Tool | Backup Location | Incremental Support | +|-------|------|-----------------|---------------------| +| **cPanel** | cPanel Backup | `/backup/` | Yes (JetBackup addon) | +| **Plesk** | Plesk Backup Manager | `/var/lib/psa/dumps/` | No (full only) | +| **InterWorx** | NodeWorx Backup | `/backup/` or custom | Yes | + +### Backup File Format +| Panel | Format | Compression | Includes | +|-------|--------|-------------|----------| +| **cPanel** | tar.gz | gzip | Home dir, DBs, email, config | +| **Plesk** | tar | Optional gzip | Subscription data, DBs, mail | +| **InterWorx** | tar.gz | gzip | SiteWorx account, DBs, email | + +--- + +## WordPress Detection + +### wp-config.php Locations +```bash +# cPanel +find /home/*/public_html -name "wp-config.php" +find /home/*/public_html/* -name "wp-config.php" # Addon domains + +# Plesk +find /var/www/vhosts/*/httpdocs -name "wp-config.php" + +# InterWorx +find /home/*/*/html -name "wp-config.php" +``` + +### WordPress Paths by Panel +| Panel | Single Site | Multisite | Addon Domain WP | +|-------|------------|-----------|-----------------| +| **cPanel** | `/home/user/public_html/` | `/home/user/public_html/wp/` | `/home/user/public_html/addon/` | +| **Plesk** | `/var/www/vhosts/domain/httpdocs/` | `/var/www/vhosts/domain/httpdocs/wp/` | N/A (separate subscription) | +| **InterWorx** | `/home/user/domain.com/html/` | `/home/user/domain.com/html/wp/` | `/home/user/addon.com/html/` | + +--- + +## Common File Patterns + +### .htaccess Locations +```bash +# All panels - in document root +/home/user/public_html/.htaccess # cPanel primary +/home/user/domain.com/html/.htaccess # InterWorx +/var/www/vhosts/domain/httpdocs/.htaccess # Plesk +``` + +### robots.txt Locations +```bash +# Same as .htaccess +# In document root +``` + +### Log Rotation +| Panel | Rotation Config | Default Retention | +|-------|----------------|-------------------| +| **cPanel** | `/etc/logrotate.d/cpanel` | 30 days | +| **Plesk** | `/etc/logrotate.d/plesk` | Varies | +| **InterWorx** | `/etc/logrotate.d/interworx` | 30 days | + +--- + +## Process Ownership + +### Apache/Web Server Processes +| Panel | User | Group | Notes | +|-------|------|-------|-------| +| **cPanel** | `nobody` (main) | `nobody` | Requests run as user via suEXEC/suPHP/FPM | +| **Plesk** | `apache` or `www-data` | `apache` or `www-data` | Depends on OS | +| **InterWorx** | `apache` | `apache` | Requests run as user via suEXEC/FPM | + +### PHP-FPM Pools +| Panel | Pool Config | User/Group | +|-------|-------------|------------| +| **cPanel** | `/opt/cpanel/ea-php*/root/etc/php-fpm.d/` | Per-user pools (username:username) | +| **Plesk** | `/etc/php-fpm.d/` | Per-domain pools | +| **InterWorx** | `/etc/php-fpm.d/` | Per-domain pools (username:username) | + +--- + +## Quick Code Snippets + +### Get All Users +```bash +# cPanel +cat /etc/trueuserowners | cut -d: -f2 | sort -u + +# Plesk +plesk bin subscription --list | awk '{print $1}' + +# InterWorx +/usr/local/interworx/bin/listaccounts.pex --output user +``` + +### Get Domains for User +```bash +# cPanel +grep "^DNS" /var/cpanel/users/$user | awk '{print $2}' + +# Plesk +plesk bin subscription --list -o $user + +# InterWorx +grep -l "SuexecUserGroup ${user}" /etc/httpd/conf.d/vhost_*.conf | \ + sed 's|.*/vhost_||; s|\.conf$||' +``` + +### Get Disk Usage for User +```bash +# All panels (if user has /home directory) +du -sh /home/$user + +# cPanel (from quota) +quota -u $user | tail -1 | awk '{print $2}' + +# Plesk +plesk bin subscription --info domain.com | grep "Disk space used" +``` + +### Check if Domain Exists +```bash +# cPanel +grep -q "^${domain}:" /etc/userdatadomains + +# Plesk +plesk bin subscription --info "$domain" &>/dev/null + +# InterWorx +[ -f "/etc/httpd/conf.d/vhost_${domain}.conf" ] +``` + +--- + +## Panel-Specific Quirks + +### cPanel Gotchas +- **Addon domains** share public_html with primary domain +- **Parked domains** are aliases (same document root as primary) +- **Database names** limited to 64 chars (including prefix!) +- **User passwords** != database passwords != FTP passwords +- **Main IP** stored in `/var/cpanel/mainip` + +### Plesk Gotchas +- **Each domain** is a separate subscription (even for same owner) +- **No shared hosting** structure (each domain isolated) +- **Database prefixes** don't exist (databases scoped to subscription) +- **Mail users** are separate from system users +- **CLI requires** lots of `--info` calls (no simple config files) + +### InterWorx Gotchas +- **Database prefix** is domain-based, NOT username-based! +- **Logs are per-domain** in user home (not centralized) +- **No separate** HTTP/HTTPS logs (combined in access_log) +- **Domain config** is one vhost file per domain +- **Listaccounts.pex** only returns username + primary domain (not addon domains) + +--- + +## Migration Implications + +### cPanel → InterWorx +- ✅ User home structure similar +- ⚠️ Document root changes (public_html → domain.com/html) +- ⚠️ Database prefixes change (username_ → domain_) +- ⚠️ Log locations move to user home +- ✅ Email structure compatible with migration + +### cPanel → Plesk +- ❌ Completely different structure +- ❌ Domain-centric vs user-centric +- ❌ No shared hosting model +- ❌ Requires full account restructure + +### Plesk → InterWorx +- ⚠️ Structure change (vhosts → home) +- ⚠️ Database prefix added +- ✅ Can map subscriptions to users +- ⚠️ Mail system different + +--- + +## Testing Commands + +### Verify Panel Detection +```bash +# Should return: cpanel, plesk, interworx, or none +source /root/server-toolkit/lib/system-detect.sh +echo $SYS_CONTROL_PANEL +``` + +### Verify Log Discovery +```bash +source /root/server-toolkit/lib/system-detect.sh +echo $SYS_LOG_DIR +ls -la "$SYS_LOG_DIR" | head +``` + +### Verify User Functions +```bash +source /root/server-toolkit/lib/user-manager.sh +eval $(get_user_info "someuser") +echo "User: $USERNAME" +echo "Primary: $PRIMARY_DOMAIN" +echo "All domains: $ALL_DOMAINS" +``` + +--- + +## References + +### Official Documentation +- cPanel: https://docs.cpanel.net/ +- Plesk: https://docs.plesk.com/ +- InterWorx: https://www.interworx.com/support/docs/ + +### Useful Files to Study +- `/etc/userdatadomains` (cPanel domain mapping) +- `/etc/trueuserowners` (cPanel user→domain) +- `/etc/trueuserdomains` (cPanel domain→user) +- `/etc/httpd/conf.d/vhost_*.conf` (InterWorx vhosts) +- `/var/www/vhosts/` (Plesk structure) + +--- + +**Last Updated:** 2025-11-19 +**Maintainer:** Server Toolkit Team diff --git a/MULTI_CONTROL_PANEL_ARCHITECTURE.md b/MULTI_CONTROL_PANEL_ARCHITECTURE.md new file mode 100644 index 0000000..fa6b7b1 --- /dev/null +++ b/MULTI_CONTROL_PANEL_ARCHITECTURE.md @@ -0,0 +1,537 @@ +# 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** +```bash +# ❌ 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** +```bash +# ❌ 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** +```bash +# ❌ 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** +```bash +# ✅ 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:** +```bash +# 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() +```bash +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() +```bash +domains=$(get_user_domains "username") +# Returns newline-separated list of domains +``` + +#### get_user_databases() +```bash +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 + +```bash +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 + +```bash +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 + +```bash +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 + +```bash +# 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** +```bash +# 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 +``` + +2. **Replace Hardcoded Paths** +```bash +# Find all hardcoded paths +grep -n "/var/cpanel\|/usr/local/cpanel\|public_html\|domlogs" yourscript.sh + +# Replace with system variables or functions +``` + +3. **Wrap API Calls** +```bash +# Find all API calls +grep -n "whmapi\|uapi\|cpapi" yourscript.sh + +# Wrap in conditional checks +``` + +4. **Add Control Panel Cases** +```bash +# For panel-specific logic, use case statements +case "$SYS_CONTROL_PANEL" in + cpanel) ... ;; + plesk) ... ;; + interworx) ... ;; + *) ... ;; +esac +``` + +5. **Test Syntax** +```bash +bash -n yourscript.sh +``` + +6. **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 +```bash +# BAD - Command might exist on other panels +if command -v whmapi1 &>/dev/null; then + # Assume cPanel +fi +``` + +**Fix:** Always check `SYS_CONTROL_PANEL` +```bash +# GOOD +if [ "$SYS_CONTROL_PANEL" = "cpanel" ] && command -v whmapi1 &>/dev/null; then + # Definitely cPanel and API available +fi +``` + +### ❌ Mistake #2: Assuming File Locations +```bash +# BAD - Only works on cPanel +domains=$(grep "^DNS" /var/cpanel/users/$user | awk '{print $2}') +``` + +**Fix:** Use abstraction +```bash +# GOOD +domains=$(get_user_domains "$user") +``` + +### ❌ Mistake #3: Hardcoding Document Root Structure +```bash +# BAD - Assumes cPanel's public_html +find /home/*/public_html -name "wp-config.php" +``` + +**Fix:** Use dynamic paths +```bash +# 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 +```bash +# BAD - Fails silently on non-cPanel +whmapi1 some_command +``` + +**Fix:** Check and report +```bash +# 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