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!
This commit is contained in:
cschantz
2025-11-19 19:52:16 -05:00
parent 9b4a6ec5e1
commit 052a311907
2 changed files with 1032 additions and 0 deletions
+495
View File
@@ -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
+537
View File
@@ -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