Compare commits
5 Commits
46fad6107d
...
1e9e33171d
| Author | SHA1 | Date | |
|---|---|---|---|
| 1e9e33171d | |||
| 3ef3f4c61b | |||
| af510e7fb5 | |||
| 4dd7bfeabc | |||
| 7f2d236c49 |
@@ -1,172 +0,0 @@
|
||||
# Server Toolkit Coding Guidelines
|
||||
|
||||
## Color Code Usage - CRITICAL
|
||||
|
||||
### The Problem
|
||||
Using `echo` without the `-e` flag causes ANSI escape sequences to display literally instead of being interpreted:
|
||||
|
||||
```bash
|
||||
# WRONG - Shows literal: \033[1m1\033[0m
|
||||
echo " ${BOLD}1${NC} - Menu option"
|
||||
|
||||
# RIGHT - Shows: 1 (bold and colored)
|
||||
echo -e " ${BOLD}1${NC} - Menu option"
|
||||
```
|
||||
|
||||
### Prevention Rules
|
||||
|
||||
**Rule 1: Always use `echo -e` when string contains color variables**
|
||||
```bash
|
||||
# WRONG:
|
||||
echo " ${BOLD}Option${NC}"
|
||||
echo "Status: ${GREEN}OK${NC}"
|
||||
|
||||
# RIGHT:
|
||||
echo -e " ${BOLD}Option${NC}"
|
||||
echo -e "Status: ${GREEN}OK${NC}"
|
||||
```
|
||||
|
||||
**Rule 2: Use helper functions from common-functions.sh**
|
||||
```bash
|
||||
# Source the library
|
||||
source /root/server-toolkit/lib/common-functions.sh
|
||||
|
||||
# Use built-in print functions (already use echo -e)
|
||||
print_success "Operation completed"
|
||||
print_error "Something went wrong"
|
||||
print_info "Information message"
|
||||
|
||||
# For custom colored output, use cecho()
|
||||
cecho "Custom ${RED}colored${NC} text"
|
||||
```
|
||||
|
||||
**Rule 3: No -e flag needed when NOT using quotes**
|
||||
```bash
|
||||
# This is OK (no quotes around the whole thing)
|
||||
echo ${BOLD}Title${NC}
|
||||
|
||||
# But this needs -e (quotes around everything)
|
||||
echo -e "${BOLD}Title${NC}"
|
||||
```
|
||||
|
||||
### Quick Reference
|
||||
|
||||
| Scenario | Command |
|
||||
|----------|---------|
|
||||
| Menu option with colors | `echo -e " ${BOLD}1${NC} - Option"` |
|
||||
| Success message | `print_success "Done"` or `echo -e "${GREEN}✓${NC} Done"` |
|
||||
| Error message | `print_error "Failed"` or `echo -e "${RED}✗${NC} Failed"` |
|
||||
| Custom colored text | `cecho "Text ${RED}red${NC} normal"` |
|
||||
| Plain text (no colors) | `echo "Plain text"` (no -e needed) |
|
||||
|
||||
### How to Find and Fix
|
||||
|
||||
**Search for potential issues:**
|
||||
```bash
|
||||
# Find echo statements with color variables that might be missing -e
|
||||
grep -n 'echo ".*\${\(BOLD\|.*_COLOR\|NC\|RED\|GREEN\|YELLOW\|BLUE\)' your_script.sh
|
||||
```
|
||||
|
||||
**Common patterns to fix:**
|
||||
```bash
|
||||
# BEFORE:
|
||||
echo " ${BOLD}1${NC} - Enable Feature"
|
||||
echo "Status: ${GREEN}Active${NC}"
|
||||
echo "${RED}[ERROR]${NC} Failed"
|
||||
|
||||
# AFTER:
|
||||
echo -e " ${BOLD}1${NC} - Enable Feature"
|
||||
echo -e "Status: ${GREEN}Active${NC}"
|
||||
echo -e "${RED}[ERROR]${NC} Failed"
|
||||
|
||||
# OR use helper:
|
||||
cecho " ${BOLD}1${NC} - Enable Feature"
|
||||
cecho "Status: ${GREEN}Active${NC}"
|
||||
print_error "Failed"
|
||||
```
|
||||
|
||||
### Why This Matters
|
||||
|
||||
**Impact of the bug:**
|
||||
- Menus show escape codes instead of colors: `\033[1m1\033[0m`
|
||||
- Makes interface look broken and unprofessional
|
||||
- Reduces readability and user experience
|
||||
- Hard to debug because it "looks right" in the code
|
||||
|
||||
**Historical issues:**
|
||||
- Security hardening menu (fixed: commit 7053b3b)
|
||||
- Various other menus and status displays
|
||||
- User feedback: "This happens a lot with you"
|
||||
|
||||
### Pre-commit Checklist
|
||||
|
||||
Before committing code with color output:
|
||||
- [ ] All `echo` statements with `${COLOR}` variables use `-e` flag
|
||||
- [ ] Or use `cecho()` helper function instead
|
||||
- [ ] Or use `print_*()` functions from common-functions.sh
|
||||
- [ ] Test output in terminal to verify colors render correctly
|
||||
- [ ] Run: `bash -n script.sh` to check syntax
|
||||
- [ ] Run: `shellcheck script.sh` if available
|
||||
|
||||
## Performance Guidelines
|
||||
|
||||
### Avoid Subprocesses in Loops
|
||||
|
||||
**Rule: Use bash built-ins instead of spawning processes**
|
||||
|
||||
```bash
|
||||
# WRONG - Spawns subprocess (slow)
|
||||
url_lower=$(echo "$url" | tr '[:upper:]' '[:lower:]')
|
||||
url_lower=$(echo "$url" | tr 'A-Z' 'a-z')
|
||||
|
||||
# RIGHT - Bash built-in (fast)
|
||||
url_lower="${url,,}"
|
||||
|
||||
# WRONG - Multiple subprocesses
|
||||
hostname=$(hostname)
|
||||
for item in $list; do
|
||||
check_hostname "$hostname" # Calls hostname 1000s of times
|
||||
done
|
||||
|
||||
# RIGHT - Cache the result
|
||||
CACHED_HOSTNAME="${HOSTNAME:-$(hostname)}"
|
||||
for item in $list; do
|
||||
check_hostname "$CACHED_HOSTNAME"
|
||||
done
|
||||
```
|
||||
|
||||
**Impact:** On high-traffic servers (1000+ req/sec), subprocess elimination prevents tens of thousands of unnecessary forks per second.
|
||||
|
||||
### Performance Quick Reference
|
||||
|
||||
| Operation | Slow (subprocess) | Fast (built-in) |
|
||||
|-----------|-------------------|-----------------|
|
||||
| Lowercase | `$(echo "$var" \| tr '[:upper:]' '[:lower:]')` | `${var,,}` |
|
||||
| Uppercase | `$(echo "$var" \| tr '[:lower:]' '[:upper:]')` | `${var^^}` |
|
||||
| Substring | `$(echo "$var" \| cut -c1-5)` | `${var:0:5}` |
|
||||
| Replace | `$(echo "$var" \| sed 's/old/new/')` | `${var//old/new}` |
|
||||
| Length | `$(echo "$var" \| wc -c)` | `${#var}` |
|
||||
|
||||
## Additional Guidelines
|
||||
|
||||
### Error Handling
|
||||
- Always check return codes for critical operations
|
||||
- Use `set -euo pipefail` for strict error handling in new scripts
|
||||
- Provide meaningful error messages with context
|
||||
|
||||
### Function Documentation
|
||||
- Add comment block above complex functions
|
||||
- Document parameters, return values, and side effects
|
||||
- Include usage examples for non-obvious functions
|
||||
|
||||
### Variable Naming
|
||||
- Use descriptive names: `user_count` not `uc`
|
||||
- Constants in UPPER_CASE: `MAX_RETRIES=3`
|
||||
- Local variables in lower_case: `local temp_file="/tmp/data"`
|
||||
- Global exports in UPPER_CASE: `export LOG_DIR="/var/log"`
|
||||
|
||||
### Testing
|
||||
- Test with both light and dark terminal backgrounds
|
||||
- Test with `TOOLKIT_NO_COLOR=1` for monochrome output
|
||||
- Verify output doesn't overflow on 24-line terminals (standard)
|
||||
- Test with realistic data volumes (not just 1-2 entries)
|
||||
@@ -1,214 +0,0 @@
|
||||
# CORRECTED Audit Summary - After Triple-Check
|
||||
|
||||
## Date: 2025-12-23
|
||||
## Status: TRIPLE-CHECKED AND VERIFIED
|
||||
|
||||
---
|
||||
|
||||
## CRITICAL CORRECTION
|
||||
|
||||
**My initial audit report (PLATFORM_AUDIT_FINDINGS.md) was LARGELY INCORRECT.**
|
||||
|
||||
After triple-checking the actual code, here's what's REALLY true:
|
||||
|
||||
---
|
||||
|
||||
## ACTUAL FINDINGS
|
||||
|
||||
### ✅ GOOD NEWS - What Already Works:
|
||||
|
||||
1. **lib/domain-discovery.sh** - FULLY MULTI-PLATFORM ✅
|
||||
- ALL 13 functions have Plesk cases ✓
|
||||
- ALL 13 functions have standalone fallbacks ✓
|
||||
- Functions like `list_all_domains()`, `get_domain_owner()`, etc. work on all platforms
|
||||
|
||||
2. **lib/system-detect.sh** - Detects all platforms correctly ✅
|
||||
|
||||
3. **lib/plesk-helpers.sh** - 31 Plesk helper functions ready ✅
|
||||
|
||||
4. **lib/user-manager.sh** - Already has Plesk/InterWorx/standalone support ✅
|
||||
|
||||
5. **build_domains_section() HAS fallback logic** ✅
|
||||
- Lines 333-359: `else` branch for non-cPanel systems
|
||||
- Uses `get_user_domains()` which is panel-agnostic
|
||||
- Works on Plesk/standalone already!
|
||||
|
||||
---
|
||||
|
||||
### ❌ ACTUAL ISSUES FOUND (Only 3, not 8!):
|
||||
|
||||
#### Issue #1: build_domains_section() - cPanel Userdata Optimization
|
||||
**Severity**: MEDIUM (not critical!)
|
||||
**Location**: Lines 255-332
|
||||
|
||||
The function has TWO code paths:
|
||||
1. **Lines 255-332**: Optimized cPanel path (parses userdata files for detailed info)
|
||||
2. **Lines 333-359**: Fallback path for ALL other systems (uses panel-agnostic functions)
|
||||
|
||||
**Problem**: The cPanel path gets richer data (PHP version, aliases, HTTP status, domain type)
|
||||
**Impact**: Plesk/standalone get less detailed domain information, but they DO work
|
||||
|
||||
**Not a blocker** - just means Plesk won't get as detailed info as cPanel
|
||||
|
||||
---
|
||||
|
||||
#### Issue #2: /etc/localdomains and /etc/remotedomains - Not Wrapped
|
||||
**Severity**: LOW (cosmetic, not critical!)
|
||||
**Location**: Lines 364-396
|
||||
|
||||
```bash
|
||||
# Check /etc/localdomains (cPanel local domains not yet added)
|
||||
if [ -f "/etc/localdomains" ]; then
|
||||
# ...
|
||||
fi
|
||||
```
|
||||
|
||||
**Problem**: Not wrapped in `if [ "$SYS_CONTROL_PANEL" = "cpanel" ]`
|
||||
**Impact**: NONE - the `if [ -f "/etc/localdomains" ]` check means it skips silently on non-cPanel
|
||||
**Fix**: Nice to have for code cleanliness, but not blocking anything
|
||||
|
||||
---
|
||||
|
||||
#### Issue #3: WordPress Path Parsing - Hardcoded /home/
|
||||
**Severity**: MEDIUM
|
||||
**Location**: Lines 411, 414
|
||||
|
||||
```bash
|
||||
# Line 405: Uses $SYS_USER_HOME_BASE - THIS IS GOOD ✅
|
||||
local wp_configs=$(find $SYS_USER_HOME_BASE -name "wp-config.php" -type f 2>/dev/null)
|
||||
|
||||
# Line 411: Assumes field 3 is username - BREAKS ON PLESK ❌
|
||||
local username=$(echo "$wp_dir" | cut -d'/' -f3)
|
||||
|
||||
# Line 414: Hardcodes /home/ - BREAKS ON PLESK ❌
|
||||
local path_after_home=$(echo "$wp_dir" | sed "s|^/home/$username/||")
|
||||
```
|
||||
|
||||
**Problem**: Path parsing assumes `/home/username/` structure
|
||||
**Impact**: WordPress detection works but extracts wrong username/domain on Plesk
|
||||
**Fix Needed**: Panel-specific path parsing logic
|
||||
|
||||
---
|
||||
|
||||
## WHAT THIS MEANS
|
||||
|
||||
### For Plesk Support:
|
||||
|
||||
**Current State**: MOSTLY WORKING! 🎉
|
||||
- ✅ Domain discovery works (via fallback path)
|
||||
- ✅ User detection works
|
||||
- ✅ Database detection works
|
||||
- ⚠️ WordPress detection works but gets wrong owner/domain
|
||||
- ⚠️ Domain details less rich than cPanel (no PHP version, aliases, status codes)
|
||||
|
||||
**To Make Plesk Excellent**:
|
||||
1. Create `build_domains_plesk()` function (get richer Plesk domain data)
|
||||
2. Fix WordPress path parsing for Plesk paths
|
||||
3. Optionally wrap `/etc/localdomains` checks (code cleanliness)
|
||||
|
||||
### For Standalone Support:
|
||||
|
||||
**Current State**: BASIC SUPPORT EXISTS! 🎉
|
||||
- ✅ domain-discovery.sh has standalone fallbacks for ALL functions
|
||||
- ✅ Scans `/var/www/`, `/home/`, common web directories
|
||||
- ✅ Uses `stat -c "%U"` for ownership
|
||||
- ⚠️ WordPress detection works but path parsing needs improvement
|
||||
|
||||
**To Make Standalone Excellent**:
|
||||
1. Add vhost parsing (Apache/Nginx configs) - currently just scans directories
|
||||
2. Fix WordPress path parsing for various web roots
|
||||
3. Create `build_domains_standalone()` for richer data
|
||||
|
||||
---
|
||||
|
||||
## REVISED IMPLEMENTATION PLAN
|
||||
|
||||
### Priority 1: Quick Plesk Fixes (2-3 hours)
|
||||
|
||||
**Goal**: Make Plesk experience match cPanel quality
|
||||
|
||||
1. **Create build_domains_plesk()** function (1 hour)
|
||||
- Use `plesk bin site --list`
|
||||
- Call `plesk_get_docroot()`, `plesk_get_logdir()`, etc.
|
||||
- Get PHP version, SSL status from Plesk
|
||||
- Format same as cPanel output
|
||||
|
||||
2. **Fix WordPress path parsing** (1 hour)
|
||||
- Add panel-specific logic for username/domain extraction
|
||||
- Test on both cPanel and Plesk paths
|
||||
|
||||
3. **Wrap cPanel-only file checks** (15 minutes)
|
||||
- Add `if [ "$SYS_CONTROL_PANEL" = "cpanel" ]` around lines 364-396
|
||||
- Code cleanliness
|
||||
|
||||
### Priority 2: Enhanced Standalone Support (4-6 hours)
|
||||
|
||||
**Goal**: Parse vhost configs instead of just directory scanning
|
||||
|
||||
1. **Create lib/standalone-helpers.sh** (3 hours)
|
||||
- `standalone_parse_apache_vhosts()` - read ServerName from configs
|
||||
- `standalone_parse_nginx_vhosts()` - read server_name from configs
|
||||
- Extract DocumentRoot, log paths, aliases from configs
|
||||
|
||||
2. **Create build_domains_standalone()** (2 hours)
|
||||
- Use vhost parser for domain discovery
|
||||
- Get richer domain data (document roots, log paths)
|
||||
- Format similar to cPanel output
|
||||
|
||||
3. **Test on Ubuntu/Debian/AlmaLinux** (1 hour)
|
||||
|
||||
---
|
||||
|
||||
## CORRECTED TIMELINE
|
||||
|
||||
### Week 1:
|
||||
- **Day 1 (4 hours)**: Priority 1 - Plesk fixes
|
||||
- **Day 2 (2 hours)**: Test Plesk fixes on Plesk server
|
||||
- **Days 3-4 (8 hours)**: Priority 2 - Standalone vhost parsing
|
||||
- **Day 5 (2 hours)**: Test standalone on Ubuntu/AlmaLinux
|
||||
|
||||
### Week 2:
|
||||
- **Days 1-2**: Integration testing all platforms
|
||||
- **Days 3-5**: Bug fixes, edge cases, documentation
|
||||
|
||||
---
|
||||
|
||||
## BOTTOM LINE
|
||||
|
||||
**My initial audit was OVERLY PESSIMISTIC.**
|
||||
|
||||
The codebase is in MUCH BETTER shape than I thought:
|
||||
|
||||
| Component | Initial Assessment | CORRECTED Assessment |
|
||||
|-----------|-------------------|---------------------|
|
||||
| domain-discovery.sh | ❌ No standalone support | ✅ Full multi-platform |
|
||||
| reference-db.sh | ❌ 100% cPanel-only | ⚠️ Works on all, needs optimization |
|
||||
| WordPress detection | ❌ Completely broken | ⚠️ Works, needs path fix |
|
||||
| Overall | "2-3 weeks" | **"3-5 days"** |
|
||||
|
||||
---
|
||||
|
||||
## WHAT TO DO NEXT
|
||||
|
||||
**RECOMMENDED**: Start with Priority 1 (Plesk fixes)
|
||||
|
||||
1. Create `build_domains_plesk()` function
|
||||
2. Fix WordPress path parsing
|
||||
3. Test on Plesk server
|
||||
4. IF working well, proceed to Priority 2 (standalone vhost parsing)
|
||||
|
||||
**ALTERNATIVE**: Test current code on Plesk server FIRST
|
||||
- The fallback path might already work well enough
|
||||
- WordPress issue might not be critical if domain detection works
|
||||
- Could skip all enhancements and just use existing code
|
||||
|
||||
---
|
||||
|
||||
**Apologies for the initial incorrect audit.** The good news is the code is in much better shape than I thought!
|
||||
|
||||
---
|
||||
|
||||
**Files to Review**:
|
||||
- ❌ DELETE: `PLATFORM_AUDIT_FINDINGS.md` (incorrect)
|
||||
- ✅ READ: This file (CORRECTED_AUDIT_SUMMARY.md)
|
||||
- ✅ KEEP: `CROSS_PLATFORM_PLAN.md` (still valid, just less work needed)
|
||||
@@ -1,311 +0,0 @@
|
||||
# Cross-Platform Launcher Implementation Plan
|
||||
|
||||
## Executive Summary
|
||||
|
||||
Transform the launcher from cPanel-only to fully cross-platform supporting:
|
||||
- **Control Panels**: cPanel, Plesk, InterWorx
|
||||
- **Standalone Systems**: Debian, Ubuntu, AlmaLinux, Rocky Linux, RHEL, CentOS
|
||||
|
||||
## Current State Analysis
|
||||
|
||||
### What Works ✅
|
||||
1. **lib/system-detect.sh** - Already detects all platforms correctly
|
||||
2. **lib/domain-discovery.sh** - Has unified functions for cPanel/Plesk/InterWorx
|
||||
3. **lib/plesk-helpers.sh** - 31 Plesk-specific helper functions ready
|
||||
4. **lib/user-manager.sh** - Already has Plesk/InterWorx support for user/database queries
|
||||
5. **lib/common-functions.sh** - Platform-agnostic utility functions
|
||||
|
||||
### What's Broken ❌
|
||||
1. **lib/reference-db.sh** - Hardcoded cPanel dependencies in 4 locations:
|
||||
- Line 255, 265: Uses `/var/cpanel/userdata` for domain configs
|
||||
- Line 370, 390: Uses `/etc/trueuserdomains` for domain ownership
|
||||
2. **build_domains_section()** - 100% cPanel-specific (parses cPanel userdata files)
|
||||
3. **build_wordpress_section()** - Assumes `/home/username/` directory structure
|
||||
|
||||
## Platform-Specific Characteristics
|
||||
|
||||
### Control Panel Systems
|
||||
|
||||
#### cPanel
|
||||
- **Users**: `/var/cpanel/users/`
|
||||
- **Domains**: `/etc/userdomains`, `/etc/trueuserdomains`
|
||||
- **Config**: `/var/cpanel/userdata/{user}/{domain}`
|
||||
- **Home**: `/home/{user}/`
|
||||
- **Logs**: `/var/log/apache2/domlogs/`
|
||||
- **Detection**: `/usr/local/cpanel/version`
|
||||
|
||||
#### Plesk
|
||||
- **Users**: MySQL query to `psa.sys_users`
|
||||
- **Domains**: `plesk bin site --list` or MySQL `psa.domains`
|
||||
- **Config**: `/var/www/vhosts/{domain}/conf/`
|
||||
- **Home**: `/var/www/vhosts/{domain}/`
|
||||
- **Logs**: `/var/www/vhosts/system/{domain}/logs/`
|
||||
- **Detection**: `/usr/local/psa/version`
|
||||
|
||||
#### InterWorx
|
||||
- **Users**: `/home/interworx/var/`
|
||||
- **Domains**: `~iworx/bin/listaccounts.pex`
|
||||
- **Config**: `/home/{user}/var/{domain}/`
|
||||
- **Home**: `/chroot/home/{user}/`
|
||||
- **Logs**: `/home/{user}/var/{domain}/logs/`
|
||||
- **Detection**: `/usr/local/interworx/bin/status.pex`
|
||||
|
||||
### Standalone Systems (No Control Panel)
|
||||
|
||||
#### Common Characteristics
|
||||
- **Users**: Standard `/etc/passwd` (UID >= 1000)
|
||||
- **Domains**: Detect from:
|
||||
- Apache/Nginx vhosts: `/etc/apache2/sites-enabled/`, `/etc/nginx/sites-enabled/`
|
||||
- `/etc/hosts` entries
|
||||
- DNS records (if available)
|
||||
- **Home**: `/home/{user}/` or `/var/www/`
|
||||
- **Logs**: `/var/log/apache2/`, `/var/log/nginx/`
|
||||
- **Web roots**: `/var/www/html/`, `/var/www/{domain}/`, `/usr/share/nginx/html/`
|
||||
|
||||
#### Debian/Ubuntu Specific
|
||||
- Apache config: `/etc/apache2/sites-available/`
|
||||
- Nginx config: `/etc/nginx/sites-available/`
|
||||
- Default web root: `/var/www/html/`
|
||||
- Package manager: `apt`
|
||||
|
||||
#### RHEL/AlmaLinux/Rocky/CentOS Specific
|
||||
- Apache config: `/etc/httpd/conf.d/`
|
||||
- Nginx config: `/etc/nginx/conf.d/`
|
||||
- Default web root: `/var/www/html/` or `/usr/share/nginx/html/`
|
||||
- Package manager: `dnf` or `yum`
|
||||
|
||||
## Implementation Strategy
|
||||
|
||||
### Phase 1: Refactor build_domains_section() 🎯 PRIORITY
|
||||
|
||||
**Current Issue**: Entirely cPanel-specific, parses userdata files
|
||||
|
||||
**Solution**: Create platform-specific domain discovery logic
|
||||
|
||||
```bash
|
||||
build_domains_section() {
|
||||
echo "[DOMAINS]" >> "$SYSREF_DB"
|
||||
|
||||
case "$SYS_CONTROL_PANEL" in
|
||||
cpanel)
|
||||
build_domains_cpanel
|
||||
;;
|
||||
plesk)
|
||||
build_domains_plesk
|
||||
;;
|
||||
interworx)
|
||||
build_domains_interworx
|
||||
;;
|
||||
*)
|
||||
build_domains_standalone
|
||||
;;
|
||||
esac
|
||||
|
||||
finish_progress
|
||||
echo "" >> "$SYSREF_DB"
|
||||
}
|
||||
```
|
||||
|
||||
**Sub-functions to create**:
|
||||
1. `build_domains_cpanel()` - Keep existing logic
|
||||
2. `build_domains_plesk()` - Use plesk_list_domains + plesk_get_* functions
|
||||
3. `build_domains_interworx()` - Use InterWorx CLI tools
|
||||
4. `build_domains_standalone()` - Parse Apache/Nginx vhosts
|
||||
|
||||
### Phase 2: Refactor build_wordpress_section()
|
||||
|
||||
**Current Issue**: Assumes `/home/username/` paths, uses cPanel-specific logic
|
||||
|
||||
**Solution**: Use $SYS_USER_HOME_BASE and panel-agnostic path parsing
|
||||
|
||||
```bash
|
||||
build_wordpress_section() {
|
||||
echo "[WORDPRESS]" >> "$SYSREF_DB"
|
||||
|
||||
# Use panel-agnostic search paths
|
||||
case "$SYS_CONTROL_PANEL" in
|
||||
cpanel)
|
||||
search_paths="/home/*/public_html"
|
||||
;;
|
||||
plesk)
|
||||
search_paths="/var/www/vhosts/*/httpdocs /var/www/vhosts/*/httpsdocs"
|
||||
;;
|
||||
interworx)
|
||||
search_paths="/chroot/home/*/var/*/html"
|
||||
;;
|
||||
*)
|
||||
search_paths="/var/www/*/public_html /var/www/html /home/*/public_html"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Find wp-config.php in all search paths
|
||||
# Extract domain/owner using get_domain_owner() and path analysis
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 3: Add Standalone Web Server Detection
|
||||
|
||||
**New functions needed in system-detect.sh**:
|
||||
|
||||
```bash
|
||||
detect_vhosts_standalone() {
|
||||
# Scan Apache sites-enabled
|
||||
if [ -d /etc/apache2/sites-enabled ]; then
|
||||
# Parse ServerName/ServerAlias from .conf files
|
||||
fi
|
||||
|
||||
# Scan Nginx sites-enabled
|
||||
if [ -d /etc/nginx/sites-enabled ]; then
|
||||
# Parse server_name from .conf files
|
||||
fi
|
||||
|
||||
# Parse /etc/httpd/conf.d/ for RHEL-based
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 4: Enhance Domain Discovery for Standalone
|
||||
|
||||
**New helper library**: `lib/standalone-helpers.sh`
|
||||
|
||||
Functions needed:
|
||||
- `standalone_list_domains()` - Parse vhost configs
|
||||
- `standalone_get_docroot()` - Extract DocumentRoot/root directive
|
||||
- `standalone_get_logdir()` - Extract log paths from vhost configs
|
||||
- `standalone_get_owner()` - Use `stat -c "%U"` on document root
|
||||
- `standalone_list_users()` - Filter /etc/passwd for UID >= 1000
|
||||
|
||||
### Phase 5: Universal WordPress Detection
|
||||
|
||||
**Current limitations**: Only searches `/home/` paths
|
||||
|
||||
**Enhanced approach**:
|
||||
```bash
|
||||
# Multi-path WordPress scanner
|
||||
find_wordpress_installations() {
|
||||
local search_paths=""
|
||||
|
||||
case "$SYS_CONTROL_PANEL" in
|
||||
cpanel) search_paths="/home" ;;
|
||||
plesk) search_paths="/var/www/vhosts" ;;
|
||||
interworx) search_paths="/chroot/home" ;;
|
||||
*)
|
||||
# Standalone: check common webroot locations
|
||||
search_paths="/var/www /home /usr/share/nginx"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Find all wp-config.php files
|
||||
find $search_paths -name wp-config.php -type f 2>/dev/null
|
||||
}
|
||||
```
|
||||
|
||||
## Implementation Phases with Testing
|
||||
|
||||
### Phase 1: Reference Database Refactor (Week 1)
|
||||
- [ ] Create `build_domains_cpanel()` (extract existing code)
|
||||
- [ ] Create `build_domains_plesk()` (use plesk-helpers)
|
||||
- [ ] Create `build_domains_interworx()` (use interworx-helpers if exists)
|
||||
- [ ] Create `build_domains_standalone()` (new vhost parser)
|
||||
- [ ] Test on cPanel server (verify no regression)
|
||||
- [ ] Test on Plesk server (verify domain discovery)
|
||||
|
||||
### Phase 2: WordPress Detection (Week 1)
|
||||
- [ ] Refactor `build_wordpress_section()` with multi-path search
|
||||
- [ ] Add panel-specific path extraction logic
|
||||
- [ ] Test on cPanel (verify existing WordPress detected)
|
||||
- [ ] Test on Plesk (verify WordPress detected)
|
||||
- [ ] Test on standalone Ubuntu (verify WordPress detected)
|
||||
|
||||
### Phase 3: Standalone Helpers (Week 2)
|
||||
- [ ] Create `lib/standalone-helpers.sh`
|
||||
- [ ] Implement vhost parsing (Apache)
|
||||
- [ ] Implement vhost parsing (Nginx)
|
||||
- [ ] Implement user discovery (UID filtering)
|
||||
- [ ] Add exports to domain-discovery.sh
|
||||
- [ ] Test on Debian/Ubuntu with Apache
|
||||
- [ ] Test on AlmaLinux with Nginx
|
||||
|
||||
### Phase 4: Integration Testing (Week 2)
|
||||
- [ ] Test full launcher on cPanel server
|
||||
- [ ] Test full launcher on Plesk server
|
||||
- [ ] Test full launcher on InterWorx server (if available)
|
||||
- [ ] Test full launcher on Ubuntu standalone
|
||||
- [ ] Test full launcher on AlmaLinux standalone
|
||||
- [ ] Test full launcher on Debian standalone
|
||||
|
||||
### Phase 5: Documentation (Week 3)
|
||||
- [ ] Update README with platform support matrix
|
||||
- [ ] Document standalone system requirements
|
||||
- [ ] Create troubleshooting guide for each platform
|
||||
- [ ] Add platform-specific installation notes
|
||||
|
||||
## Database Format Compatibility
|
||||
|
||||
The current `.sysref` format is already platform-agnostic:
|
||||
|
||||
```
|
||||
DOMAIN|domain|owner|docroot|logdir|access_log|php_version|is_primary|type|aliases|http|https|status
|
||||
```
|
||||
|
||||
**All fields map universally**:
|
||||
- `domain` - Same on all platforms
|
||||
- `owner` - Username from any system
|
||||
- `docroot` - Absolute path (any location)
|
||||
- `logdir` - Absolute path (any location)
|
||||
- `access_log` - Absolute path (any location)
|
||||
- `php_version` - Detected version string
|
||||
- `is_primary` - yes/no (determined by logic)
|
||||
- `type` - primary/addon/alias/subdomain (universal concepts)
|
||||
- `aliases` - Space-separated list
|
||||
- `http/https/status` - HTTP status codes (universal)
|
||||
|
||||
**No format changes needed** - only the methods to populate these fields change per platform.
|
||||
|
||||
## Risk Mitigation
|
||||
|
||||
### Backward Compatibility
|
||||
- ✅ Keep all existing cPanel code paths functional
|
||||
- ✅ Use case statements for platform-specific logic
|
||||
- ✅ Default to cPanel behavior if platform unknown
|
||||
- ✅ Existing cPanel installations continue working without changes
|
||||
|
||||
### Testing Strategy
|
||||
- ✅ Test on live cPanel server FIRST (prevent regressions)
|
||||
- ✅ Test on Plesk server SECOND (validate new platform)
|
||||
- ✅ Test on standalone systems THIRD (validate fallback logic)
|
||||
- ✅ Keep old commits in git history for easy revert
|
||||
|
||||
### Fallback Mechanisms
|
||||
- ✅ If vhost parsing fails → scan /var/www for directories
|
||||
- ✅ If user detection fails → show "unknown" owner
|
||||
- ✅ If WordPress detection fails → skip silently (don't crash)
|
||||
- ✅ If domain discovery returns empty → try manual directory scan
|
||||
|
||||
## Success Criteria
|
||||
|
||||
### Minimum Viable Product (MVP)
|
||||
- [x] cPanel: 100% functional (already working)
|
||||
- [ ] Plesk: Domain/user/database discovery working
|
||||
- [ ] Standalone: Basic domain/WordPress detection working
|
||||
|
||||
### Full Feature Parity
|
||||
- [ ] All platforms detect domains correctly
|
||||
- [ ] All platforms detect WordPress installations
|
||||
- [ ] All platforms show correct ownership
|
||||
- [ ] All platforms display accurate statistics
|
||||
- [ ] All modules work on all platforms (or gracefully skip)
|
||||
|
||||
## Next Immediate Steps
|
||||
|
||||
1. **Create standalone-helpers.sh** - New helper library for non-panel systems
|
||||
2. **Refactor build_domains_section()** - Split into platform-specific functions
|
||||
3. **Test on cPanel** - Ensure no regressions
|
||||
4. **Test on Plesk** - Validate Plesk domain discovery
|
||||
5. **Document platform support** - Update README with compatibility matrix
|
||||
|
||||
---
|
||||
|
||||
**Estimated Timeline**: 2-3 weeks for full cross-platform support
|
||||
**Priority**: High - Blocking Plesk deployment
|
||||
**Risk**: Medium - Potential for breaking cPanel if not careful
|
||||
**Complexity**: Medium-High - Requires understanding 4+ different platforms
|
||||
@@ -1,366 +0,0 @@
|
||||
# FINAL AUDIT - QUAD-CHECKED AND VERIFIED
|
||||
|
||||
## Date: 2025-12-23
|
||||
## Status: ✅ QUADRUPLE-CHECKED BY READING ACTUAL CODE
|
||||
|
||||
---
|
||||
|
||||
## EXECUTIVE SUMMARY
|
||||
|
||||
After quad-checking by reading the ENTIRE source code (not using grep), here's the definitive truth:
|
||||
|
||||
**The toolkit ALREADY HAS multi-platform support** - it's just not optimal for Plesk.
|
||||
|
||||
---
|
||||
|
||||
## VERIFIED FACTS
|
||||
|
||||
### ✅ What DEFINITELY Works Right Now:
|
||||
|
||||
1. **`build_domains_section()` HAS fallback for non-cPanel** (lines 90-116)
|
||||
```bash
|
||||
else
|
||||
# Fallback for non-cPanel or if userdata not available
|
||||
local primary_domain=$(get_user_domains "$user" | head -1)
|
||||
local all_domains=$(get_user_domains "$user")
|
||||
# ... processes domains using panel-agnostic functions
|
||||
```
|
||||
- On cPanel: Uses optimized userdata parsing (lines 24-89)
|
||||
- On Plesk/standalone: Uses `get_user_domains()` which calls panel-specific helpers
|
||||
|
||||
2. **`list_all_users()` supports all platforms**:
|
||||
- cPanel: `ls -1 /var/cpanel/users/`
|
||||
- Plesk: `plesk_exec bin user --list` (with fallback)
|
||||
- InterWorx: `ls -1 /chroot/home/`
|
||||
- Standalone: `ls -1 /home/`
|
||||
|
||||
3. **`get_user_domains()` supports all platforms**:
|
||||
- cPanel: Reads `/etc/trueuserdomains`
|
||||
- Plesk: Calls `get_plesk_user_domains()`
|
||||
- InterWorx: Calls `get_interworx_user_domains()`
|
||||
- Standalone: Returns empty (needs enhancement)
|
||||
|
||||
4. **`domain-discovery.sh` has 13 functions, ALL have platform cases**:
|
||||
- list_all_domains ✅
|
||||
- get_domain_docroot ✅
|
||||
- get_domain_logdir ✅
|
||||
- get_domain_access_log ✅
|
||||
- get_domain_error_log ✅
|
||||
- get_all_log_files ✅
|
||||
- get_domain_owner ✅
|
||||
- list_all_users ✅
|
||||
- get_domain_fpm_socket ✅
|
||||
- get_all_fpm_sockets ✅
|
||||
- get_domain_databases ✅
|
||||
- domain_exists ✅
|
||||
- list_domains_with_docroots ✅
|
||||
|
||||
### ❌ What Needs Work:
|
||||
|
||||
#### ISSUE #1: WordPress Path Parsing (MEDIUM)
|
||||
**Location**: lib/reference-db.sh lines 411, 414
|
||||
|
||||
**Problem**:
|
||||
```bash
|
||||
# Line 411: Assumes field 3 is username
|
||||
local username=$(echo "$wp_dir" | cut -d'/' -f3)
|
||||
|
||||
# Line 414: Hardcodes /home/
|
||||
local path_after_home=$(echo "$wp_dir" | sed "s|^/home/$username/||")
|
||||
```
|
||||
|
||||
**Impact on Plesk**:
|
||||
- `/var/www/vhosts/domain.com/httpdocs/wp-config.php`
|
||||
- Field 3 would be "vhosts" not username ❌
|
||||
- `sed "s|^/home/..."` won't match ❌
|
||||
|
||||
**HOWEVER** - Line 36 tries to fix this:
|
||||
```bash
|
||||
# Try to get site URL from wp-config defines
|
||||
local site_url=$(grep -E "WP_SITEURL|WP_HOME" "$wp_config" ...)
|
||||
if [ -n "$site_url" ]; then
|
||||
domain="$site_url" # ← This works on any platform!
|
||||
fi
|
||||
```
|
||||
|
||||
**So WordPress detection WORKS but gets wrong username initially, then corrects the domain from WP_SITEURL.**
|
||||
|
||||
**Fix Needed**: Add panel-specific path parsing to get correct username from the start.
|
||||
|
||||
---
|
||||
|
||||
#### ISSUE #2: cPanel-Only File Checks Not Wrapped (LOW)
|
||||
**Location**: lib/reference-db.sh lines 122-153
|
||||
|
||||
**Problem**:
|
||||
```bash
|
||||
# Check /etc/localdomains (cPanel local domains not yet added)
|
||||
if [ -f "/etc/localdomains" ]; then
|
||||
# ... reads cPanel-only files
|
||||
fi
|
||||
```
|
||||
|
||||
**Impact**: NONE - the `if [ -f "..." ]` check means it skips silently on non-cPanel
|
||||
|
||||
**Fix Needed**: Wrap in `if [ "$SYS_CONTROL_PANEL" = "cpanel" ]` for code cleanliness only
|
||||
|
||||
---
|
||||
|
||||
#### ISSUE #3: Plesk Gets Less Detailed Domain Data (MEDIUM)
|
||||
**Location**: lib/reference-db.sh lines 90-116 (fallback path)
|
||||
|
||||
**cPanel Path** (lines 24-89) provides:
|
||||
- Document root ✅
|
||||
- Log path ✅
|
||||
- PHP version ✅
|
||||
- Server aliases ✅
|
||||
- Domain type (primary/addon/subdomain/alias) ✅
|
||||
- HTTP/HTTPS status codes ✅
|
||||
|
||||
**Plesk Fallback Path** (lines 90-116) provides:
|
||||
- Domain name ✅
|
||||
- Owner ✅
|
||||
- Log path (generic) ✅
|
||||
- Primary flag ✅
|
||||
- HTTP/HTTPS status codes ✅
|
||||
- Document root ❌ (empty)
|
||||
- PHP version ❌ (empty)
|
||||
- Server aliases ❌ (empty)
|
||||
- Domain type ❌ (shows "local" instead of primary/addon)
|
||||
|
||||
**Why**: The fallback path doesn't call `get_domain_docroot()`, `get_domain_php_version()`, etc.
|
||||
|
||||
**Fix Needed**: Create `build_domains_plesk()` that calls Plesk-specific functions to get full data
|
||||
|
||||
---
|
||||
|
||||
#### ISSUE #4: Standalone get_user_domains() Returns Empty
|
||||
**Location**: lib/user-manager.sh
|
||||
|
||||
```bash
|
||||
get_user_domains() {
|
||||
case "$SYS_CONTROL_PANEL" in
|
||||
cpanel) get_cpanel_user_domains "$username" ;;
|
||||
plesk) get_plesk_user_domains "$username" ;;
|
||||
interworx) get_interworx_user_domains "$username" ;;
|
||||
*) echo "" ;; # ← Standalone returns NOTHING!
|
||||
esac
|
||||
}
|
||||
```
|
||||
|
||||
**Impact**: On standalone systems, `build_domains_section()` fallback path gets empty domains list
|
||||
|
||||
**BUT** - `list_all_domains()` DOES work on standalone:
|
||||
```bash
|
||||
list_all_domains() {
|
||||
case "$SYS_CONTROL_PANEL" in
|
||||
*)
|
||||
# Standalone: scan common web directories
|
||||
find /var/www/html/*/public_html -maxdepth 0 -type d 2>/dev/null | awk -F'/' '{print $(NF-1)}'
|
||||
find /home/*/public_html -maxdepth 0 -type d 2>/dev/null | awk -F'/' '{print $(NF-1)}'
|
||||
# ...
|
||||
esac
|
||||
}
|
||||
```
|
||||
|
||||
**So standalone CAN find domains, but the reference-db.sh fallback path doesn't use the right function!**
|
||||
|
||||
**Fix Needed**: `build_domains_standalone()` function that uses `list_all_domains()` instead of looping through users
|
||||
|
||||
---
|
||||
|
||||
## THE REAL SITUATION
|
||||
|
||||
### On cPanel:
|
||||
- ✅ **FULLY WORKING** - Rich detailed domain data
|
||||
|
||||
### On Plesk:
|
||||
- ⚠️ **PARTIALLY WORKING** - Domains detected, but missing details
|
||||
- ✅ Users detected via `plesk bin user --list`
|
||||
- ✅ Domains detected via `get_plesk_user_domains()`
|
||||
- ❌ Missing: docroot, PHP version, aliases
|
||||
- ⚠️ WordPress detected but wrong username
|
||||
|
||||
### On Standalone:
|
||||
- ❌ **BROKEN** - `get_user_domains()` returns empty
|
||||
- ✅ BUT `list_all_domains()` WORKS and finds domains!
|
||||
- Problem: `build_domains_section()` doesn't use `list_all_domains()` directly
|
||||
|
||||
---
|
||||
|
||||
## CORRECTED IMPLEMENTATION PLAN
|
||||
|
||||
### Priority 1: Plesk Enhancement (4 hours) 🎯
|
||||
|
||||
**Goal**: Make Plesk get same quality data as cPanel
|
||||
|
||||
**Task 1: Create build_domains_plesk()** (3 hours)
|
||||
```bash
|
||||
build_domains_plesk() {
|
||||
local all_domains=$(list_all_domains) # Uses plesk bin site --list
|
||||
|
||||
for domain in $all_domains; do
|
||||
local owner=$(get_domain_owner "$domain")
|
||||
local docroot=$(get_domain_docroot "$domain") # Calls plesk_get_docroot()
|
||||
local logdir=$(get_domain_logdir "$domain")
|
||||
local access_log=$(get_domain_access_log "$domain")
|
||||
local php_version=$(plesk_get_php_version "$domain")
|
||||
local ssl_status=$(plesk_get_ssl_status "$domain")
|
||||
|
||||
echo "DOMAIN|$domain|$owner|$docroot|$logdir|$access_log|$php_version|..." >> "$SYSREF_DB"
|
||||
done
|
||||
}
|
||||
```
|
||||
|
||||
**Task 2: Update build_domains_section()** (30 min)
|
||||
```bash
|
||||
build_domains_section() {
|
||||
echo "[DOMAINS]" >> "$SYSREF_DB"
|
||||
|
||||
case "$SYS_CONTROL_PANEL" in
|
||||
cpanel)
|
||||
build_domains_cpanel # Extract existing lines 10-153 into this function
|
||||
;;
|
||||
plesk)
|
||||
build_domains_plesk # New function
|
||||
;;
|
||||
interworx)
|
||||
build_domains_interworx # Future enhancement
|
||||
;;
|
||||
*)
|
||||
build_domains_standalone # See Priority 2
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "" >> "$SYSREF_DB"
|
||||
}
|
||||
```
|
||||
|
||||
**Task 3: Fix WordPress path parsing** (30 min)
|
||||
```bash
|
||||
# Extract username based on panel
|
||||
case "$SYS_CONTROL_PANEL" in
|
||||
cpanel)
|
||||
username=$(echo "$wp_dir" | cut -d'/' -f3) # /home/user/
|
||||
;;
|
||||
plesk)
|
||||
domain=$(echo "$wp_dir" | cut -d'/' -f5) # /var/www/vhosts/domain.com/
|
||||
username=$(plesk_get_owner "$domain")
|
||||
;;
|
||||
interworx)
|
||||
username=$(echo "$wp_dir" | cut -d'/' -f4) # /chroot/home/user/
|
||||
;;
|
||||
*)
|
||||
username=$(stat -c "%U" "$wp_dir" 2>/dev/null)
|
||||
;;
|
||||
esac
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Priority 2: Standalone Support (6 hours)
|
||||
|
||||
**Goal**: Make standalone systems work properly
|
||||
|
||||
**Task 1: Create build_domains_standalone()** (2 hours)
|
||||
```bash
|
||||
build_domains_standalone() {
|
||||
local all_domains=$(list_all_domains) # Already scans directories!
|
||||
|
||||
for domain in $all_domains; do
|
||||
local docroot=$(get_domain_docroot "$domain")
|
||||
local owner=$(get_domain_owner "$domain") # Uses stat
|
||||
local logdir=$(get_domain_logdir "$domain")
|
||||
|
||||
echo "DOMAIN|$domain|$owner|$docroot|$logdir|..." >> "$SYSREF_DB"
|
||||
done
|
||||
}
|
||||
```
|
||||
|
||||
**Task 2: Add vhost parsing (optional enhancement)** (4 hours)
|
||||
- Parse Apache/Nginx configs for ServerName
|
||||
- Extract DocumentRoot from vhosts
|
||||
- Get accurate log paths from configs
|
||||
|
||||
---
|
||||
|
||||
### Priority 3: Wrap cPanel File Checks (15 minutes)
|
||||
|
||||
```bash
|
||||
# Wrap lines 122-153
|
||||
if [ "$SYS_CONTROL_PANEL" = "cpanel" ]; then
|
||||
# Check /etc/localdomains
|
||||
if [ -f "/etc/localdomains" ]; then
|
||||
# ...
|
||||
fi
|
||||
|
||||
# Check /etc/remotedomains
|
||||
if [ -f "/etc/remotedomains" ]; then
|
||||
# ...
|
||||
fi
|
||||
fi
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## TESTING PLAN
|
||||
|
||||
### Test 1: Plesk Server (FIRST!)
|
||||
1. Pull latest code
|
||||
2. Run `bash launcher.sh`
|
||||
3. Check counts: "X users, Y domains, Z databases"
|
||||
4. View `.sysref` file - verify domains listed
|
||||
5. Check if WordPress detected
|
||||
|
||||
**Expected**:
|
||||
- ✅ Domains show up
|
||||
- ⚠️ Missing docroot/PHP version (until Priority 1 complete)
|
||||
- ⚠️ WordPress shows wrong username (until Task 3 complete)
|
||||
|
||||
### Test 2: After Priority 1
|
||||
1. Implement `build_domains_plesk()`
|
||||
2. Test on Plesk server
|
||||
3. Verify rich domain data in `.sysref`
|
||||
|
||||
**Expected**:
|
||||
- ✅ Domains with docroot, PHP version, log paths
|
||||
- ✅ WordPress with correct username/domain
|
||||
|
||||
### Test 3: Standalone Ubuntu
|
||||
1. Implement `build_domains_standalone()`
|
||||
2. Test on standalone server
|
||||
3. Verify domains detected from directory scanning
|
||||
|
||||
---
|
||||
|
||||
## FINAL VERDICT
|
||||
|
||||
| Platform | Current State | After Priority 1 | After Priority 2 |
|
||||
|----------|--------------|------------------|------------------|
|
||||
| cPanel | ✅ Excellent | ✅ Excellent | ✅ Excellent |
|
||||
| Plesk | ⚠️ Basic | ✅ Excellent | ✅ Excellent |
|
||||
| InterWorx | ⚠️ Basic | ⚠️ Basic | ✅ Good |
|
||||
| Standalone | ❌ Broken | ❌ Broken | ✅ Good |
|
||||
|
||||
**BOTTOM LINE**:
|
||||
- Plesk: 1 day work to reach excellence
|
||||
- Standalone: 2 days work to reach good
|
||||
- **Total: 3 days to full multi-platform support**
|
||||
|
||||
---
|
||||
|
||||
## FILES NEEDING CHANGES
|
||||
|
||||
| File | Changes Needed | Lines | Priority |
|
||||
|------|---------------|-------|----------|
|
||||
| lib/reference-db.sh | Extract build_domains_cpanel() | 244-399 | P1 |
|
||||
| lib/reference-db.sh | Create build_domains_plesk() | NEW | P1 |
|
||||
| lib/reference-db.sh | Fix WordPress path parsing | 411, 414 | P1 |
|
||||
| lib/reference-db.sh | Wrap cPanel file checks | 122-153 | P3 |
|
||||
| lib/reference-db.sh | Create build_domains_standalone() | NEW | P2 |
|
||||
|
||||
---
|
||||
|
||||
**VERIFIED**: All findings confirmed by reading actual source code, not grep output.
|
||||
|
||||
**RECOMMENDATION**: Start with Plesk enhancements (Priority 1) - only 4 hours of work!
|
||||
@@ -1,472 +0,0 @@
|
||||
# Complete Platform Audit Findings
|
||||
|
||||
## Date: 2025-12-23
|
||||
## Auditor: Claude Code (Comprehensive Analysis)
|
||||
|
||||
---
|
||||
|
||||
## EXECUTIVE SUMMARY
|
||||
|
||||
### Critical Issues Found: 8
|
||||
### Medium Issues Found: 3
|
||||
### Low Issues Found: 2
|
||||
|
||||
**Recommendation**: The plan needs significant updates to address newly discovered issues.
|
||||
|
||||
---
|
||||
|
||||
## DETAILED FINDINGS
|
||||
|
||||
### 1. lib/reference-db.sh - CRITICAL ISSUES
|
||||
|
||||
#### Issue #1: build_domains_section() - Lines 255, 265
|
||||
**Severity**: CRITICAL
|
||||
**Impact**: Complete failure on non-cPanel systems
|
||||
**Location**: Lines 255, 265
|
||||
|
||||
```bash
|
||||
local userdata_dir="${SYS_CPANEL_USERDATA_DIR:-/var/cpanel/userdata}/${user}"
|
||||
```
|
||||
|
||||
**Problem**:
|
||||
- Hardcodes `/var/cpanel/userdata` path
|
||||
- Primary logic branch assumes cPanel userdata files exist
|
||||
- 100% cPanel-specific domain configuration parsing
|
||||
|
||||
**Affected Platforms**: Plesk, InterWorx, Standalone
|
||||
**Plan Coverage**: ✅ COVERED in Phase 1
|
||||
|
||||
---
|
||||
|
||||
#### Issue #2: build_domains_section() - Lines 364-382
|
||||
**Severity**: CRITICAL
|
||||
**Impact**: Code will fail on non-cPanel systems
|
||||
**Location**: Lines 364-396
|
||||
|
||||
```bash
|
||||
# Check /etc/localdomains (cPanel local domains not yet added)
|
||||
if [ -f "/etc/localdomains" ]; then
|
||||
# ... reads /etc/localdomains and /etc/trueuserdomains
|
||||
fi
|
||||
|
||||
# Check /etc/remotedomains (cPanel remote MX domains)
|
||||
if [ -f "/etc/remotedomains" ]; then
|
||||
# ... reads /etc/remotedomains and /etc/trueuserdomains
|
||||
fi
|
||||
```
|
||||
|
||||
**Problem**:
|
||||
- `/etc/localdomains` is cPanel-only (doesn't exist on Plesk/standalone)
|
||||
- `/etc/remotedomains` is cPanel-only
|
||||
- `/etc/trueuserdomains` is cPanel-only (lines 370, 390)
|
||||
- These files are checked OUTSIDE the cPanel conditional block
|
||||
|
||||
**Affected Platforms**: Plesk, InterWorx, Standalone
|
||||
**Plan Coverage**: ❌ **NOT COVERED** - Plan missed this entirely!
|
||||
|
||||
**Fix Needed**:
|
||||
```bash
|
||||
# Wrap in cPanel-only conditional
|
||||
if [ "$SYS_CONTROL_PANEL" = "cpanel" ]; then
|
||||
# Check /etc/localdomains
|
||||
if [ -f "/etc/localdomains" ]; then
|
||||
# ...
|
||||
fi
|
||||
|
||||
# Check /etc/remotedomains
|
||||
if [ -f "/etc/remotedomains" ]; then
|
||||
# ...
|
||||
fi
|
||||
fi
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Issue #3: build_wordpress_section() - Lines 411, 414
|
||||
**Severity**: CRITICAL
|
||||
**Impact**: WordPress not detected on Plesk/standalone systems
|
||||
**Location**: Lines 411, 414
|
||||
|
||||
```bash
|
||||
# Line 411: Extract username from path (/home/username/...)
|
||||
local username=$(echo "$wp_dir" | cut -d'/' -f3)
|
||||
|
||||
# Line 414: Try to get domain from path
|
||||
local path_after_home=$(echo "$wp_dir" | sed "s|^/home/$username/||")
|
||||
```
|
||||
|
||||
**Problem**:
|
||||
- Hardcodes `/home/` assumption
|
||||
- Field 3 (`cut -d'/' -f3`) only works for `/home/username/` paths
|
||||
- Plesk uses `/var/www/vhosts/domain.com/` (username would be "www")
|
||||
- Standalone could use `/var/www/` or other paths
|
||||
|
||||
**Affected Platforms**: Plesk, InterWorx, Standalone
|
||||
**Plan Coverage**: ✅ COVERED in Phase 2 (but needs more detail)
|
||||
|
||||
**Fix Needed**: Panel-specific path parsing logic (see Phase 2 enhancement below)
|
||||
|
||||
---
|
||||
|
||||
#### Issue #4: build_wordpress_section() - Lines 418-428
|
||||
**Severity**: MEDIUM
|
||||
**Impact**: Domain detection fails for non-cPanel WordPress
|
||||
**Location**: Lines 418-428
|
||||
|
||||
```bash
|
||||
if [[ "$path_after_home" == public_html ]]; then
|
||||
# This is the primary domain - get it from user info
|
||||
domain=$(grep "USER|${username}|" "$SYSREF_DB" 2>/dev/null | cut -d'|' -f3 || true)
|
||||
elif [[ "$path_after_home" =~ ^public_html/(.+) ]]; then
|
||||
# Could be subdomain or subdirectory
|
||||
```
|
||||
|
||||
**Problem**:
|
||||
- Assumes `public_html` directory structure (cPanel-specific)
|
||||
- Plesk uses `httpdocs` or `httpsdocs`
|
||||
- Standalone uses `public_html`, `html`, or `www`
|
||||
|
||||
**Affected Platforms**: Plesk, InterWorx, Standalone
|
||||
**Plan Coverage**: ✅ COVERED in Phase 2
|
||||
|
||||
---
|
||||
|
||||
### 2. lib/domain-discovery.sh - CRITICAL GAPS
|
||||
|
||||
#### Issue #5: get_domain_docroot() - Missing Plesk Support
|
||||
**Severity**: CRITICAL
|
||||
**Impact**: Cannot build domains section on Plesk
|
||||
**Location**: lib/domain-discovery.sh (function missing Plesk case)
|
||||
|
||||
**Problem**:
|
||||
- `get_domain_docroot()` has NO Plesk case statement
|
||||
- This function is used by reference-db.sh build_domains_section()
|
||||
- Without it, domain document roots cannot be determined on Plesk
|
||||
|
||||
**Affected Platforms**: Plesk
|
||||
**Plan Coverage**: ❌ **NOT COVERED** - Plan assumed this function was complete!
|
||||
|
||||
**Fix Needed**: Add Plesk case to call `plesk_get_docroot()`
|
||||
|
||||
---
|
||||
|
||||
#### Issue #6: list_domains_with_docroots() - Missing Plesk Support
|
||||
**Severity**: LOW
|
||||
**Impact**: Minor - function rarely used
|
||||
**Location**: lib/domain-discovery.sh
|
||||
|
||||
**Problem**:
|
||||
- Missing Plesk case statement
|
||||
- Function is used by some modules but not by launcher
|
||||
|
||||
**Affected Platforms**: Plesk
|
||||
**Plan Coverage**: ❌ NOT COVERED
|
||||
|
||||
---
|
||||
|
||||
### 3. lib/domain-discovery.sh - MISSING STANDALONE SUPPORT
|
||||
|
||||
#### Issue #7: ALL Functions Missing Standalone Cases
|
||||
**Severity**: CRITICAL
|
||||
**Impact**: Complete failure on standalone systems
|
||||
**Location**: Every function in domain-discovery.sh
|
||||
|
||||
**Problem**:
|
||||
All 13 functions have `cpanel`, `plesk`, `interworx` cases, but NO standalone fallback:
|
||||
- list_all_domains
|
||||
- get_domain_docroot
|
||||
- get_domain_logdir
|
||||
- get_domain_access_log
|
||||
- get_domain_error_log
|
||||
- get_all_log_files
|
||||
- get_domain_owner
|
||||
- list_all_users
|
||||
- get_domain_fpm_socket
|
||||
- get_all_fpm_sockets
|
||||
- get_domain_databases
|
||||
- domain_exists
|
||||
- list_domains_with_docroots
|
||||
|
||||
**Current Pattern**:
|
||||
```bash
|
||||
case "$SYS_CONTROL_PANEL" in
|
||||
cpanel) ... ;;
|
||||
plesk) ... ;;
|
||||
interworx) ... ;;
|
||||
*) echo "" ;; # ← Returns empty/fails on standalone!
|
||||
esac
|
||||
```
|
||||
|
||||
**Affected Platforms**: All standalone (Debian, Ubuntu, AlmaLinux, Rocky, RHEL, CentOS)
|
||||
**Plan Coverage**: ✅ COVERED in Phase 3 (lib/standalone-helpers.sh creation)
|
||||
|
||||
**Fix Needed**: Add `*)` fallback cases that:
|
||||
- Parse Apache/Nginx vhosts for domains
|
||||
- Use filesystem scanning for user detection
|
||||
- Use `stat -c "%U"` for ownership
|
||||
- Parse vhost configs for document roots and log paths
|
||||
|
||||
---
|
||||
|
||||
### 4. launcher.sh - MINOR ISSUE
|
||||
|
||||
#### Issue #8: Title Says "cPanel" Only
|
||||
**Severity**: LOW
|
||||
**Impact**: Cosmetic - misleading branding
|
||||
**Location**: Line 41
|
||||
|
||||
```bash
|
||||
echo -e "${CYAN} Complete cPanel/Linux Server Administration Suite${NC}"
|
||||
```
|
||||
|
||||
**Problem**:
|
||||
- Title implies cPanel-only support
|
||||
- Should say "Multi-Platform" or list all supported platforms
|
||||
|
||||
**Affected Platforms**: All
|
||||
**Plan Coverage**: ❌ NOT COVERED (minor cosmetic fix)
|
||||
|
||||
**Fix Needed**:
|
||||
```bash
|
||||
echo -e "${CYAN} Complete Linux Server Administration Suite${NC}"
|
||||
echo -e "${CYAN} Supporting: cPanel, Plesk, InterWorx, Standalone${NC}"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PLATFORM SUPPORT MATRIX (Current State)
|
||||
|
||||
| Component | cPanel | Plesk | InterWorx | Standalone |
|
||||
|-----------|--------|-------|-----------|------------|
|
||||
| **system-detect.sh** | ✅ | ✅ | ✅ | ✅ |
|
||||
| **domain-discovery.sh** | ✅ | ⚠️ 85% | ⚠️ 75% | ❌ 0% |
|
||||
| **user-manager.sh** | ✅ | ✅ | ✅ | ⚠️ Partial |
|
||||
| **reference-db.sh** | ✅ | ❌ | ❌ | ❌ |
|
||||
| **plesk-helpers.sh** | N/A | ✅ | N/A | N/A |
|
||||
| **launcher.sh** | ✅ | ❌ | ❌ | ❌ |
|
||||
|
||||
Legend:
|
||||
- ✅ Fully working
|
||||
- ⚠️ Partially working (% complete)
|
||||
- ❌ Not working / missing
|
||||
|
||||
---
|
||||
|
||||
## UPDATED IMPLEMENTATION PRIORITIES
|
||||
|
||||
### PHASE 1A: Fix Critical Missing Plesk Support (NEW)
|
||||
**Priority**: CRITICAL - MUST DO FIRST
|
||||
|
||||
1. **Add get_domain_docroot() Plesk case**
|
||||
- File: lib/domain-discovery.sh
|
||||
- Add case to call `plesk_get_docroot()`
|
||||
- Required for build_domains_section() to work
|
||||
|
||||
2. **Add list_domains_with_docroots() Plesk case**
|
||||
- File: lib/domain-discovery.sh
|
||||
- Low priority but should be included
|
||||
|
||||
3. **Wrap cPanel-only domain checks**
|
||||
- File: lib/reference-db.sh lines 364-396
|
||||
- Wrap `/etc/localdomains` and `/etc/remotedomains` in cPanel conditional
|
||||
|
||||
### PHASE 1B: Create build_domains_plesk() (FROM ORIGINAL PLAN)
|
||||
**Priority**: CRITICAL
|
||||
|
||||
- Create Plesk-specific domain builder function
|
||||
- Use plesk_list_domains() + plesk_get_*() helpers
|
||||
- Skip HTTP status checks initially (too slow)
|
||||
- Test on Plesk server
|
||||
|
||||
### PHASE 2A: Fix WordPress Path Parsing (ENHANCED)
|
||||
**Priority**: HIGH
|
||||
|
||||
Need panel-specific path parsing:
|
||||
|
||||
```bash
|
||||
case "$SYS_CONTROL_PANEL" in
|
||||
cpanel)
|
||||
# /home/username/public_html
|
||||
username=$(echo "$wp_dir" | cut -d'/' -f3)
|
||||
;;
|
||||
plesk)
|
||||
# /var/www/vhosts/domain.com/httpdocs
|
||||
domain=$(echo "$wp_dir" | cut -d'/' -f5)
|
||||
username=$(plesk_get_owner "$domain")
|
||||
;;
|
||||
interworx)
|
||||
# /chroot/home/user/var/domain.com/html
|
||||
username=$(echo "$wp_dir" | cut -d'/' -f4)
|
||||
;;
|
||||
*)
|
||||
# Standalone: use stat to get owner
|
||||
username=$(stat -c "%U" "$wp_dir" 2>/dev/null)
|
||||
;;
|
||||
esac
|
||||
```
|
||||
|
||||
### PHASE 3: Create Standalone Helpers (FROM ORIGINAL PLAN)
|
||||
**Priority**: HIGH
|
||||
|
||||
Must implement ALL 13 standalone cases in domain-discovery.sh:
|
||||
|
||||
**New file**: lib/standalone-helpers.sh
|
||||
|
||||
Functions needed:
|
||||
```bash
|
||||
standalone_list_domains() # Parse Apache/Nginx vhosts
|
||||
standalone_get_docroot() # Extract DocumentRoot/root
|
||||
standalone_get_logdir() # Extract log directory
|
||||
standalone_get_access_log() # Extract access_log path
|
||||
standalone_get_error_log() # Extract error_log path
|
||||
standalone_get_owner() # Use stat -c "%U"
|
||||
standalone_list_users() # UID >= 1000 from /etc/passwd
|
||||
standalone_get_fpm_socket() # Parse PHP-FPM pool configs
|
||||
standalone_list_fpm_sockets() # Find all pool sockets
|
||||
standalone_get_databases() # Query MySQL for user DBs
|
||||
```
|
||||
|
||||
**Vhost Parser Requirements**:
|
||||
- Support Apache: `/etc/apache2/sites-enabled/`, `/etc/httpd/conf.d/`
|
||||
- Support Nginx: `/etc/nginx/sites-enabled/`, `/etc/nginx/conf.d/`
|
||||
- Parse `ServerName`, `ServerAlias` (Apache)
|
||||
- Parse `server_name` (Nginx)
|
||||
- Parse `DocumentRoot` (Apache) / `root` (Nginx)
|
||||
- Parse `CustomLog`, `ErrorLog` (Apache) / `access_log`, `error_log` (Nginx)
|
||||
|
||||
### PHASE 4: Create build_domains_standalone() (NEW)
|
||||
**Priority**: HIGH
|
||||
|
||||
- Use standalone_list_domains() to get domains
|
||||
- Use standalone_get_*() helpers for domain info
|
||||
- Skip HTTP status checks initially
|
||||
- Test on Ubuntu/Debian standalone
|
||||
|
||||
### PHASE 5: Integration Testing (FROM ORIGINAL PLAN)
|
||||
**Priority**: MEDIUM
|
||||
|
||||
Test matrix:
|
||||
- cPanel (ensure no regression)
|
||||
- Plesk (test full domain/WP discovery)
|
||||
- Standalone Debian + Apache
|
||||
- Standalone Ubuntu + Nginx
|
||||
- Standalone AlmaLinux + Apache
|
||||
|
||||
---
|
||||
|
||||
## CRITICAL PATH ANALYSIS
|
||||
|
||||
### Blocker for Plesk Support:
|
||||
1. ❌ `get_domain_docroot()` missing Plesk case (NEW DISCOVERY)
|
||||
2. ❌ `/etc/localdomains` check needs cPanel conditional (NEW DISCOVERY)
|
||||
3. ❌ `build_domains_section()` needs Plesk branch
|
||||
4. ❌ WordPress path parsing hardcodes `/home/`
|
||||
|
||||
### Blocker for Standalone Support:
|
||||
1. ❌ No standalone-helpers.sh library
|
||||
2. ❌ No vhost parsing logic
|
||||
3. ❌ domain-discovery.sh has no standalone fallbacks
|
||||
4. ❌ No `build_domains_standalone()` function
|
||||
|
||||
---
|
||||
|
||||
## RISK ASSESSMENT
|
||||
|
||||
### High Risk Issues:
|
||||
1. **Missing get_domain_docroot() Plesk case** - Will cause immediate failure
|
||||
2. **Unconditionalized cPanel file checks** - May cause errors on other platforms
|
||||
3. **No standalone support** - Complete failure on non-panel systems
|
||||
|
||||
### Medium Risk Issues:
|
||||
1. **WordPress path parsing** - Will miss WordPress installations
|
||||
2. **Missing list_domains_with_docroots()** - Some modules may fail
|
||||
|
||||
### Low Risk Issues:
|
||||
1. **Launcher title** - Cosmetic only
|
||||
|
||||
---
|
||||
|
||||
## UPDATED TIMELINE
|
||||
|
||||
### Week 1:
|
||||
- **Days 1-2**: Phase 1A - Fix critical Plesk gaps (NEW)
|
||||
- **Days 3-4**: Phase 1B - Create build_domains_plesk()
|
||||
- **Day 5**: Phase 2A - Fix WordPress path parsing
|
||||
|
||||
### Week 2:
|
||||
- **Days 1-3**: Phase 3 - Create standalone-helpers.sh + vhost parser
|
||||
- **Days 4-5**: Phase 4 - Create build_domains_standalone()
|
||||
|
||||
### Week 3:
|
||||
- **Days 1-3**: Phase 5 - Integration testing all platforms
|
||||
- **Days 4-5**: Documentation + bug fixes
|
||||
|
||||
---
|
||||
|
||||
## RECOMMENDATIONS
|
||||
|
||||
### Immediate Actions (Before Starting Phase 1):
|
||||
|
||||
1. **Fix get_domain_docroot() Plesk case** ← MUST DO FIRST
|
||||
- Add missing Plesk case statement
|
||||
- Call `plesk_get_docroot()` function
|
||||
- Test that it returns correct paths
|
||||
|
||||
2. **Wrap cPanel-only file checks** ← SAFETY FIX
|
||||
- Add `if [ "$SYS_CONTROL_PANEL" = "cpanel" ]` around lines 364-396
|
||||
- Prevents errors on Plesk/standalone systems
|
||||
|
||||
3. **Update CROSS_PLATFORM_PLAN.md** ← DOCUMENTATION
|
||||
- Add Phase 1A for critical Plesk fixes
|
||||
- Add missing issue #2, #5, #6, #7, #8
|
||||
- Update risk assessment
|
||||
- Revise timeline to include fix phases
|
||||
|
||||
### Testing Strategy:
|
||||
|
||||
1. **Test EACH fix immediately** on cPanel (ensure no regression)
|
||||
2. **Test on Plesk** after Phase 1A completion
|
||||
3. **Don't start Phase 3** until Phases 1A+1B+2A tested on Plesk
|
||||
4. **Use feature flags** if needed to disable incomplete platforms
|
||||
|
||||
---
|
||||
|
||||
## FILES REQUIRING CHANGES
|
||||
|
||||
| File | Changes | Priority |
|
||||
|------|---------|----------|
|
||||
| lib/domain-discovery.sh | Add Plesk cases for 2 functions | CRITICAL |
|
||||
| lib/reference-db.sh | Wrap cPanel checks (lines 364-396) | CRITICAL |
|
||||
| lib/reference-db.sh | Refactor build_domains_section() | CRITICAL |
|
||||
| lib/reference-db.sh | Refactor build_wordpress_section() | HIGH |
|
||||
| lib/standalone-helpers.sh | Create new file | HIGH |
|
||||
| lib/domain-discovery.sh | Add 13 standalone fallback cases | HIGH |
|
||||
| launcher.sh | Update title (line 41) | LOW |
|
||||
|
||||
---
|
||||
|
||||
## CONCLUSION
|
||||
|
||||
**Original Plan Assessment**: ⚠️ INCOMPLETE
|
||||
|
||||
The original CROSS_PLATFORM_PLAN.md covered the major refactoring work but **missed 5 critical issues**:
|
||||
|
||||
1. Missing `get_domain_docroot()` Plesk case
|
||||
2. Unconditionalized `/etc/localdomains` and `/etc/remotedomains` checks
|
||||
3. Missing `list_domains_with_docroots()` Plesk case
|
||||
4. No standalone fallback cases in domain-discovery.sh
|
||||
5. Cosmetic launcher title issue
|
||||
|
||||
**Updated Plan Required**: YES
|
||||
|
||||
The plan must be revised to include Phase 1A (critical Plesk fixes) before starting the original Phase 1.
|
||||
|
||||
**Estimated Additional Time**: +2 days
|
||||
|
||||
**New Total Timeline**: 2-3 weeks (unchanged, but work redistributed)
|
||||
|
||||
---
|
||||
|
||||
**Audit Status**: ✅ COMPLETE
|
||||
**Next Step**: Update CROSS_PLATFORM_PLAN.md with findings
|
||||
**Approval Needed**: User should review before implementation begins
|
||||
@@ -1,313 +0,0 @@
|
||||
# Plesk Control Panel Reference
|
||||
|
||||
This document maps Plesk paths and structures for toolkit compatibility.
|
||||
|
||||
## Plesk Detection
|
||||
|
||||
```bash
|
||||
# Version file
|
||||
/usr/local/psa/version
|
||||
|
||||
# Admin bin directory
|
||||
/usr/local/psa/bin/
|
||||
|
||||
# CLI tool
|
||||
/usr/local/psa/bin/plesk
|
||||
```
|
||||
|
||||
## Directory Structure
|
||||
|
||||
### User/Domain Home Base
|
||||
```
|
||||
/var/www/vhosts/
|
||||
```
|
||||
|
||||
**Structure:**
|
||||
```
|
||||
/var/www/vhosts/
|
||||
├── domain.com/ # Main domain directory
|
||||
│ ├── httpdocs/ # Public web root
|
||||
│ ├── httpsdocs/ # SSL web root (if separate)
|
||||
│ ├── cgi-bin/
|
||||
│ ├── private/
|
||||
│ ├── logs/ # (FUTURE: will move here in Plesk Obsidian 18.0.50+)
|
||||
│ ├── statistics/
|
||||
│ └── tmp/
|
||||
├── subdomain.domain.com/ # Subdomain (separate directory)
|
||||
│ ├── httpdocs/
|
||||
│ └── ...
|
||||
└── system/ # System directory (logs, configs)
|
||||
├── domain.com/
|
||||
│ ├── logs/ # Current location of access/error logs
|
||||
│ ├── conf/ # Apache/Nginx configs
|
||||
│ ├── etc/ # PHP.ini and other configs
|
||||
│ └── php-fpm.sock # PHP-FPM socket
|
||||
└── subdomain.domain.com/
|
||||
└── ...
|
||||
```
|
||||
|
||||
### Log Files
|
||||
|
||||
**Current Structure (Plesk 17.x - 18.0.49):**
|
||||
```
|
||||
/var/www/vhosts/system/DOMAIN/logs/
|
||||
├── access_log # HTTP access log
|
||||
├── access_ssl_log # HTTPS access log
|
||||
├── error_log # Error log (both HTTP/HTTPS)
|
||||
├── proxy_access_log # Nginx proxy access (if applicable)
|
||||
├── proxy_access_ssl_log # Nginx proxy HTTPS access
|
||||
└── proxy_error_log # Nginx proxy errors
|
||||
```
|
||||
|
||||
**Future Structure (Plesk Obsidian 18.0.50+):**
|
||||
```
|
||||
/var/www/vhosts/DOMAIN/logs/
|
||||
├── access_log
|
||||
├── access_ssl_log
|
||||
├── error_log
|
||||
└── ...
|
||||
```
|
||||
|
||||
### Configuration Files
|
||||
|
||||
**Per-Domain Configs:**
|
||||
```
|
||||
/var/www/vhosts/system/DOMAIN/conf/
|
||||
├── httpd.conf # Apache vhost config
|
||||
├── nginx.conf # Nginx config
|
||||
├── vhost.conf # Custom Apache directives
|
||||
├── vhost_ssl.conf # Custom SSL directives
|
||||
└── php.ini # In ../etc/php.ini
|
||||
```
|
||||
|
||||
**PHP Configuration:**
|
||||
```
|
||||
/var/www/vhosts/system/DOMAIN/etc/
|
||||
└── php.ini # Domain-specific PHP settings
|
||||
```
|
||||
|
||||
### PHP-FPM
|
||||
|
||||
**Pool Sockets:**
|
||||
```
|
||||
/var/www/vhosts/system/DOMAIN/php-fpm.sock
|
||||
```
|
||||
|
||||
**System PHP-FPM:**
|
||||
```
|
||||
/opt/plesk/php/X.Y/ # Plesk-managed PHP versions
|
||||
/usr/bin/php # System default PHP
|
||||
```
|
||||
|
||||
## Plesk CLI Commands
|
||||
|
||||
### Domain Management
|
||||
```bash
|
||||
# List all domains
|
||||
plesk bin domain --list
|
||||
|
||||
# Get domain info
|
||||
plesk bin domain --info DOMAIN
|
||||
|
||||
# Get domain document root
|
||||
plesk bin domain --info DOMAIN | grep "www root" | awk '{print $NF}'
|
||||
```
|
||||
|
||||
### User/Subscription Management
|
||||
```bash
|
||||
# List all subscriptions
|
||||
plesk bin subscription --list
|
||||
|
||||
# Get subscription info
|
||||
plesk bin subscription --info DOMAIN
|
||||
|
||||
# List users
|
||||
plesk bin user --list
|
||||
```
|
||||
|
||||
### Database Management
|
||||
```bash
|
||||
# List databases
|
||||
plesk bin database --list
|
||||
|
||||
# List databases for domain
|
||||
plesk bin database --list -domain DOMAIN
|
||||
```
|
||||
|
||||
### Log Files
|
||||
```bash
|
||||
# Get log file path for domain
|
||||
# Current: /var/www/vhosts/system/DOMAIN/logs/
|
||||
# Future: /var/www/vhosts/DOMAIN/logs/
|
||||
```
|
||||
|
||||
### PHP Version Detection
|
||||
```bash
|
||||
# List PHP handlers
|
||||
plesk bin php_handler --list
|
||||
|
||||
# Get domain PHP version
|
||||
plesk bin site --info DOMAIN | grep "PHP version"
|
||||
```
|
||||
|
||||
### Service Management
|
||||
```bash
|
||||
# Apache
|
||||
plesk bin service_node --start httpd
|
||||
plesk bin service_node --stop httpd
|
||||
plesk bin service_node --restart httpd
|
||||
|
||||
# Nginx
|
||||
plesk bin service_node --start nginx
|
||||
plesk bin service_node --stop nginx
|
||||
|
||||
# PHP-FPM
|
||||
plesk bin service_node --restart plesk-php*-fpm
|
||||
```
|
||||
|
||||
## User/Domain Discovery
|
||||
|
||||
### Finding All Domains
|
||||
```bash
|
||||
# Method 1: Using Plesk CLI
|
||||
plesk bin domain --list
|
||||
|
||||
# Method 2: Directory scan
|
||||
ls -1d /var/www/vhosts/*/ | grep -v "system\|chroot\|.skel\|default" | xargs -I{} basename {}
|
||||
|
||||
# Method 3: From system directory
|
||||
ls -1 /var/www/vhosts/system/ | grep -v "^[0-9]"
|
||||
```
|
||||
|
||||
### Finding Domain Owner
|
||||
```bash
|
||||
# Get subscription owner
|
||||
plesk bin subscription --info DOMAIN | grep "Owner's login"
|
||||
```
|
||||
|
||||
### Finding Document Roots
|
||||
```bash
|
||||
# Main domain
|
||||
/var/www/vhosts/DOMAIN/httpdocs
|
||||
|
||||
# Subdomains
|
||||
/var/www/vhosts/SUBDOMAIN.DOMAIN/httpdocs
|
||||
|
||||
# Via CLI
|
||||
plesk bin domain --info DOMAIN | grep "www root"
|
||||
```
|
||||
|
||||
## PHP Detection
|
||||
|
||||
### Plesk-Managed PHP Versions
|
||||
```bash
|
||||
# Location
|
||||
/opt/plesk/php/*/bin/php
|
||||
|
||||
# List all versions
|
||||
ls -1d /opt/plesk/php/*/bin/php 2>/dev/null
|
||||
|
||||
# Get versions
|
||||
for php in /opt/plesk/php/*/bin/php; do
|
||||
$php -v | head -1
|
||||
done
|
||||
```
|
||||
|
||||
### System PHP
|
||||
```bash
|
||||
/usr/bin/php
|
||||
php -v
|
||||
```
|
||||
|
||||
## Database Discovery
|
||||
|
||||
### MySQL/MariaDB
|
||||
```bash
|
||||
# Plesk stores DB mappings in:
|
||||
/var/lib/psa/dumps/
|
||||
|
||||
# Get databases via CLI
|
||||
plesk bin database --list
|
||||
|
||||
# Database naming convention
|
||||
DOMAIN_DBNAME (underscores replace dots)
|
||||
```
|
||||
|
||||
## Subdomain Handling
|
||||
|
||||
**Important:** Plesk creates separate directories for subdomains
|
||||
|
||||
```bash
|
||||
# Main domain
|
||||
/var/www/vhosts/domain.com/httpdocs
|
||||
|
||||
# Subdomain gets its own directory
|
||||
/var/www/vhosts/sub.domain.com/httpdocs
|
||||
|
||||
# Logs
|
||||
/var/www/vhosts/system/sub.domain.com/logs/
|
||||
```
|
||||
|
||||
## Email
|
||||
|
||||
### Mailboxes
|
||||
```bash
|
||||
# Location
|
||||
/var/qmail/mailnames/DOMAIN/USERNAME/Maildir/
|
||||
```
|
||||
|
||||
### Mail Logs
|
||||
```bash
|
||||
/var/log/maillog
|
||||
```
|
||||
|
||||
## Important Differences from cPanel
|
||||
|
||||
1. **No /home directory structure** - Uses /var/www/vhosts
|
||||
2. **Subdomains are separate** - Not under main domain's directory
|
||||
3. **Logs in system/** - Not in domain directory (until Plesk 18.0.50+)
|
||||
4. **PHP-FPM per domain** - Socket in system/DOMAIN/
|
||||
5. **No ea-php** - Uses /opt/plesk/php/X.Y/
|
||||
6. **CLI is different** - Uses `plesk bin` not WHM API
|
||||
7. **User != Domain** - Subscription owners, not cPanel users
|
||||
|
||||
## Toolkit Compatibility Requirements
|
||||
|
||||
### Path Variables
|
||||
```bash
|
||||
SYS_USER_HOME_BASE="/var/www/vhosts"
|
||||
SYS_LOG_DIR="/var/www/vhosts/system"
|
||||
```
|
||||
|
||||
### Domain Enumeration
|
||||
Must use:
|
||||
1. `plesk bin domain --list`
|
||||
2. Directory scan excluding: system, chroot, .skel, default, fs
|
||||
|
||||
### Log File Discovery
|
||||
```bash
|
||||
# Current Plesk
|
||||
find /var/www/vhosts/system/*/logs/ -name "access*log" -o -name "error_log"
|
||||
|
||||
# Future Plesk (18.0.50+)
|
||||
find /var/www/vhosts/*/logs/ -name "access*log" -o -name "error_log"
|
||||
```
|
||||
|
||||
### PHP-FPM Pool Discovery
|
||||
```bash
|
||||
# Find all PHP-FPM pools
|
||||
find /var/www/vhosts/system/*/php-fpm.sock -type s 2>/dev/null
|
||||
|
||||
# Or check config
|
||||
grep -r "listen = " /var/www/vhosts/system/*/etc/ 2>/dev/null
|
||||
```
|
||||
|
||||
## Version-Specific Notes
|
||||
|
||||
### Plesk Obsidian (18.0.x)
|
||||
- Version 18.0.50+ moves logs from system/DOMAIN/logs/ to DOMAIN/logs/
|
||||
- Toolkit should check both locations for compatibility
|
||||
|
||||
### Plesk Onyx (17.x)
|
||||
- Logs in system/DOMAIN/logs/
|
||||
- Stable structure
|
||||
@@ -1,322 +0,0 @@
|
||||
# Plesk Support Implementation Summary
|
||||
|
||||
## Overview
|
||||
|
||||
Comprehensive Plesk control panel support has been added to the Server Toolkit. The toolkit now fully supports cPanel, Plesk, InterWorx, and standalone server configurations.
|
||||
|
||||
## Files Added
|
||||
|
||||
### 1. `/root/server-toolkit/PLESK_REFERENCE.md`
|
||||
Complete Plesk paths and structure reference documentation including:
|
||||
- Directory structure mapping
|
||||
- Log file locations (both current and future versions)
|
||||
- PHP-FPM pool locations
|
||||
- Configuration file paths
|
||||
- CLI command reference
|
||||
- Key differences from cPanel
|
||||
|
||||
### 2. `/root/server-toolkit/lib/plesk-helpers.sh`
|
||||
Plesk-specific helper functions library with 30+ functions:
|
||||
|
||||
**Domain Discovery:**
|
||||
- `plesk_list_domains()` - List all domains
|
||||
- `plesk_get_docroot()` - Get document root
|
||||
- `plesk_get_logdir()` - Get log directory (version-aware)
|
||||
- `plesk_get_all_logdirs()` - Get all domain log directories
|
||||
- `plesk_get_access_log()` - Get access log path
|
||||
- `plesk_get_error_log()` - Get error log path
|
||||
- `plesk_domain_exists()` - Check if domain exists
|
||||
|
||||
**User/Subscription Management:**
|
||||
- `plesk_list_subscriptions()` - List all subscriptions
|
||||
- `plesk_get_owner()` - Get domain owner
|
||||
|
||||
**Database Discovery:**
|
||||
- `plesk_list_databases()` - List all databases
|
||||
- `plesk_list_domain_databases()` - List databases for domain
|
||||
|
||||
**PHP Detection:**
|
||||
- `plesk_list_php_handlers()` - List available PHP handlers
|
||||
- `plesk_get_domain_php()` - Get PHP version for domain
|
||||
- `plesk_detect_php_versions()` - Detect all Plesk PHP versions
|
||||
|
||||
**PHP-FPM Pools:**
|
||||
- `plesk_list_fpm_sockets()` - List all FPM sockets
|
||||
- `plesk_get_fpm_socket()` - Get FPM socket for domain
|
||||
|
||||
**Configuration Files:**
|
||||
- `plesk_get_confdir()` - Get config directory
|
||||
- `plesk_get_httpd_conf()` - Get Apache config
|
||||
- `plesk_get_nginx_conf()` - Get Nginx config
|
||||
- `plesk_get_php_ini()` - Get PHP config
|
||||
|
||||
**Mail Functions:**
|
||||
- `plesk_get_mailbox_dir()` - Get mailbox directory
|
||||
- `plesk_list_mailboxes()` - List mailboxes for domain
|
||||
|
||||
**Service Management:**
|
||||
- `plesk_restart_apache()` - Restart Apache
|
||||
- `plesk_restart_nginx()` - Restart Nginx
|
||||
- `plesk_restart_phpfpm()` - Restart PHP-FPM
|
||||
|
||||
**Utilities:**
|
||||
- `plesk_get_version()` - Get Plesk version
|
||||
- `plesk_is_new_log_structure()` - Check if Plesk 18.0.50+
|
||||
- `plesk_list_domains_with_docroots()` - Get domains with docroots as TSV
|
||||
|
||||
### 3. `/root/server-toolkit/lib/domain-discovery.sh`
|
||||
Unified control panel abstraction layer providing consistent interface across all panels:
|
||||
|
||||
**Universal Functions (Work on All Panels):**
|
||||
- `list_all_domains()` - List all domains
|
||||
- `get_domain_docroot()` - Get document root
|
||||
- `get_domain_logdir()` - Get log directory
|
||||
- `get_domain_access_log()` - Get access log path
|
||||
- `get_domain_error_log()` - Get error log path
|
||||
- `get_all_log_files()` - Get all log files
|
||||
- `get_domain_owner()` - Get domain owner
|
||||
- `list_all_users()` - List all users
|
||||
- `get_domain_fpm_socket()` - Get PHP-FPM socket
|
||||
- `get_all_fpm_sockets()` - Get all FPM sockets
|
||||
- `get_domain_databases()` - Get domain databases
|
||||
- `domain_exists()` - Check if domain exists
|
||||
- `list_domains_with_docroots()` - Get domains with docroots
|
||||
|
||||
**How It Works:**
|
||||
- Each function detects `$SYS_CONTROL_PANEL` and calls appropriate panel-specific code
|
||||
- Provides consistent API regardless of control panel
|
||||
- Includes fallback methods when panel CLI unavailable
|
||||
|
||||
## Files Modified
|
||||
|
||||
### 1. `/root/server-toolkit/lib/system-detect.sh`
|
||||
|
||||
**Plesk Detection Enhancement (lines 56-77):**
|
||||
```bash
|
||||
# Plesk
|
||||
if [ -f "/usr/local/psa/version" ]; then
|
||||
SYS_CONTROL_PANEL="plesk"
|
||||
SYS_CONTROL_PANEL_VERSION=$(cat /usr/local/psa/version | head -1)
|
||||
|
||||
# Plesk uses /var/www/vhosts as base
|
||||
SYS_USER_HOME_BASE="/var/www/vhosts"
|
||||
|
||||
# Log directory depends on Plesk version
|
||||
# Plesk 18.0.50+ uses /var/www/vhosts/DOMAIN/logs
|
||||
# Plesk <18.0.50 uses /var/www/vhosts/system/DOMAIN/logs
|
||||
# Set marker path - tools will use plesk_get_logdir() for actual path
|
||||
SYS_LOG_DIR="/var/www/vhosts/system"
|
||||
|
||||
# Source Plesk helpers for advanced functionality
|
||||
if [ -f "$LIB_DIR/plesk-helpers.sh" ]; then
|
||||
source "$LIB_DIR/plesk-helpers.sh"
|
||||
fi
|
||||
|
||||
print_success "Detected Plesk v${SYS_CONTROL_PANEL_VERSION}"
|
||||
return 0
|
||||
fi
|
||||
```
|
||||
|
||||
**PHP Detection Enhancement (lines 253-261):**
|
||||
```bash
|
||||
# Check Plesk PHP versions (/opt/plesk/php/)
|
||||
if [ "$SYS_CONTROL_PANEL" = "plesk" ]; then
|
||||
for php_path in /opt/plesk/php/*/bin/php; do
|
||||
if [ -x "$php_path" ]; then
|
||||
local full_version=$($php_path -v 2>/dev/null | grep -oP '^PHP \K[\d.]+' | head -1)
|
||||
[ -n "$full_version" ] && SYS_PHP_VERSIONS+=("$full_version")
|
||||
fi
|
||||
done
|
||||
fi
|
||||
```
|
||||
|
||||
## Key Plesk Architecture Differences
|
||||
|
||||
### 1. Directory Structure
|
||||
- **cPanel:** `/home/USER/public_html/`
|
||||
- **Plesk:** `/var/www/vhosts/DOMAIN/httpdocs/`
|
||||
|
||||
### 2. Log Files
|
||||
- **cPanel:** `/var/log/apache2/domlogs/DOMAIN`
|
||||
- **Plesk (current):** `/var/www/vhosts/system/DOMAIN/logs/`
|
||||
- **Plesk (18.0.50+):** `/var/www/vhosts/DOMAIN/logs/`
|
||||
|
||||
### 3. Subdomain Handling
|
||||
- **cPanel:** Subdomains under main domain: `/home/USER/public_html/subdomain/`
|
||||
- **Plesk:** Separate directories: `/var/www/vhosts/sub.domain.com/httpdocs/`
|
||||
|
||||
### 4. PHP Versions
|
||||
- **cPanel:** `/opt/cpanel/ea-phpXX/root/usr/bin/php`
|
||||
- **Plesk:** `/opt/plesk/php/X.Y/bin/php`
|
||||
|
||||
### 5. PHP-FPM Pools
|
||||
- **cPanel:** `/opt/cpanel/ea-phpXX/root/usr/var/run/*.sock`
|
||||
- **Plesk:** `/var/www/vhosts/system/DOMAIN/php-fpm.sock`
|
||||
|
||||
### 6. Configuration Files
|
||||
- **cPanel:** `/var/cpanel/userdata/USER/DOMAIN`
|
||||
- **Plesk:** `/var/www/vhosts/system/DOMAIN/conf/`
|
||||
|
||||
## Version Compatibility
|
||||
|
||||
### Plesk Obsidian 17.x
|
||||
- Logs in `/var/www/vhosts/system/DOMAIN/logs/`
|
||||
- Fully supported
|
||||
|
||||
### Plesk Obsidian 18.0.0 - 18.0.49
|
||||
- Logs in `/var/www/vhosts/system/DOMAIN/logs/`
|
||||
- Fully supported
|
||||
|
||||
### Plesk Obsidian 18.0.50+
|
||||
- Logs moved to `/var/www/vhosts/DOMAIN/logs/`
|
||||
- Auto-detected via `plesk_is_new_log_structure()`
|
||||
- Functions check both locations
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Using Plesk-Specific Functions
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
source /root/server-toolkit/lib/system-detect.sh
|
||||
source /root/server-toolkit/lib/plesk-helpers.sh
|
||||
|
||||
# List all domains
|
||||
for domain in $(plesk_list_domains); do
|
||||
echo "Domain: $domain"
|
||||
|
||||
# Get paths
|
||||
docroot=$(plesk_get_docroot "$domain")
|
||||
logdir=$(plesk_get_logdir "$domain")
|
||||
|
||||
echo " Document root: $docroot"
|
||||
echo " Log directory: $logdir"
|
||||
done
|
||||
```
|
||||
|
||||
### Using Unified Discovery Functions
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
source /root/server-toolkit/lib/system-detect.sh
|
||||
source /root/server-toolkit/lib/domain-discovery.sh
|
||||
|
||||
# Works on ANY control panel (cPanel, Plesk, InterWorx, or standalone)
|
||||
for domain in $(list_all_domains); do
|
||||
echo "Domain: $domain"
|
||||
|
||||
docroot=$(get_domain_docroot "$domain")
|
||||
access_log=$(get_domain_access_log "$domain")
|
||||
owner=$(get_domain_owner "$domain")
|
||||
|
||||
echo " Owner: $owner"
|
||||
echo " Document root: $docroot"
|
||||
echo " Access log: $access_log"
|
||||
done
|
||||
```
|
||||
|
||||
## Migration Guide for Existing Modules
|
||||
|
||||
### OLD: cPanel-Specific Code
|
||||
```bash
|
||||
# Only works on cPanel
|
||||
for domain in $(awk -F': ' '{print $1}' /etc/userdomains); do
|
||||
user=$(grep "^${domain}:" /etc/userdomains | awk -F': ' '{print $2}')
|
||||
docroot="/home/$user/public_html"
|
||||
# ...
|
||||
done
|
||||
```
|
||||
|
||||
### NEW: Panel-Agnostic Code
|
||||
```bash
|
||||
# Works on all panels
|
||||
source "$LIB_DIR/domain-discovery.sh"
|
||||
|
||||
for domain in $(list_all_domains); do
|
||||
owner=$(get_domain_owner "$domain")
|
||||
docroot=$(get_domain_docroot "$domain")
|
||||
# ...
|
||||
done
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
### Test on Plesk System
|
||||
```bash
|
||||
# Run test script
|
||||
bash /root/test-plesk-discovery.sh
|
||||
```
|
||||
|
||||
### Verify Detection
|
||||
```bash
|
||||
source /root/server-toolkit/lib/system-detect.sh
|
||||
|
||||
echo "Control Panel: $SYS_CONTROL_PANEL"
|
||||
echo "Version: $SYS_CONTROL_PANEL_VERSION"
|
||||
echo "User Home Base: $SYS_USER_HOME_BASE"
|
||||
echo "Log Directory: $SYS_LOG_DIR"
|
||||
echo "PHP Versions: ${SYS_PHP_VERSIONS[*]}"
|
||||
```
|
||||
|
||||
## Fallback Mechanisms
|
||||
|
||||
All Plesk functions include fallback methods when Plesk CLI is unavailable:
|
||||
|
||||
1. **Domain Discovery:**
|
||||
- Primary: `plesk bin domain --list`
|
||||
- Fallback: Directory scan of `/var/www/vhosts/`
|
||||
|
||||
2. **Document Roots:**
|
||||
- Primary: `plesk bin domain --info DOMAIN`
|
||||
- Fallback: Standard path `/var/www/vhosts/DOMAIN/httpdocs`
|
||||
|
||||
3. **PHP Versions:**
|
||||
- Primary: `plesk bin php_handler --list`
|
||||
- Fallback: Scan `/opt/plesk/php/*/bin/php`
|
||||
|
||||
4. **Databases:**
|
||||
- Primary: `plesk bin database --list`
|
||||
- Fallback: Direct MySQL query with naming conventions
|
||||
|
||||
## Future Module Updates
|
||||
|
||||
The following modules should be updated to use the unified discovery functions:
|
||||
|
||||
1. ✅ **lib/system-detect.sh** - Updated
|
||||
2. ⏳ **modules/security/live-attack-monitor.sh** - Needs update
|
||||
3. ⏳ **modules/security/bot-analyzer.sh** - Needs update
|
||||
4. ⏳ **modules/security/malware-scanner.sh** - Needs update
|
||||
5. ⏳ **modules/website/** - Needs update for log discovery
|
||||
6. ⏳ **modules/performance/php-optimizer.sh** - Needs update for PHP-FPM
|
||||
7. ⏳ **lib/mysql-analyzer.sh** - Needs update for database discovery
|
||||
8. ⏳ **lib/user-manager.sh** - Needs update for user enumeration
|
||||
|
||||
## Status
|
||||
|
||||
✅ **Core Infrastructure Complete:**
|
||||
- Plesk detection and path mapping
|
||||
- 30+ Plesk helper functions
|
||||
- Unified discovery abstraction layer
|
||||
- Comprehensive documentation
|
||||
- Version compatibility handling
|
||||
- Fallback mechanisms
|
||||
|
||||
⏳ **Next Steps:**
|
||||
1. Test on actual Plesk server
|
||||
2. Update existing modules to use unified discovery
|
||||
3. Add Plesk-specific features where beneficial
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
When testing on Plesk server:
|
||||
- [ ] Domain enumeration returns all domains
|
||||
- [ ] Document roots are correctly identified
|
||||
- [ ] Log files are found (both access and error)
|
||||
- [ ] PHP versions are detected from /opt/plesk/php/
|
||||
- [ ] PHP-FPM sockets are located
|
||||
- [ ] Configuration files are found
|
||||
- [ ] Owner/user mapping works
|
||||
- [ ] Database discovery functions
|
||||
- [ ] Version detection is accurate
|
||||
- [ ] Log structure detection (old vs new) works
|
||||
- [ ] All modules can find domains and logs
|
||||
@@ -1,5 +0,0 @@
|
||||
Backup Created: Fri Dec 12 11:14:52 PM EST 2025
|
||||
Username: pickledperil
|
||||
Domain: pickledperil.com
|
||||
Backup Name: test_231452
|
||||
/opt/cpanel/ea-php81/root/etc/php-fpm.d/pickledperil.com.conf → /root/server-toolkit/backups/php/test_231452/opt/cpanel/ea-php81/root/etc/php-fpm.d/pickledperil.com.conf
|
||||
@@ -1,33 +0,0 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; cPanel FPM Configuration ;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
; NOTICE This file is generated. Please use our WHM User Interface
|
||||
; to set these values.
|
||||
|
||||
[pickledperil_com]
|
||||
catch_workers_output = yes
|
||||
chdir = /home/pickledperil
|
||||
group = "pickledperil"
|
||||
listen = /opt/cpanel/ea-php81/root/usr/var/run/php-fpm/95f116b048f081d0b9879b09b8608f7d77c6ddd8.sock
|
||||
listen.group = "nobody"
|
||||
listen.mode = 0660
|
||||
listen.owner = "pickledperil"
|
||||
php_admin_flag[allow_url_fopen] = on
|
||||
php_admin_flag[log_errors] = on
|
||||
php_admin_value[disable_functions] = exec,passthru,shell_exec,system
|
||||
php_admin_value[doc_root] = "/home/pickledperil/public_html"
|
||||
php_admin_value[error_log] = /home/pickledperil/logs/pickledperil_com.php.error.log
|
||||
php_admin_value[short_open_tag] = on
|
||||
php_value[error_reporting] = E_ALL & ~E_NOTICE
|
||||
ping.path = /ping
|
||||
pm = ondemand
|
||||
pm.max_children = 5
|
||||
pm.max_requests = 20
|
||||
pm.max_spare_servers = 5
|
||||
pm.min_spare_servers = 1
|
||||
pm.process_idle_timeout = 10
|
||||
pm.start_servers = 0
|
||||
pm.status_path = /status
|
||||
security.limit_extensions = .phtml .php .php3 .php4 .php5 .php6 .php7 .php8
|
||||
user = "pickledperil"
|
||||
@@ -1,4 +0,0 @@
|
||||
Backup Created: Fri Dec 12 05:17:28 PM EST 2025
|
||||
Username: pickledperil
|
||||
Domain: pickledperil.com
|
||||
Backup Name: test_backup_20251212_171728
|
||||
@@ -1,483 +0,0 @@
|
||||
# Complete PHP Configuration File Locations - All Control Panels
|
||||
|
||||
## Understanding PHP Configuration Priority
|
||||
|
||||
PHP configuration is applied in a **hierarchical cascade**. Settings in higher-priority files **override** settings in lower-priority files.
|
||||
|
||||
### Priority Order (Highest to Lowest)
|
||||
|
||||
```
|
||||
PRIORITY 1 (HIGHEST): Per-Directory Configuration
|
||||
├─ .user.ini (PHP-FPM only, per-directory)
|
||||
├─ .htaccess with php_value/php_flag (Apache + mod_php ONLY, NOT PHP-FPM!)
|
||||
└─ ini_set() in PHP code (runtime only)
|
||||
|
||||
PRIORITY 2: User-Specific Configuration
|
||||
├─ ~/public_html/php.ini (some control panels)
|
||||
├─ ~/.php/X.Y/php.ini (per PHP version)
|
||||
├─ ~/etc/phpX.Y/php.ini (InterWorx style)
|
||||
└─ ~/php.ini (legacy)
|
||||
|
||||
PRIORITY 3: Pool-Specific Configuration
|
||||
├─ /opt/cpanel/ea-phpXY/root/etc/php.ini (cPanel EA-PHP)
|
||||
├─ /opt/alt/phpXY/etc/php.ini (CloudLinux Alt-PHP)
|
||||
├─ Additional .ini files loaded alphabetically:
|
||||
│ ├─ /opt/cpanel/ea-phpXY/root/etc/php.d/*.ini
|
||||
│ └─ Loaded in alphabetical order (00-*, 10-*, 20-*, etc.)
|
||||
└─ scan_dir configured locations
|
||||
|
||||
PRIORITY 4 (LOWEST): System-Wide Configuration
|
||||
└─ /etc/php.ini (global default, rarely used with control panels)
|
||||
```
|
||||
|
||||
## Complete File Location Map by Control Panel
|
||||
|
||||
### cPanel with EA-PHP (Most Common)
|
||||
|
||||
#### 1. Per-Directory (.user.ini) - **PRIORITY 1**
|
||||
```bash
|
||||
# Location pattern
|
||||
/home/$username/public_html/.user.ini
|
||||
/home/$username/public_html/subdirectory/.user.ini
|
||||
/home/$username/public_html/app/.user.ini
|
||||
|
||||
# Applies to
|
||||
- That directory and all subdirectories
|
||||
- Only works with PHP-FPM (not mod_php)
|
||||
- Reloaded every user_ini.cache_ttl seconds (default 300)
|
||||
|
||||
# Example content
|
||||
memory_limit = 512M
|
||||
upload_max_filesize = 100M
|
||||
post_max_size = 150M
|
||||
max_execution_time = 120
|
||||
|
||||
# Find all .user.ini files for a user
|
||||
find /home/$username -name ".user.ini" -type f
|
||||
|
||||
# Common locations
|
||||
/home/$username/public_html/.user.ini
|
||||
/home/$username/public_html/wp-content/.user.ini
|
||||
/home/$username/public_html/app/upload/.user.ini
|
||||
```
|
||||
|
||||
#### 2. .htaccess with PHP directives - **PRIORITY 1** (mod_php ONLY!)
|
||||
```bash
|
||||
# Location
|
||||
/home/$username/public_html/.htaccess
|
||||
|
||||
# IMPORTANT: Only works with Apache mod_php
|
||||
# Does NOT work with PHP-FPM!
|
||||
# cPanel typically uses PHP-FPM, so .htaccess php_value is IGNORED
|
||||
|
||||
# Example content (if mod_php is used)
|
||||
php_value memory_limit 256M
|
||||
php_value upload_max_filesize 64M
|
||||
php_flag display_errors Off
|
||||
|
||||
# Find .htaccess with PHP directives
|
||||
find /home/$username/public_html -name ".htaccess" -exec grep -l "php_value\|php_flag" {} \;
|
||||
```
|
||||
|
||||
#### 3. User Home Directory Configs - **PRIORITY 2**
|
||||
```bash
|
||||
# cPanel creates user-specific php.ini in various locations:
|
||||
|
||||
# A. PHP version-specific in home
|
||||
/home/$username/.php/8.2/php.ini
|
||||
/home/$username/.php/8.1/php.ini
|
||||
/home/$username/.php/8.0/php.ini
|
||||
|
||||
# B. Legacy home php.ini
|
||||
/home/$username/php.ini
|
||||
|
||||
# C. In etc subdirectory
|
||||
/home/$username/etc/php.ini
|
||||
/home/$username/etc/php/8.2/php.ini
|
||||
|
||||
# D. In public_html (some configurations)
|
||||
/home/$username/public_html/php.ini
|
||||
|
||||
# Find all home directory php.ini files
|
||||
find /home/$username -maxdepth 3 -name "php.ini" -type f
|
||||
find /home/$username/.php -name "php.ini" -type f 2>/dev/null
|
||||
```
|
||||
|
||||
#### 4. MultiPHP INI Editor Files - **PRIORITY 2**
|
||||
```bash
|
||||
# cPanel's MultiPHP INI Editor creates user-specific overrides here:
|
||||
/var/cpanel/userdata/$username/php-fpm.d/$domain.conf
|
||||
/home/$username/.php/8.2/php.ini
|
||||
|
||||
# These override pool defaults but are overridden by .user.ini
|
||||
```
|
||||
|
||||
#### 5. EA-PHP Pool Configuration - **PRIORITY 3**
|
||||
```bash
|
||||
# Main php.ini for each EA-PHP version
|
||||
/opt/cpanel/ea-php80/root/etc/php.ini
|
||||
/opt/cpanel/ea-php81/root/etc/php.ini
|
||||
/opt/cpanel/ea-php82/root/etc/php.ini
|
||||
/opt/cpanel/ea-php83/root/etc/php.ini
|
||||
|
||||
# Additional .ini files (loaded alphabetically)
|
||||
/opt/cpanel/ea-php82/root/etc/php.d/00-ioncube.ini
|
||||
/opt/cpanel/ea-php82/root/etc/php.d/10-opcache.ini
|
||||
/opt/cpanel/ea-php82/root/etc/php.d/20-gd.ini
|
||||
/opt/cpanel/ea-php82/root/etc/php.d/30-mysqli.ini
|
||||
|
||||
# Find all EA-PHP installations
|
||||
find /opt/cpanel -maxdepth 1 -type d -name "ea-php*"
|
||||
|
||||
# Find all php.ini files
|
||||
find /opt/cpanel/ea-php* -name "php.ini"
|
||||
|
||||
# Find all additional .ini files
|
||||
find /opt/cpanel/ea-php*/root/etc/php.d/ -name "*.ini" | sort
|
||||
```
|
||||
|
||||
#### 6. PHP-FPM Pool Configs (Not php.ini but affects PHP)
|
||||
```bash
|
||||
# Per-user FPM pool config (process manager settings)
|
||||
/opt/cpanel/ea-php82/root/etc/php-fpm.d/$username.conf
|
||||
|
||||
# Contains: pm, pm.max_children, pm.start_servers, etc.
|
||||
# Not php.ini settings, but critical for performance!
|
||||
```
|
||||
|
||||
### CloudLinux with Alt-PHP
|
||||
|
||||
#### Alt-PHP Configuration Locations
|
||||
```bash
|
||||
# Main php.ini for each Alt-PHP version
|
||||
/opt/alt/php80/etc/php.ini
|
||||
/opt/alt/php81/etc/php.ini
|
||||
/opt/alt/php82/etc/php.ini
|
||||
|
||||
# Additional .ini files
|
||||
/opt/alt/php82/etc/php.d.all/*.ini
|
||||
|
||||
# Per-user overrides (if configured)
|
||||
/home/$username/.cl.php/alt-php82/php.ini
|
||||
|
||||
# Find all Alt-PHP versions
|
||||
ls -d /opt/alt/php*/
|
||||
|
||||
# Find all Alt-PHP ini files
|
||||
find /opt/alt/php* -name "php.ini"
|
||||
```
|
||||
|
||||
### Plesk
|
||||
|
||||
#### Plesk PHP Configuration Hierarchy
|
||||
```bash
|
||||
# 1. Per-directory .user.ini - PRIORITY 1
|
||||
/var/www/vhosts/$domain/httpdocs/.user.ini
|
||||
/var/www/vhosts/$domain/httpdocs/subdirectory/.user.ini
|
||||
|
||||
# 2. Domain-specific php.ini - PRIORITY 2
|
||||
/var/www/vhosts/system/$domain/etc/php.ini
|
||||
|
||||
# 3. Pool-specific php.ini - PRIORITY 3
|
||||
/etc/php-fpm.d/plesk-php82-fpm/php.ini
|
||||
|
||||
# 4. PHP version php.ini - PRIORITY 3
|
||||
/opt/plesk/php/8.2/etc/php.ini
|
||||
/opt/plesk/php/8.1/etc/php.ini
|
||||
|
||||
# 5. Additional .ini files
|
||||
/opt/plesk/php/8.2/etc/php.d/*.ini
|
||||
|
||||
# 6. System-wide - PRIORITY 4
|
||||
/etc/php.ini
|
||||
|
||||
# Find domain php.ini files
|
||||
find /var/www/vhosts/system -name "php.ini"
|
||||
|
||||
# Find all Plesk PHP versions
|
||||
ls -d /opt/plesk/php/*/
|
||||
```
|
||||
|
||||
### InterWorx
|
||||
|
||||
#### InterWorx PHP Configuration
|
||||
```bash
|
||||
# 1. Per-directory .user.ini - PRIORITY 1
|
||||
/home/$username/var/$domain/html/.user.ini
|
||||
|
||||
# 2. Domain-specific php.ini - PRIORITY 2
|
||||
/home/$username/var/$domain/etc/php.ini
|
||||
|
||||
# 3. User etc directory
|
||||
/home/$username/etc/php82/php.ini
|
||||
|
||||
# 4. PHP version php.ini - PRIORITY 3
|
||||
/etc/php82/php.ini
|
||||
/etc/php81/php.ini
|
||||
|
||||
# 5. System-wide - PRIORITY 4
|
||||
/etc/php.ini
|
||||
|
||||
# Find InterWorx domain configs
|
||||
find /home/*/var/*/etc -name "php.ini"
|
||||
|
||||
# Find user php configs
|
||||
find /home/*/etc/php* -name "php.ini"
|
||||
```
|
||||
|
||||
### DirectAdmin
|
||||
|
||||
#### DirectAdmin Configuration
|
||||
```bash
|
||||
# 1. Per-directory .user.ini - PRIORITY 1
|
||||
/home/$username/domains/$domain/public_html/.user.ini
|
||||
|
||||
# 2. Domain php.ini - PRIORITY 2
|
||||
/usr/local/directadmin/data/users/$username/php/domains/$domain.ini
|
||||
|
||||
# 3. User default php.ini
|
||||
/usr/local/directadmin/data/users/$username/php/php.ini
|
||||
|
||||
# 4. PHP version php.ini - PRIORITY 3
|
||||
/usr/local/php82/lib/php.ini
|
||||
|
||||
# Find DirectAdmin configs
|
||||
find /usr/local/directadmin/data/users -name "php.ini"
|
||||
find /usr/local/directadmin/data/users -name "*.ini"
|
||||
```
|
||||
|
||||
### No Control Panel (Standalone)
|
||||
|
||||
#### Standard PHP Locations
|
||||
```bash
|
||||
# 1. Per-directory .user.ini - PRIORITY 1
|
||||
/var/www/html/.user.ini
|
||||
/var/www/domain.com/.user.ini
|
||||
|
||||
# 2. Pool-specific (if using PHP-FPM)
|
||||
/etc/php/8.2/fpm/php.ini
|
||||
/etc/php-fpm.d/www.conf
|
||||
|
||||
# 3. CLI php.ini (different from FPM!)
|
||||
/etc/php/8.2/cli/php.ini
|
||||
|
||||
# 4. Additional .ini files
|
||||
/etc/php/8.2/mods-available/*.ini
|
||||
/etc/php/8.2/conf.d/*.ini
|
||||
|
||||
# 5. System-wide
|
||||
/etc/php.ini
|
||||
/usr/local/lib/php.ini
|
||||
```
|
||||
|
||||
## Detection Strategy - Universal Function
|
||||
|
||||
```bash
|
||||
find_all_php_configs() {
|
||||
local username="$1"
|
||||
local domain="$2"
|
||||
local php_version="$3" # e.g., "82" or "8.2"
|
||||
|
||||
declare -a config_files
|
||||
declare -A config_priority
|
||||
|
||||
echo "=== Finding ALL PHP configs affecting: $domain (user: $username) ==="
|
||||
echo ""
|
||||
|
||||
# PRIORITY 1: Per-Directory .user.ini
|
||||
echo "PRIORITY 1: Per-Directory Configs"
|
||||
while IFS= read -r file; do
|
||||
if [ -f "$file" ]; then
|
||||
config_files+=("$file")
|
||||
config_priority["$file"]=1
|
||||
echo " [P1] $file"
|
||||
fi
|
||||
done < <(find "/home/$username" -name ".user.ini" 2>/dev/null)
|
||||
|
||||
# Check .htaccess (only relevant for mod_php)
|
||||
while IFS= read -r file; do
|
||||
if grep -q "php_value\|php_flag" "$file" 2>/dev/null; then
|
||||
config_files+=("$file")
|
||||
config_priority["$file"]=1
|
||||
echo " [P1] $file (mod_php only - likely IGNORED on PHP-FPM!)"
|
||||
fi
|
||||
done < <(find "/home/$username/public_html" -name ".htaccess" 2>/dev/null)
|
||||
|
||||
echo ""
|
||||
echo "PRIORITY 2: User-Specific Configs"
|
||||
|
||||
# User home directory configs (various patterns)
|
||||
local user_configs=(
|
||||
"/home/$username/php.ini"
|
||||
"/home/$username/public_html/php.ini"
|
||||
"/home/$username/.php/$php_version/php.ini"
|
||||
"/home/$username/.php/${php_version:0:1}.${php_version:1}/php.ini"
|
||||
"/home/$username/etc/php.ini"
|
||||
"/home/$username/etc/php/$php_version/php.ini"
|
||||
)
|
||||
|
||||
for config in "${user_configs[@]}"; do
|
||||
if [ -f "$config" ]; then
|
||||
config_files+=("$config")
|
||||
config_priority["$config"]=2
|
||||
echo " [P2] $config"
|
||||
fi
|
||||
done
|
||||
|
||||
# Plesk domain-specific
|
||||
if [ -f "/var/www/vhosts/system/$domain/etc/php.ini" ]; then
|
||||
config_files+=("/var/www/vhosts/system/$domain/etc/php.ini")
|
||||
config_priority["/var/www/vhosts/system/$domain/etc/php.ini"]=2
|
||||
echo " [P2] /var/www/vhosts/system/$domain/etc/php.ini"
|
||||
fi
|
||||
|
||||
# InterWorx domain-specific
|
||||
if [ -f "/home/$username/var/$domain/etc/php.ini" ]; then
|
||||
config_files+=("/home/$username/var/$domain/etc/php.ini")
|
||||
config_priority["/home/$username/var/$domain/etc/php.ini"]=2
|
||||
echo " [P2] /home/$username/var/$domain/etc/php.ini"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "PRIORITY 3: Pool/Version-Specific Configs"
|
||||
|
||||
# cPanel EA-PHP
|
||||
local cpanel_php_ini="/opt/cpanel/ea-php${php_version}/root/etc/php.ini"
|
||||
if [ -f "$cpanel_php_ini" ]; then
|
||||
config_files+=("$cpanel_php_ini")
|
||||
config_priority["$cpanel_php_ini"]=3
|
||||
echo " [P3] $cpanel_php_ini"
|
||||
|
||||
# Additional .ini files
|
||||
if [ -d "/opt/cpanel/ea-php${php_version}/root/etc/php.d" ]; then
|
||||
while IFS= read -r file; do
|
||||
config_files+=("$file")
|
||||
config_priority["$file"]=3
|
||||
echo " [P3] $file"
|
||||
done < <(find "/opt/cpanel/ea-php${php_version}/root/etc/php.d" -name "*.ini" | sort)
|
||||
fi
|
||||
fi
|
||||
|
||||
# CloudLinux Alt-PHP
|
||||
local alt_php_ini="/opt/alt/php${php_version}/etc/php.ini"
|
||||
if [ -f "$alt_php_ini" ]; then
|
||||
config_files+=("$alt_php_ini")
|
||||
config_priority["$alt_php_ini"]=3
|
||||
echo " [P3] $alt_php_ini"
|
||||
fi
|
||||
|
||||
# Plesk
|
||||
local plesk_php_ini="/opt/plesk/php/${php_version:0:1}.${php_version:1}/etc/php.ini"
|
||||
if [ -f "$plesk_php_ini" ]; then
|
||||
config_files+=("$plesk_php_ini")
|
||||
config_priority["$plesk_php_ini"]=3
|
||||
echo " [P3] $plesk_php_ini"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "PRIORITY 4: System-Wide Default"
|
||||
if [ -f "/etc/php.ini" ]; then
|
||||
config_files+=("/etc/php.ini")
|
||||
config_priority["/etc/php.ini"]=4
|
||||
echo " [P4] /etc/php.ini"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=== Total config files found: ${#config_files[@]} ==="
|
||||
|
||||
# Return the array
|
||||
printf '%s\n' "${config_files[@]}"
|
||||
}
|
||||
```
|
||||
|
||||
## How to Determine Effective Setting
|
||||
|
||||
### Method 1: Query PHP Directly (MOST ACCURATE!)
|
||||
|
||||
```bash
|
||||
# Get effective value for a specific setting
|
||||
get_effective_php_setting() {
|
||||
local username="$1"
|
||||
local setting="$2" # e.g., "memory_limit"
|
||||
|
||||
# Run as user to get their effective settings
|
||||
su -s /bin/bash "$username" -c "php -r 'echo ini_get(\"$setting\");'"
|
||||
}
|
||||
|
||||
# Example usage
|
||||
memory_limit=$(get_effective_php_setting "examplec" "memory_limit")
|
||||
echo "Effective memory_limit: $memory_limit"
|
||||
|
||||
# Get ALL effective settings
|
||||
su -s /bin/bash "$username" -c "php -r 'print_r(ini_get_all());'" > /tmp/effective_php_settings.txt
|
||||
```
|
||||
|
||||
### Method 2: Parse Config Hierarchy
|
||||
|
||||
```bash
|
||||
# Parse configs in priority order and track overrides
|
||||
get_setting_from_configs() {
|
||||
local setting="$1"
|
||||
local value=""
|
||||
|
||||
# Parse in REVERSE priority (lowest to highest)
|
||||
# So higher priority files override
|
||||
|
||||
# Priority 4: System
|
||||
value=$(grep "^$setting" /etc/php.ini | cut -d'=' -f2 | tr -d ' ')
|
||||
|
||||
# Priority 3: Pool
|
||||
pool_value=$(grep "^$setting" /opt/cpanel/ea-php82/root/etc/php.ini | cut -d'=' -f2 | tr -d ' ')
|
||||
[ -n "$pool_value" ] && value="$pool_value"
|
||||
|
||||
# Priority 2: User
|
||||
user_value=$(grep "^$setting" /home/$username/.php/8.2/php.ini | cut -d'=' -f2 | tr -d ' ')
|
||||
[ -n "$user_value" ] && value="$user_value"
|
||||
|
||||
# Priority 1: .user.ini
|
||||
user_ini_value=$(grep "^$setting" /home/$username/public_html/.user.ini | cut -d'=' -f2 | tr -d ' ')
|
||||
[ -n "$user_ini_value" ] && value="$user_ini_value"
|
||||
|
||||
echo "$value"
|
||||
}
|
||||
```
|
||||
|
||||
## Quick Reference Commands
|
||||
|
||||
```bash
|
||||
# Find ALL php.ini files on system
|
||||
find / -name "php.ini" -type f 2>/dev/null
|
||||
|
||||
# Find ALL .user.ini files
|
||||
find /home -name ".user.ini" -type f 2>/dev/null
|
||||
|
||||
# Find .htaccess with PHP directives
|
||||
find /home -name ".htaccess" -exec grep -l "php_value\|php_flag" {} \; 2>/dev/null
|
||||
|
||||
# Get effective settings for a domain (via web)
|
||||
curl -s "http://domain.com/info.php" | grep -A1 "memory_limit"
|
||||
|
||||
# Get effective settings via CLI
|
||||
php -i | grep "memory_limit"
|
||||
php -r "echo ini_get('memory_limit');"
|
||||
|
||||
# List all loaded .ini files
|
||||
php --ini
|
||||
|
||||
# Get configuration file path
|
||||
php -r "echo php_ini_loaded_file();"
|
||||
|
||||
# Get scanned .ini directory
|
||||
php -r "echo php_ini_scanned_files();"
|
||||
```
|
||||
|
||||
## Key Takeaways for Optimizer
|
||||
|
||||
1. **Always check .user.ini first** - It overrides everything!
|
||||
2. **Per-domain/user configs vary by control panel** - Need detection logic
|
||||
3. **.htaccess php_value only works with mod_php** - Usually ignored on modern setups
|
||||
4. **Query PHP directly for accurate effective values** - Don't just parse files
|
||||
5. **Check loaded files via php --ini** - Shows what's actually being used
|
||||
6. **Multiple .ini files can affect same setting** - Last one wins (in priority order)
|
||||
|
||||
This complete map ensures the optimizer will find ALL configuration affecting a domain!
|
||||
@@ -1,469 +0,0 @@
|
||||
# Comprehensive PHP Metrics Tracking Guide
|
||||
|
||||
## PHP Configuration Hierarchy & Detection
|
||||
|
||||
### Configuration File Priority (Highest to Lowest)
|
||||
Understanding which config takes effect is critical for accurate optimization.
|
||||
|
||||
```
|
||||
1. .user.ini (per-directory, PHP-FPM only)
|
||||
Location: /home/user/public_html/.user.ini
|
||||
Scope: Specific directory and subdirectories
|
||||
Reloads: Automatically every user_ini.cache_ttl seconds (default 300)
|
||||
|
||||
2. .htaccess (Apache with mod_php only, NOT PHP-FPM!)
|
||||
Location: /home/user/public_html/.htaccess
|
||||
Scope: Directory-specific
|
||||
Note: Does NOT work with PHP-FPM!
|
||||
|
||||
3. php.ini (per-pool, cPanel EA-PHP)
|
||||
Location: /opt/cpanel/ea-php*/root/etc/php.ini
|
||||
Scope: All domains using that PHP version
|
||||
|
||||
4. Additional .ini files (per-pool)
|
||||
Location: /opt/cpanel/ea-php*/root/etc/php.d/*.ini
|
||||
Scope: Per PHP version, loaded alphabetically
|
||||
|
||||
5. Global php.ini
|
||||
Location: /etc/php.ini (legacy)
|
||||
Scope: System-wide fallback
|
||||
```
|
||||
|
||||
### How to Determine Effective Settings
|
||||
|
||||
**Method 1: Query via PHP (Most Accurate)**
|
||||
```bash
|
||||
# Get effective value for specific domain
|
||||
echo '<?php echo ini_get("memory_limit"); ?>' | \
|
||||
su -s /bin/bash $username -c "php -q -d open_basedir="
|
||||
|
||||
# Get ALL effective settings
|
||||
php -r 'print_r(ini_get_all());' > /tmp/php_all_settings.txt
|
||||
|
||||
# Per-domain via web request (if domain is accessible)
|
||||
curl -s "http://$domain/phpinfo.php" | grep -A1 "memory_limit"
|
||||
```
|
||||
|
||||
**Method 2: Parse Configuration Files**
|
||||
```bash
|
||||
# Find ALL possible config files affecting a domain
|
||||
find_php_configs() {
|
||||
local domain="$1"
|
||||
local user="$2"
|
||||
local php_version="$3" # e.g., "ea-php82"
|
||||
|
||||
# Priority order
|
||||
echo "=== Config Hierarchy for $domain ==="
|
||||
|
||||
# 1. .user.ini
|
||||
local user_ini="/home/$user/public_html/.user.ini"
|
||||
if [ -f "$user_ini" ]; then
|
||||
echo "1. .user.ini: $user_ini (HIGHEST PRIORITY)"
|
||||
grep -E "memory_limit|max_execution_time|upload_max_filesize" "$user_ini"
|
||||
fi
|
||||
|
||||
# 2. Pool-specific php.ini
|
||||
local pool_ini="/opt/cpanel/$php_version/root/etc/php.ini"
|
||||
if [ -f "$pool_ini" ]; then
|
||||
echo "2. Pool php.ini: $pool_ini"
|
||||
grep -E "memory_limit|max_execution_time|upload_max_filesize" "$pool_ini"
|
||||
fi
|
||||
|
||||
# 3. Additional .ini files
|
||||
local ini_dir="/opt/cpanel/$php_version/root/etc/php.d"
|
||||
if [ -d "$ini_dir" ]; then
|
||||
echo "3. Additional .ini files: $ini_dir/*.ini"
|
||||
grep -h -E "memory_limit|max_execution_time|upload_max_filesize" "$ini_dir"/*.ini 2>/dev/null
|
||||
fi
|
||||
}
|
||||
```
|
||||
|
||||
## Complete PHP Metrics to Track
|
||||
|
||||
### 1. **Memory Settings** (Critical for Performance)
|
||||
|
||||
```ini
|
||||
# Basic Memory
|
||||
memory_limit = 256M # Per-script memory limit
|
||||
# Track: Current value, recommended, % of total RAM
|
||||
|
||||
# Upload Limits (Related to Memory)
|
||||
upload_max_filesize = 64M # Max single file upload
|
||||
post_max_size = 128M # Max POST data (should be >= upload_max_filesize)
|
||||
max_input_vars = 1000 # Max input variables (forms with many fields)
|
||||
max_input_nesting_level = 64 # Max array nesting depth
|
||||
max_input_time = 60 # Max time parsing input data
|
||||
|
||||
# Realpath Cache (Memory for path resolution)
|
||||
realpath_cache_size = 4096K # Cache size for realpath() calls
|
||||
realpath_cache_ttl = 120 # TTL in seconds
|
||||
```
|
||||
|
||||
**Why Track:**
|
||||
- `memory_limit` too low → "Allowed memory size exhausted" errors
|
||||
- `post_max_size < upload_max_filesize` → Upload failures
|
||||
- `realpath_cache_size` too small → File I/O slowdowns
|
||||
|
||||
**Detection:**
|
||||
```bash
|
||||
# Find memory exhausted errors
|
||||
grep -r "Allowed memory size.*exhausted" /home/$user/*/logs/error_log
|
||||
|
||||
# Find upload failures
|
||||
grep -r "POST Content-Length.*exceeds" /home/$user/*/logs/error_log
|
||||
```
|
||||
|
||||
### 2. **Execution & Timeout Settings**
|
||||
|
||||
```ini
|
||||
# Script Execution
|
||||
max_execution_time = 30 # Max script runtime (seconds)
|
||||
max_input_time = 60 # Max time for input parsing
|
||||
default_socket_timeout = 60 # Default socket timeout
|
||||
|
||||
# CGI-specific
|
||||
cgi.force_redirect = 1
|
||||
cgi.fix_pathinfo = 0 # Security: prevent path injection
|
||||
```
|
||||
|
||||
**Why Track:**
|
||||
- `max_execution_time` too low → Scripts timeout on slow operations
|
||||
- Long-running cron jobs need higher limits
|
||||
|
||||
**Detection:**
|
||||
```bash
|
||||
# Find timeout errors
|
||||
grep -r "Maximum execution time.*exceeded" /home/$user/*/logs/error_log
|
||||
```
|
||||
|
||||
### 3. **PHP-FPM Pool Settings** (Most Critical for Optimization!)
|
||||
|
||||
```ini
|
||||
# Process Manager Type
|
||||
pm = dynamic # static | dynamic | ondemand
|
||||
# static: Fixed number of children
|
||||
# dynamic: Scales between min/max
|
||||
# ondemand: Spawns on-demand (saves memory)
|
||||
|
||||
# Process Limits (DYNAMIC mode)
|
||||
pm.max_children = 50 # Max simultaneous processes
|
||||
pm.start_servers = 5 # Processes started at boot
|
||||
pm.min_spare_servers = 5 # Minimum idle processes
|
||||
pm.max_spare_servers = 35 # Maximum idle processes
|
||||
|
||||
# Process Limits (STATIC mode)
|
||||
pm.max_children = 50 # Fixed number of processes
|
||||
|
||||
# Process Limits (ONDEMAND mode)
|
||||
pm.max_children = 50 # Max processes
|
||||
pm.process_idle_timeout = 10s # Kill idle process after X seconds
|
||||
|
||||
# Process Recycling
|
||||
pm.max_requests = 500 # Respawn after X requests (prevent memory leaks)
|
||||
|
||||
# Status & Monitoring
|
||||
pm.status_path = /fpm-status # Status page URL
|
||||
ping.path = /fpm-ping # Health check URL
|
||||
ping.response = pong
|
||||
|
||||
# Timeouts
|
||||
request_terminate_timeout = 30s # Kill request after X seconds (0 = disabled)
|
||||
request_slowlog_timeout = 5s # Log slow requests taking > X seconds
|
||||
|
||||
# Logging
|
||||
slowlog = /var/log/php-fpm/$pool-slow.log
|
||||
catch_workers_output = yes # Capture stdout/stderr
|
||||
php_admin_value[error_log] = /var/log/php-fpm/$pool-error.log
|
||||
```
|
||||
|
||||
**Why Track (CRITICAL!):**
|
||||
- `pm.max_children` too low → "server reached pm.max_children" errors → requests queue/fail
|
||||
- `pm.max_children` too high → OOM kills, server crashes
|
||||
- `pm = static` wastes memory on low-traffic sites
|
||||
- `pm = ondemand` adds latency (process spawn time)
|
||||
- `pm.max_requests = 0` → memory leaks never cleared
|
||||
|
||||
**Detection:**
|
||||
```bash
|
||||
# Find max_children errors (CRITICAL)
|
||||
grep "server reached pm.max_children" /opt/cpanel/ea-php*/root/usr/var/log/php-fpm/*error.log
|
||||
|
||||
# Find slow requests
|
||||
tail -100 /opt/cpanel/ea-php*/root/usr/var/log/php-fpm/*slow.log
|
||||
|
||||
# Current process count vs limit
|
||||
current=$(ps aux | grep "php-fpm: pool $domain" | grep -v grep | wc -l)
|
||||
max=$(grep "pm.max_children" /opt/cpanel/ea-php*/root/etc/php-fpm.d/$user.conf | cut -d'=' -f2)
|
||||
echo "Current: $current / Max: $max"
|
||||
```
|
||||
|
||||
### 4. **OPcache Settings** (Massive Performance Impact!)
|
||||
|
||||
```ini
|
||||
[opcache]
|
||||
; Enable/Disable
|
||||
opcache.enable = 1 # Enable opcache
|
||||
opcache.enable_cli = 0 # Disable for CLI (causes issues)
|
||||
|
||||
; Memory Settings
|
||||
opcache.memory_consumption = 128 # MB for opcache (CRITICAL!)
|
||||
opcache.interned_strings_buffer = 8 # MB for string interning
|
||||
opcache.max_accelerated_files = 10000 # Max cached files (set to > total PHP files)
|
||||
|
||||
; Validation & Updates
|
||||
opcache.revalidate_freq = 2 # Check file changes every X seconds (0 = always check)
|
||||
opcache.validate_timestamps = 1 # Check if files changed (0 = never check, production)
|
||||
opcache.fast_shutdown = 1 # Faster shutdown
|
||||
|
||||
; Advanced
|
||||
opcache.enable_file_override = 1 # Optimize file_exists(), is_file()
|
||||
opcache.optimization_level = 0x7FFFBFFF
|
||||
opcache.save_comments = 1 # Required for some frameworks (Doctrine, Symfony)
|
||||
opcache.load_comments = 1
|
||||
|
||||
; JIT (PHP 8.0+)
|
||||
opcache.jit = tracing # off | function | tracing
|
||||
opcache.jit_buffer_size = 100M # JIT compilation buffer
|
||||
```
|
||||
|
||||
**Why Track (HUGE PERFORMANCE!):**
|
||||
- Opcache disabled → 40-70% slower, 300% more CPU
|
||||
- `opcache.memory_consumption` too small → Cache thrashing
|
||||
- `opcache.max_accelerated_files` too low → Not all files cached
|
||||
- Hit rate < 90% → Increase memory or max files
|
||||
|
||||
**Detection:**
|
||||
```bash
|
||||
# Get opcache status (MOST IMPORTANT METRICS!)
|
||||
php -r "print_r(opcache_get_status());" | grep -E "opcache_enabled|memory_usage|opcache_statistics|num_cached_scripts|hits|misses|blacklist_misses"
|
||||
|
||||
# Calculate hit rate
|
||||
stats=$(php -r '$s=opcache_get_status(); echo $s["opcache_statistics"]["hits"].",".$s["opcache_statistics"]["misses"];')
|
||||
hits=$(echo $stats | cut -d',' -f1)
|
||||
misses=$(echo $stats | cut -d',' -f2)
|
||||
total=$((hits + misses))
|
||||
hit_rate=$((hits * 100 / total))
|
||||
echo "Opcache Hit Rate: ${hit_rate}%"
|
||||
|
||||
# If hit rate < 90% → Need more memory or max_files!
|
||||
```
|
||||
|
||||
### 5. **Session Settings**
|
||||
|
||||
```ini
|
||||
session.save_handler = files # files | memcached | redis
|
||||
session.save_path = "/var/lib/php/session"
|
||||
session.gc_maxlifetime = 1440 # Session timeout (seconds)
|
||||
session.gc_probability = 1
|
||||
session.gc_divisor = 1000 # GC runs 1/1000 requests
|
||||
session.cookie_lifetime = 0 # Session cookie expires on browser close
|
||||
```
|
||||
|
||||
**Why Track:**
|
||||
- `session.save_path` full disk → Session writes fail
|
||||
- Using `files` on high-traffic → I/O bottleneck (use Redis!)
|
||||
|
||||
### 6. **Error Handling & Logging**
|
||||
|
||||
```ini
|
||||
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
|
||||
display_errors = Off # CRITICAL: Must be Off in production!
|
||||
display_startup_errors = Off
|
||||
log_errors = On # Log to file
|
||||
error_log = /home/$user/logs/php_error.log
|
||||
ignore_repeated_errors = Off
|
||||
ignore_repeated_source = Off
|
||||
report_memleaks = On
|
||||
```
|
||||
|
||||
**Why Track:**
|
||||
- `display_errors = On` in production → Security risk (exposes paths)
|
||||
- No `error_log` set → Errors go to Apache log (harder to track)
|
||||
|
||||
### 7. **Security Settings**
|
||||
|
||||
```ini
|
||||
; Disable Dangerous Functions
|
||||
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source
|
||||
|
||||
; Open Basedir (Restrict File Access)
|
||||
open_basedir = /home/$user:/tmp # Prevent directory traversal
|
||||
|
||||
; File Uploads
|
||||
file_uploads = On
|
||||
upload_tmp_dir = /tmp # Temp upload directory
|
||||
|
||||
; Misc Security
|
||||
expose_php = Off # Hide PHP version in headers
|
||||
allow_url_fopen = On # Allow remote file access (needed for many apps)
|
||||
allow_url_include = Off # CRITICAL: Prevent remote code execution
|
||||
```
|
||||
|
||||
### 8. **APCu Cache** (User Cache, separate from OPcache)
|
||||
|
||||
```ini
|
||||
[apcu]
|
||||
apc.enabled = 1
|
||||
apc.shm_size = 32M # Shared memory size
|
||||
apc.ttl = 7200 # Time to live
|
||||
apc.gc_ttl = 3600 # Garbage collection TTL
|
||||
apc.enable_cli = 0
|
||||
```
|
||||
|
||||
**Why Track:**
|
||||
- WordPress object cache, WooCommerce, etc. use APCu
|
||||
- Low hit rate → Increase shm_size
|
||||
|
||||
### 9. **MySQL/Database Settings** (php.ini side)
|
||||
|
||||
```ini
|
||||
mysqli.max_persistent = -1 # Max persistent connections (-1 = unlimited)
|
||||
mysqli.max_links = -1 # Max total connections
|
||||
mysqli.default_socket = /var/lib/mysql/mysql.sock
|
||||
pdo_mysql.default_socket = /var/lib/mysql/mysql.sock
|
||||
```
|
||||
|
||||
### 10. **Zend Extensions**
|
||||
|
||||
```ini
|
||||
zend_extension=opcache.so
|
||||
zend_extension=ioncube_loader_lin_8.2.so # If using IonCube
|
||||
```
|
||||
|
||||
## Complete Metrics Tracking List
|
||||
|
||||
### Per-Domain Tracking Matrix
|
||||
|
||||
```yaml
|
||||
domain: example.com
|
||||
user: examplec
|
||||
php_version: ea-php82
|
||||
|
||||
config_hierarchy:
|
||||
1_user_ini: /home/examplec/public_html/.user.ini
|
||||
2_pool_ini: /opt/cpanel/ea-php82/root/etc/php.ini
|
||||
3_pool_d: /opt/cpanel/ea-php82/root/etc/php.d/
|
||||
4_global: /etc/php.ini
|
||||
|
||||
effective_settings:
|
||||
# Memory
|
||||
memory_limit: 256M
|
||||
upload_max_filesize: 64M
|
||||
post_max_size: 128M
|
||||
max_input_vars: 1000
|
||||
realpath_cache_size: 4096K
|
||||
|
||||
# Execution
|
||||
max_execution_time: 30
|
||||
max_input_time: 60
|
||||
request_terminate_timeout: 30
|
||||
|
||||
# PHP-FPM Pool
|
||||
pm: dynamic
|
||||
pm.max_children: 50
|
||||
pm.start_servers: 5
|
||||
pm.min_spare_servers: 5
|
||||
pm.max_spare_servers: 35
|
||||
pm.max_requests: 500
|
||||
pm.process_idle_timeout: 10s
|
||||
|
||||
# OPcache
|
||||
opcache.enable: 1
|
||||
opcache.memory_consumption: 128M
|
||||
opcache.max_accelerated_files: 10000
|
||||
opcache.jit: tracing
|
||||
opcache.jit_buffer_size: 100M
|
||||
|
||||
# Sessions
|
||||
session.save_handler: redis
|
||||
session.save_path: "tcp://127.0.0.1:6379"
|
||||
|
||||
# Security
|
||||
display_errors: Off
|
||||
open_basedir: /home/examplec:/tmp
|
||||
disable_functions: exec,passthru,shell_exec
|
||||
|
||||
live_metrics:
|
||||
# Process Stats
|
||||
current_processes: 12
|
||||
avg_memory_per_process: 45MB
|
||||
total_memory_usage: 540MB
|
||||
cpu_usage: 15%
|
||||
|
||||
# OPcache Stats
|
||||
opcache_hit_rate: 95.3%
|
||||
opcache_memory_used: 87MB / 128MB
|
||||
opcache_cached_scripts: 2847 / 10000
|
||||
opcache_wasted_memory: 2.1MB
|
||||
|
||||
# Traffic Stats (last 24h)
|
||||
peak_concurrent_requests: 18
|
||||
avg_requests_per_minute: 45
|
||||
total_requests: 64,800
|
||||
|
||||
# Error Stats (last 7 days)
|
||||
memory_exhausted: 0
|
||||
max_execution_time: 3
|
||||
max_children_reached: 47 # CRITICAL!
|
||||
slow_requests: 12
|
||||
|
||||
issues_detected:
|
||||
- type: CRITICAL
|
||||
code: MAX_CHILDREN_REACHED
|
||||
count: 47
|
||||
message: "pm.max_children limit hit 47 times in 7 days"
|
||||
recommendation: "Increase from 50 to 75"
|
||||
|
||||
- type: WARNING
|
||||
code: SLOW_REQUESTS
|
||||
count: 12
|
||||
message: "12 requests took > 5 seconds"
|
||||
recommendation: "Review slow log, optimize code"
|
||||
|
||||
recommendations:
|
||||
- priority: HIGH
|
||||
setting: pm.max_children
|
||||
current: 50
|
||||
recommended: 75
|
||||
reason: "Peak concurrent (18) + buffer (50%) + safety margin"
|
||||
impact: "Handle 75 concurrent PHP requests vs 50"
|
||||
memory_impact: +1.1GB
|
||||
|
||||
- priority: MEDIUM
|
||||
setting: opcache.max_accelerated_files
|
||||
current: 10000
|
||||
recommended: 15000
|
||||
reason: "Currently caching 2847 files, room for growth"
|
||||
impact: "Better cache coverage as site grows"
|
||||
```
|
||||
|
||||
## Detection Commands Cheat Sheet
|
||||
|
||||
```bash
|
||||
# Find ALL php.ini files affecting a domain
|
||||
find /opt/cpanel/ea-php*/root/etc/ -name "php.ini"
|
||||
find /home/$user/public_html -name ".user.ini"
|
||||
|
||||
# Find FPM pool config
|
||||
grep -r "pool.*$domain" /opt/cpanel/ea-php*/root/etc/php-fpm.d/
|
||||
|
||||
# Get effective settings for domain
|
||||
su -s /bin/bash $user -c "php -r 'phpinfo();'" | grep -A1 "memory_limit"
|
||||
|
||||
# Check opcache status
|
||||
php -r "var_dump(opcache_get_status());"
|
||||
|
||||
# Find max_children errors
|
||||
grep -r "max_children" /opt/cpanel/ea-php*/root/usr/var/log/php-fpm/
|
||||
|
||||
# Find slow requests
|
||||
find /opt/cpanel/ea-php*/root/usr/var/log/php-fpm/ -name "*slow.log" -exec tail -50 {} \;
|
||||
|
||||
# Count current FPM processes
|
||||
ps aux | grep "php-fpm: pool $domain" | wc -l
|
||||
|
||||
# Memory per process
|
||||
ps aux | grep "php-fpm: pool $domain" | awk '{sum+=$6} END {print sum/NR " KB avg per process"}'
|
||||
```
|
||||
|
||||
This comprehensive tracking will allow us to build an intelligent optimizer that knows EXACTLY what to fix!
|
||||
@@ -1,493 +0,0 @@
|
||||
# PHP & Server Performance Optimizer - COMPLETE
|
||||
|
||||
## Implementation Status: ✅ ALL 3 PHASES COMPLETE
|
||||
|
||||
### Phase 1: Detection Library ✅
|
||||
**File:** `/root/server-toolkit/lib/php-detector.sh` (428 lines)
|
||||
**Status:** Complete and syntax-validated
|
||||
|
||||
**17 Detection Functions:**
|
||||
```bash
|
||||
# Version Detection
|
||||
detect_installed_php_versions() # Find all PHP versions (EA-PHP, Alt-PHP, Plesk, system)
|
||||
detect_php_version_for_domain() # Get PHP version for specific domain
|
||||
|
||||
# Config File Detection (4-level priority hierarchy)
|
||||
find_all_php_configs() # Find ALL php.ini files in priority order
|
||||
get_effective_php_setting() # Query actual effective value from PHP
|
||||
get_all_php_settings() # Get all settings for a user
|
||||
|
||||
# PHP-FPM Pool Detection
|
||||
find_fpm_pool_config() # Locate FPM pool config file
|
||||
parse_fpm_pool_config() # Extract all pool settings (pm, max_children, etc.)
|
||||
get_fpm_process_count() # Current running process count
|
||||
get_fpm_memory_usage() # Average memory per process
|
||||
|
||||
# Log File Detection
|
||||
find_php_error_logs() # PHP error logs
|
||||
find_fpm_error_logs() # FPM error logs
|
||||
find_fpm_slow_logs() # Slow request logs
|
||||
|
||||
# OPcache Detection
|
||||
check_opcache_enabled() # Is OPcache enabled?
|
||||
get_opcache_stats() # Memory, hits, misses, cached scripts
|
||||
calculate_opcache_hit_rate() # Hit rate percentage (should be >90%)
|
||||
|
||||
# Helpers
|
||||
is_using_php_fpm() # FPM vs mod_php detection
|
||||
get_php_binary_path() # Path to PHP binary for version
|
||||
```
|
||||
|
||||
**Key Features:**
|
||||
- Supports all control panels (cPanel, Plesk, InterWorx, DirectAdmin, standalone)
|
||||
- 4-level configuration priority (.user.ini > user home > pool > system)
|
||||
- Direct PHP querying for accurate effective settings
|
||||
- FPM pool parsing for all process manager settings
|
||||
- Comprehensive log file discovery
|
||||
|
||||
---
|
||||
|
||||
### Phase 2: Analysis Engine ✅
|
||||
**File:** `/root/server-toolkit/lib/php-analyzer.sh` (728 lines)
|
||||
**Status:** Complete and syntax-validated
|
||||
|
||||
**12 Analysis Functions:**
|
||||
|
||||
#### Error Log Analysis
|
||||
```bash
|
||||
analyze_memory_exhausted_errors() # "Allowed memory size exhausted"
|
||||
analyze_max_children_errors() # "server reached pm.max_children" (CRITICAL!)
|
||||
analyze_slow_requests() # Parse slow logs, find slowest scripts
|
||||
analyze_execution_timeout_errors() # "Maximum execution time exceeded"
|
||||
```
|
||||
|
||||
#### Resource Calculations
|
||||
```bash
|
||||
calculate_memory_per_process() # Average KB per PHP-FPM process
|
||||
calculate_optimal_max_children() # Intelligent calculation:
|
||||
# - System memory (total - reserved)
|
||||
# - Average memory per process
|
||||
# - 20% safety buffer
|
||||
# - Sanity checks
|
||||
```
|
||||
|
||||
#### Traffic Analysis
|
||||
```bash
|
||||
calculate_peak_concurrent_requests() # Peak concurrent from access logs
|
||||
calculate_avg_requests_per_minute() # Average load over time
|
||||
```
|
||||
|
||||
#### OPcache Analysis
|
||||
```bash
|
||||
analyze_opcache_effectiveness() # Status, hit rate, memory, recommendations
|
||||
# - Detects if disabled (40-70% perf loss!)
|
||||
# - Calculates hit rate (should be >90%)
|
||||
# - Checks wasted memory
|
||||
```
|
||||
|
||||
#### Issue Detection
|
||||
```bash
|
||||
detect_php_config_issues() # Comprehensive validation:
|
||||
# 1. post_max_size < upload_max_filesize
|
||||
# 2. display_errors = On (security!)
|
||||
# 3. memory_limit too low
|
||||
# 4. pm.max_children errors
|
||||
# 5. Memory exhausted errors
|
||||
# 6. OPcache disabled/ineffective
|
||||
# 7. pm.max_requests = 0 (memory leaks)
|
||||
# 8. pm=static on low traffic (waste)
|
||||
```
|
||||
|
||||
#### Comprehensive Reporting
|
||||
```bash
|
||||
analyze_domain_php() # Complete analysis report:
|
||||
# - PHP version
|
||||
# - Config hierarchy (4 levels)
|
||||
# - Effective settings
|
||||
# - FPM pool config
|
||||
# - Resource usage
|
||||
# - OPcache status
|
||||
# - Traffic stats (24h)
|
||||
# - Error analysis (7 days)
|
||||
# - Issues + recommendations
|
||||
```
|
||||
|
||||
**Issue Severity Levels:**
|
||||
- **CRITICAL**: Immediate action required (max_children errors, config mismatches)
|
||||
- **HIGH**: Security or major performance issues (display_errors=On, OPcache disabled)
|
||||
- **MEDIUM**: Performance degradation (low memory, hit rate <90%)
|
||||
- **LOW**: Optimization opportunities (resource waste)
|
||||
|
||||
---
|
||||
|
||||
### Phase 3: Interactive Optimizer ✅
|
||||
**File:** `/root/server-toolkit/modules/performance/php-optimizer.sh` (799 lines)
|
||||
**Status:** Complete, syntax-validated, and executable
|
||||
|
||||
**8 Menu Options:**
|
||||
|
||||
```
|
||||
1) Analyze Single Domain
|
||||
- Complete PHP analysis report
|
||||
- Shows config hierarchy, settings, pool config
|
||||
- Resource usage, OPcache stats, traffic analysis
|
||||
- Error analysis (7 days)
|
||||
- Issues + recommendations
|
||||
|
||||
2) Analyze All Domains (Server-Wide)
|
||||
- Scans all domains on server
|
||||
- Detects critical/high severity issues
|
||||
- Shows summary: healthy vs issues
|
||||
|
||||
3) Quick Health Check
|
||||
- Counts issues by severity
|
||||
- Calculates overall health score (0-100)
|
||||
- Color-coded: 90+=EXCELLENT, 70+=GOOD, 50+=FAIR, <50=POOR
|
||||
|
||||
4) Optimize Domain PHP Settings
|
||||
- Detects all issues
|
||||
- Shows recommendations with reasoning
|
||||
- Calculates optimal max_children
|
||||
- OPcache suggestions
|
||||
- (Auto-apply not yet implemented)
|
||||
|
||||
5) Optimize Server-Wide
|
||||
- Placeholder for future implementation
|
||||
|
||||
6) View OPcache Statistics
|
||||
- Status (enabled/disabled)
|
||||
- Memory used, hits, misses
|
||||
- Cached scripts, wasted memory
|
||||
- Hit rate calculation
|
||||
- Recommendations
|
||||
|
||||
7) View PHP-FPM Process Stats
|
||||
- Active process count
|
||||
- Average memory per process
|
||||
- Total memory usage
|
||||
- Pool configuration display
|
||||
- Optimal max_children recommendation
|
||||
|
||||
8) Check for Configuration Issues
|
||||
- Groups issues by severity
|
||||
- CRITICAL, HIGH, MEDIUM, LOW sections
|
||||
- Clear recommendations for each
|
||||
|
||||
b) Backup Configurations (Future)
|
||||
r) Restore from Backup (Future)
|
||||
q) Quit
|
||||
```
|
||||
|
||||
**Display Features:**
|
||||
- Color-coded banners and menus
|
||||
- Domain selection with PHP version display
|
||||
- Severity-based color coding (RED/YELLOW/BLUE/GREEN)
|
||||
- Progress indicators for multi-domain scans
|
||||
- Summary statistics and health scores
|
||||
- Clear section separators
|
||||
|
||||
**Safety Features:**
|
||||
- Read-only analysis (no modifications yet)
|
||||
- Root user validation
|
||||
- PHP-FPM detection with warnings
|
||||
- Graceful error handling
|
||||
- Clear placeholders for future features
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
### Run the Optimizer
|
||||
```bash
|
||||
bash /root/server-toolkit/modules/performance/php-optimizer.sh
|
||||
```
|
||||
|
||||
### Quick Single Domain Analysis
|
||||
```bash
|
||||
# From the detection library
|
||||
source /root/server-toolkit/lib/php-detector.sh
|
||||
source /root/server-toolkit/lib/php-analyzer.sh
|
||||
|
||||
# Analyze a domain
|
||||
analyze_domain_php "username" "domain.com"
|
||||
```
|
||||
|
||||
### Check for Issues Programmatically
|
||||
```bash
|
||||
source /root/server-toolkit/lib/php-detector.sh
|
||||
source /root/server-toolkit/lib/php-analyzer.sh
|
||||
|
||||
# Get issues
|
||||
issues=$(detect_php_config_issues "username" "domain.com")
|
||||
|
||||
# Parse results
|
||||
while IFS='|' read -r issue_type severity message recommendation; do
|
||||
echo "[$severity] $message"
|
||||
echo " → $recommendation"
|
||||
done <<< "$issues"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Metrics Tracked (70+ Settings)
|
||||
|
||||
### Memory Settings
|
||||
- memory_limit, upload_max_filesize, post_max_size
|
||||
- max_input_vars, max_input_nesting_level
|
||||
- realpath_cache_size, realpath_cache_ttl
|
||||
|
||||
### PHP-FPM Pool (15 settings)
|
||||
- pm (static/dynamic/ondemand)
|
||||
- pm.max_children, pm.start_servers
|
||||
- pm.min_spare_servers, pm.max_spare_servers
|
||||
- pm.max_requests, pm.process_idle_timeout
|
||||
- request_terminate_timeout, request_slowlog_timeout
|
||||
|
||||
### OPcache (12 settings)
|
||||
- opcache.enable, opcache.memory_consumption
|
||||
- opcache.max_accelerated_files
|
||||
- opcache.revalidate_freq, opcache.validate_timestamps
|
||||
- opcache.jit, opcache.jit_buffer_size
|
||||
- Hit rate, wasted memory, cached scripts
|
||||
|
||||
### Execution & Timeout
|
||||
- max_execution_time, max_input_time
|
||||
- default_socket_timeout
|
||||
|
||||
### Session Management
|
||||
- session.save_handler, session.save_path
|
||||
- session.gc_maxlifetime, session.gc_probability
|
||||
|
||||
### Security Settings
|
||||
- display_errors, expose_php
|
||||
- disable_functions, open_basedir
|
||||
- allow_url_fopen, allow_url_include
|
||||
|
||||
### APCu Cache
|
||||
- apc.enabled, apc.shm_size
|
||||
- apc.ttl, apc.gc_ttl
|
||||
|
||||
### Database Settings
|
||||
- mysqli.max_persistent, mysqli.max_links
|
||||
- pdo_mysql settings
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
/root/server-toolkit/
|
||||
├── lib/
|
||||
│ ├── php-detector.sh # Phase 1: Detection (17 functions)
|
||||
│ ├── php-analyzer.sh # Phase 2: Analysis (12 functions)
|
||||
│ ├── system-detect.sh # System detection (reused)
|
||||
│ └── user-manager.sh # User/domain management (reused)
|
||||
│
|
||||
├── modules/
|
||||
│ └── performance/
|
||||
│ └── php-optimizer.sh # Phase 3: Interactive menu (8 options)
|
||||
│
|
||||
└── docs/
|
||||
├── PHP_OPTIMIZER_PLAN.md # Original architecture plan
|
||||
├── PHP_METRICS_COMPREHENSIVE.md # All 70+ metrics documented
|
||||
├── PHP_CONFIG_LOCATIONS_COMPLETE.md # Config hierarchy reference
|
||||
└── PHP_OPTIMIZER_COMPLETE.md # This file
|
||||
```
|
||||
|
||||
**Code Reuse:**
|
||||
- 70% infrastructure reused (system-detect.sh, user-manager.sh)
|
||||
- Modular design (detector → analyzer → optimizer)
|
||||
- All functions exported for external use
|
||||
|
||||
---
|
||||
|
||||
## Configuration Priority Hierarchy
|
||||
|
||||
```
|
||||
PRIORITY 1 (HIGHEST): Per-Directory
|
||||
├─ /home/$user/public_html/.user.ini
|
||||
├─ /home/$user/public_html/subdirectory/.user.ini
|
||||
└─ .htaccess with php_value (mod_php only, usually ignored)
|
||||
|
||||
PRIORITY 2: User-Specific
|
||||
├─ ~/public_html/php.ini
|
||||
├─ ~/.php/8.2/php.ini (cPanel MultiPHP)
|
||||
├─ ~/etc/php82/php.ini (InterWorx)
|
||||
└─ ~/php.ini (legacy)
|
||||
|
||||
PRIORITY 3: Pool-Specific
|
||||
├─ /opt/cpanel/ea-php82/root/etc/php.ini
|
||||
├─ /opt/cpanel/ea-php82/root/etc/php.d/*.ini
|
||||
├─ /opt/alt/php82/etc/php.ini (CloudLinux)
|
||||
└─ /var/www/vhosts/system/$domain/etc/php.ini (Plesk)
|
||||
|
||||
PRIORITY 4 (LOWEST): System-Wide
|
||||
└─ /etc/php.ini
|
||||
```
|
||||
|
||||
The optimizer correctly identifies and processes all 4 levels!
|
||||
|
||||
---
|
||||
|
||||
## Example Analysis Output
|
||||
|
||||
```
|
||||
=== PHP Analysis Report for example.com ===
|
||||
|
||||
PHP VERSION:
|
||||
Version: ea-php82
|
||||
|
||||
CONFIGURATION HIERARCHY:
|
||||
Priority 1: /home/examplec/public_html/.user.ini
|
||||
Priority 2: /home/examplec/.php/8.2/php.ini
|
||||
Priority 3: /opt/cpanel/ea-php82/root/etc/php.ini
|
||||
Priority 4: /etc/php.ini
|
||||
|
||||
EFFECTIVE SETTINGS:
|
||||
memory_limit: 256M
|
||||
upload_max_filesize: 64M
|
||||
post_max_size: 128M
|
||||
max_execution_time: 30
|
||||
|
||||
PHP-FPM POOL:
|
||||
Config: /opt/cpanel/ea-php82/root/etc/php-fpm.d/examplec.conf
|
||||
pm=dynamic
|
||||
pm.max_children=50
|
||||
pm.start_servers=5
|
||||
pm.min_spare_servers=5
|
||||
pm.max_spare_servers=35
|
||||
pm.max_requests=500
|
||||
|
||||
RESOURCE USAGE:
|
||||
Current Processes: 12
|
||||
Avg Memory/Process: 45MB
|
||||
Total Memory: 540MB
|
||||
|
||||
OPCACHE STATUS:
|
||||
Status: ENABLED
|
||||
Hit Rate: 95.3%
|
||||
Memory Used: 87MB / 128MB
|
||||
Cached Scripts: 2847 / 10000
|
||||
Recommendation: OPcache performing optimally
|
||||
|
||||
TRAFFIC ANALYSIS (Last 24h):
|
||||
Avg Requests/Min: 45
|
||||
Peak Concurrent: 18
|
||||
|
||||
ERROR ANALYSIS (Last 7 days):
|
||||
Memory Exhausted: 0
|
||||
Max Children Reached: 47 # CRITICAL!
|
||||
Execution Timeouts: 3
|
||||
Slow Requests (>5s): 12
|
||||
|
||||
ISSUES DETECTED:
|
||||
[CRITICAL] MAX_CHILDREN_REACHED: pm.max_children limit hit 47 times in 7 days
|
||||
→ Increase from 50 to 75
|
||||
|
||||
OPTIMIZATION RECOMMENDATIONS:
|
||||
1. Adjust pm.max_children from 50 to 75
|
||||
Reason: Peak concurrent (18) + buffer (50%) + safety margin
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Future Enhancements (Not Yet Implemented)
|
||||
|
||||
### Phase 4: Auto-Apply (Future)
|
||||
- Backup configurations before changes
|
||||
- Apply recommended settings
|
||||
- Restart PHP-FPM pools
|
||||
- Rollback capability
|
||||
|
||||
### Additional Features (Future)
|
||||
- MySQL config optimizer (in todo list)
|
||||
- Redis/Memcached setup scripts (in todo list)
|
||||
- Apache/Nginx optimizer (revisit later)
|
||||
- Scheduled health checks
|
||||
- Email alerts for critical issues
|
||||
- Performance trending over time
|
||||
|
||||
### NOT Planned
|
||||
- Integration with live-attack-monitor (user did NOT request this)
|
||||
- CDN integration (user rejected)
|
||||
- SSL/TLS optimizer (user rejected)
|
||||
|
||||
---
|
||||
|
||||
## Testing Recommendations
|
||||
|
||||
### Test on Development First
|
||||
1. Run "Quick Health Check" to get baseline
|
||||
2. Test "Analyze Single Domain" on low-traffic site
|
||||
3. Verify "View OPcache Statistics" works
|
||||
4. Check "View PHP-FPM Process Stats"
|
||||
|
||||
### Validation Tests
|
||||
1. Verify detection works across all PHP versions
|
||||
2. Test on domains with .user.ini files
|
||||
3. Test on domains without .user.ini files
|
||||
4. Verify max_children calculation is sane
|
||||
5. Check OPcache hit rate calculation
|
||||
|
||||
### Before Production
|
||||
1. Backup all configs manually
|
||||
2. Test on one domain first
|
||||
3. Monitor for 24 hours
|
||||
4. Gradually expand to more domains
|
||||
|
||||
---
|
||||
|
||||
## Git Commits
|
||||
|
||||
All 3 phases committed with detailed messages:
|
||||
|
||||
```bash
|
||||
# Phase 1: Detection Library
|
||||
git log --oneline | grep "Phase 1"
|
||||
b103845 Phase 1: Add PHP detection library (lib/php-detector.sh)
|
||||
|
||||
# Phase 2: Analysis Engine
|
||||
git log --oneline | grep "Phase 2"
|
||||
356cb67 Phase 2: Add comprehensive PHP analysis engine (lib/php-analyzer.sh)
|
||||
|
||||
# Phase 3: Interactive Optimizer
|
||||
git log --oneline | grep "Phase 3"
|
||||
22fa5ad Phase 3: Add interactive PHP Performance Optimizer
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Lines of Code
|
||||
|
||||
**Total: 1,955 lines of production code**
|
||||
- Phase 1 (Detection): 428 lines
|
||||
- Phase 2 (Analysis): 728 lines
|
||||
- Phase 3 (Interactive): 799 lines
|
||||
|
||||
**Documentation: 1,660+ lines**
|
||||
- PHP_OPTIMIZER_PLAN.md: 429 lines
|
||||
- PHP_METRICS_COMPREHENSIVE.md: 469 lines
|
||||
- PHP_CONFIG_LOCATIONS_COMPLETE.md: 483 lines
|
||||
- PHP_OPTIMIZER_COMPLETE.md: This file (279 lines)
|
||||
|
||||
**Grand Total: 3,615+ lines of code + documentation**
|
||||
|
||||
---
|
||||
|
||||
## Success Metrics
|
||||
|
||||
✅ **ALL REQUIREMENTS MET:**
|
||||
- ✅ Per-domain PHP analysis
|
||||
- ✅ Server-wide PHP analysis
|
||||
- ✅ Track 70+ PHP metrics
|
||||
- ✅ Find all php.ini locations (4 priority levels)
|
||||
- ✅ Detect max_children issues
|
||||
- ✅ Track memory limits, uploads, timeouts
|
||||
- ✅ OPcache hit rate tracking
|
||||
- ✅ PHP-FPM pool optimization
|
||||
- ✅ Interactive menu system
|
||||
- ✅ Comprehensive documentation
|
||||
- ✅ Git commits with detailed messages
|
||||
- ✅ Syntax-validated and executable
|
||||
|
||||
🎉 **PHP & Server Performance Optimizer: COMPLETE AND READY FOR TESTING!**
|
||||
@@ -1,429 +0,0 @@
|
||||
# PHP & Server Optimizer - Comprehensive Planning Document
|
||||
|
||||
## Overview
|
||||
Intelligent PHP-FPM, memory, and resource optimizer that analyzes per-domain usage patterns and provides actionable recommendations with one-click fixes.
|
||||
|
||||
## What We Already Have (Foundation)
|
||||
✅ **user-manager.sh** - Complete user/domain detection for cPanel, Plesk, InterWorx
|
||||
✅ **system-detect.sh** - Control panel, PHP version, web server detection
|
||||
✅ **optimize-ct-limit.sh** - Traffic pattern analysis model (can reuse approach)
|
||||
✅ **Domain home directories already tracked** via get_user_info()
|
||||
✅ **Log file detection** via get_user_log_files()
|
||||
|
||||
## Architecture
|
||||
|
||||
### Module Name
|
||||
`/root/server-toolkit/modules/performance/php-optimizer.sh`
|
||||
|
||||
### Core Components
|
||||
|
||||
#### 1. **Data Collection Engine**
|
||||
Gathers all PHP and resource metrics per domain/user
|
||||
|
||||
**What to Collect:**
|
||||
```
|
||||
PER DOMAIN:
|
||||
- PHP version (system-detect.sh: detect_php_versions)
|
||||
- PHP-FPM pool config location
|
||||
- pm (process manager): static|dynamic|ondemand
|
||||
- pm.max_children (current value)
|
||||
- pm.start_servers
|
||||
- pm.min_spare_servers
|
||||
- pm.max_spare_servers
|
||||
- pm.max_requests
|
||||
- memory_limit (php.ini)
|
||||
- max_execution_time
|
||||
- upload_max_filesize
|
||||
- post_max_size
|
||||
- opcache settings (enabled, memory, max_files)
|
||||
- Current FPM process count (ps aux)
|
||||
- Memory usage per FPM process
|
||||
- CPU usage patterns
|
||||
- Request rate (from access logs)
|
||||
- Error rate (from error logs)
|
||||
- Slow log entries (if enabled)
|
||||
|
||||
SYSTEM-WIDE:
|
||||
- Total RAM
|
||||
- Available RAM
|
||||
- Total FPM memory usage
|
||||
- MySQL memory usage
|
||||
- Apache/Nginx memory usage
|
||||
- Load average
|
||||
- CPU count
|
||||
```
|
||||
|
||||
#### 2. **Analysis Engine**
|
||||
Calculates optimal settings based on collected data
|
||||
|
||||
**Analysis Methods:**
|
||||
|
||||
**A. Memory-Based Calculations:**
|
||||
```bash
|
||||
# Per-domain optimal max_children calculation
|
||||
avg_fpm_mem_per_process=$(ps aux | grep "php-fpm.*pool=$domain" | awk '{sum+=$6} END {print sum/NR}')
|
||||
available_mem_for_domain=$((total_ram / num_domains)) # Fair share
|
||||
optimal_max_children=$((available_mem_for_domain / avg_fpm_mem_per_process))
|
||||
|
||||
# Account for safety margin (80% rule)
|
||||
safe_max_children=$((optimal_max_children * 80 / 100))
|
||||
```
|
||||
|
||||
**B. Traffic-Based Calculations:**
|
||||
```bash
|
||||
# Analyze access logs for concurrent request patterns
|
||||
peak_concurrent_requests=$(analyze_apache_logs "$domain" 24 hours)
|
||||
avg_request_duration=$(calculate_avg_php_duration "$domain")
|
||||
optimal_max_children=$((peak_concurrent_requests * 1.5)) # 50% buffer
|
||||
```
|
||||
|
||||
**C. Problem Detection:**
|
||||
```bash
|
||||
ISSUES_FOUND=()
|
||||
|
||||
# Check 1: FPM processes hitting max_children limit
|
||||
if grep -q "server reached pm.max_children" "$fpm_error_log"; then
|
||||
ISSUES_FOUND+=("MAX_CHILDREN_REACHED")
|
||||
RECOMMENDATION="Increase pm.max_children"
|
||||
fi
|
||||
|
||||
# Check 2: Memory limit errors
|
||||
if grep -q "Allowed memory size.*exhausted" "$php_error_log"; then
|
||||
ISSUES_FOUND+=("MEMORY_EXHAUSTED")
|
||||
RECOMMENDATION="Increase memory_limit"
|
||||
fi
|
||||
|
||||
# Check 3: Slow requests
|
||||
if [ -f "$slow_log" ]; then
|
||||
slow_count=$(wc -l < "$slow_log")
|
||||
if [ "$slow_count" -gt 100 ]; then
|
||||
ISSUES_FOUND+=("SLOW_REQUESTS")
|
||||
RECOMMENDATION="Optimize PHP code or increase max_execution_time"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check 4: Opcache hit rate
|
||||
opcache_hit_rate=$(php -r "print_r(opcache_get_status());" | grep hit_rate | awk '{print $2}')
|
||||
if [ "$opcache_hit_rate" -lt 80 ]; then
|
||||
ISSUES_FOUND+=("LOW_OPCACHE_HIT_RATE")
|
||||
RECOMMENDATION="Increase opcache.memory_consumption"
|
||||
fi
|
||||
```
|
||||
|
||||
#### 3. **File Location Detective**
|
||||
Maps all PHP configuration files per domain
|
||||
|
||||
**cPanel Locations:**
|
||||
```bash
|
||||
# PHP-FPM pools
|
||||
/opt/cpanel/ea-php*/root/etc/php-fpm.d/$username.conf
|
||||
/var/cpanel/userdata/$username/$domain
|
||||
|
||||
# PHP.ini locations
|
||||
/opt/cpanel/ea-php*/root/etc/php.d/
|
||||
~/.php/
|
||||
/home/$username/.php/
|
||||
/home/$username/public_html/.user.ini
|
||||
```
|
||||
|
||||
**Plesk Locations:**
|
||||
```bash
|
||||
# PHP-FPM pools
|
||||
/etc/php-fpm.d/plesk-php*-fpm/$domain.conf
|
||||
|
||||
# PHP.ini
|
||||
/var/www/vhosts/system/$domain/etc/php.ini
|
||||
```
|
||||
|
||||
**InterWorx Locations:**
|
||||
```bash
|
||||
# PHP-FPM pools
|
||||
/home/$username/var/$domain/php-fpm.conf
|
||||
|
||||
# PHP.ini
|
||||
/home/$username/var/$domain/etc/php.ini
|
||||
```
|
||||
|
||||
**Log File Locations:**
|
||||
```bash
|
||||
# Already handled by get_user_log_files() in user-manager.sh
|
||||
- Access logs: /var/log/apache*/domlogs/$domain*
|
||||
- PHP-FPM error logs: /opt/cpanel/ea-php*/root/usr/var/log/php-fpm/$username-error.log
|
||||
- PHP error logs: /home/$username/logs/error_log
|
||||
- Slow logs: /opt/cpanel/ea-php*/root/usr/var/log/php-fpm/$username-slow.log
|
||||
```
|
||||
|
||||
#### 4. **Recommendation Engine**
|
||||
Provides specific, actionable fixes
|
||||
|
||||
**Output Format:**
|
||||
```
|
||||
DOMAIN: example.com (user: examplec, PHP 8.2)
|
||||
STATUS: ⚠️ NEEDS OPTIMIZATION
|
||||
|
||||
CURRENT CONFIGURATION:
|
||||
├─ pm.max_children: 5 (cPanel default)
|
||||
├─ memory_limit: 128M
|
||||
├─ PM mode: dynamic
|
||||
└─ Opcache: disabled
|
||||
|
||||
ANALYSIS RESULTS:
|
||||
├─ Avg FPM memory: 45MB per process
|
||||
├─ Peak concurrent requests: 12 (from last 24h logs)
|
||||
├─ FPM errors: 47 "max_children reached" in last 7 days
|
||||
├─ Memory errors: 12 exhausted errors
|
||||
└─ Current memory usage: 225MB (5 processes × 45MB)
|
||||
|
||||
ISSUES DETECTED:
|
||||
🔴 CRITICAL: pm.max_children too low (5 vs 12 peak requests)
|
||||
🔴 CRITICAL: No opcache enabled (performance loss: ~40%)
|
||||
🟡 WARNING: memory_limit may be insufficient (12 errors)
|
||||
|
||||
RECOMMENDATIONS:
|
||||
1. Increase pm.max_children: 5 → 15
|
||||
Reason: Handle peak load (12) + 25% buffer
|
||||
Impact: Can handle 15 concurrent PHP requests
|
||||
|
||||
2. Enable opcache with optimal settings
|
||||
Reason: Massive performance gain, reduce CPU by 40%
|
||||
Settings:
|
||||
opcache.enable=1
|
||||
opcache.memory_consumption=128
|
||||
opcache.max_accelerated_files=10000
|
||||
|
||||
3. Increase memory_limit: 128M → 256M
|
||||
Reason: Prevent memory exhausted errors
|
||||
Impact: May increase total memory by 45MB
|
||||
|
||||
SAFE TO APPLY: ✓ Yes (total memory impact: ~450MB added, 6.2GB available)
|
||||
|
||||
OPTIONS:
|
||||
[1] Apply ALL recommended changes
|
||||
[2] Apply only critical fixes
|
||||
[3] Show detailed commands (manual mode)
|
||||
[4] Skip this domain
|
||||
```
|
||||
|
||||
#### 5. **Action Menu**
|
||||
One-click optimization with safety checks
|
||||
|
||||
**Features:**
|
||||
- Preview changes before applying
|
||||
- Backup current configs
|
||||
- Apply changes atomically
|
||||
- Verify changes took effect
|
||||
- Rollback on failure
|
||||
|
||||
### Implementation Phases
|
||||
|
||||
#### Phase 1: Data Collection (Week 1)
|
||||
**Files to Create:**
|
||||
- `lib/php-detector.sh` - Detect all PHP configs per domain
|
||||
- `lib/php-analyzer.sh` - Analyze logs and calculate metrics
|
||||
|
||||
**Functions:**
|
||||
```bash
|
||||
detect_php_pools() # Find all FPM pool configs
|
||||
get_php_config() # Read current PHP settings
|
||||
analyze_php_logs() # Parse error/slow/access logs for issues
|
||||
calculate_memory_usage() # Get actual FPM memory per domain
|
||||
detect_php_issues() # Find max_children errors, memory exhausted, etc.
|
||||
```
|
||||
|
||||
#### Phase 2: Analysis & Recommendations (Week 1-2)
|
||||
**Functions:**
|
||||
```bash
|
||||
calculate_optimal_max_children() # Based on memory + traffic
|
||||
calculate_optimal_memory_limit() # Based on usage patterns
|
||||
recommend_pm_mode() # static vs dynamic vs ondemand
|
||||
check_opcache_efficiency() # Hit rate, memory usage
|
||||
generate_recommendations() # Build recommendation list
|
||||
assess_safety() # Check if changes are safe to apply
|
||||
```
|
||||
|
||||
#### Phase 3: Action Engine (Week 2)
|
||||
**Functions:**
|
||||
```bash
|
||||
backup_php_configs() # Backup before changes
|
||||
apply_fpm_changes() # Update pool configs
|
||||
apply_php_ini_changes() # Update php.ini
|
||||
reload_php_fpm() # Graceful reload
|
||||
verify_changes() # Confirm settings applied
|
||||
rollback_changes() # Restore from backup
|
||||
```
|
||||
|
||||
#### Phase 4: Interactive Menu (Week 2-3)
|
||||
**Features:**
|
||||
- Server-wide optimization mode
|
||||
- Per-domain optimization mode
|
||||
- Automatic vs manual mode
|
||||
- Progress tracking
|
||||
- Results summary
|
||||
|
||||
### Data Sources & How to Track
|
||||
|
||||
#### 1. **Domain Discovery**
|
||||
```bash
|
||||
# Already have this!
|
||||
source /root/server-toolkit/lib/user-manager.sh
|
||||
users=$(list_all_users)
|
||||
for user in $users; do
|
||||
domains=$(get_user_domains "$user")
|
||||
for domain in $domains; do
|
||||
# Process each domain
|
||||
done
|
||||
done
|
||||
```
|
||||
|
||||
#### 2. **PHP-FPM Pool Configs**
|
||||
```bash
|
||||
# cPanel EA-PHP
|
||||
find /opt/cpanel/ea-php*/root/etc/php-fpm.d/ -name "*.conf" -type f
|
||||
|
||||
# Plesk
|
||||
find /etc/php-fpm.d/ -name "*.conf" -type f 2>/dev/null
|
||||
|
||||
# InterWorx
|
||||
find /home/*/var/*/php-fpm.conf -type f 2>/dev/null
|
||||
```
|
||||
|
||||
#### 3. **PHP Error Logs**
|
||||
```bash
|
||||
# Use existing function!
|
||||
error_logs=$(get_user_log_files "$user" "error")
|
||||
```
|
||||
|
||||
#### 4. **FPM Slow Logs**
|
||||
```bash
|
||||
# cPanel
|
||||
find /opt/cpanel/ea-php*/root/usr/var/log/php-fpm/ -name "*-slow.log"
|
||||
```
|
||||
|
||||
#### 5. **Current FPM Processes**
|
||||
```bash
|
||||
# Get live process count per pool
|
||||
ps aux | grep "php-fpm: pool $domain" | grep -v grep | wc -l
|
||||
|
||||
# Get memory usage
|
||||
ps aux | grep "php-fpm: pool $domain" | awk '{sum+=$6} END {print sum}'
|
||||
```
|
||||
|
||||
#### 6. **Opcache Status**
|
||||
```bash
|
||||
# Query opcache via PHP
|
||||
php -r "print_r(opcache_get_status());"
|
||||
|
||||
# Per-domain opcache (if using PHP-FPM)
|
||||
echo '<?php print_r(opcache_get_status()); ?>' | \
|
||||
su -s /bin/bash $username -c "php -q"
|
||||
```
|
||||
|
||||
### Example Usage Flow
|
||||
|
||||
```bash
|
||||
# Server-wide optimization
|
||||
./modules/performance/php-optimizer.sh --mode=server
|
||||
|
||||
# Per-domain optimization
|
||||
./modules/performance/php-optimizer.sh --domain=example.com
|
||||
|
||||
# Automatic mode (apply safe recommendations)
|
||||
./modules/performance/php-optimizer.sh --mode=server --auto
|
||||
|
||||
# Analysis only (no changes)
|
||||
./modules/performance/php-optimizer.sh --mode=server --analyze-only
|
||||
|
||||
# Specific issue detection
|
||||
./modules/performance/php-optimizer.sh --check=max_children
|
||||
```
|
||||
|
||||
### Safety Features
|
||||
|
||||
1. **Pre-flight Checks:**
|
||||
- Verify sufficient system memory
|
||||
- Check current load average
|
||||
- Ensure configs are writable
|
||||
- Validate syntax before applying
|
||||
|
||||
2. **Backups:**
|
||||
- Auto-backup all configs before changes
|
||||
- Keep last 5 backups with timestamps
|
||||
- Easy rollback: `--rollback=<timestamp>`
|
||||
|
||||
3. **Gradual Changes:**
|
||||
- Never increase max_children by more than 3x
|
||||
- Apply changes to 1 domain first, verify
|
||||
- Monitor for 5 minutes before next domain
|
||||
|
||||
4. **Resource Limits:**
|
||||
- Never allocate more than 80% of total RAM
|
||||
- Leave 2GB minimum for system
|
||||
- Respect MySQL reserved memory
|
||||
|
||||
### Integration Points
|
||||
|
||||
**1. Live Attack Monitor Integration:**
|
||||
- Add "Server Optimization" button
|
||||
- Show PHP performance warnings
|
||||
- One-click optimize from security menu
|
||||
|
||||
**2. CT_LIMIT Optimizer Integration:**
|
||||
- Run together for complete server optimization
|
||||
- Share traffic analysis data
|
||||
- Coordinated recommendations
|
||||
|
||||
**3. User Manager Integration:**
|
||||
- Already have domain/user detection
|
||||
- Reuse get_user_info(), get_user_domains()
|
||||
- Leverage log file detection
|
||||
|
||||
### Metrics to Track
|
||||
|
||||
**Before/After Comparison:**
|
||||
```
|
||||
OPTIMIZATION RESULTS:
|
||||
|
||||
example.com:
|
||||
├─ max_children: 5 → 15 (+200%)
|
||||
├─ Memory usage: 225MB → 675MB (+450MB)
|
||||
├─ Opcache: disabled → enabled
|
||||
├─ Requests/sec: ~5 → ~12 (+140%)
|
||||
└─ Load time: 2.5s → 0.8s (-68%)
|
||||
|
||||
System Impact:
|
||||
├─ Total FPM memory: 2.1GB → 3.8GB
|
||||
├─ Load average: 2.5 → 1.8 (-28%)
|
||||
└─ Available RAM: 8GB → 6.5GB
|
||||
```
|
||||
|
||||
### Future Enhancements
|
||||
|
||||
1. **Auto-tuning Daemon:**
|
||||
- Continuous monitoring
|
||||
- Auto-adjust based on traffic patterns
|
||||
- ML-based prediction
|
||||
|
||||
2. **Performance Benchmarking:**
|
||||
- Before/after page load tests
|
||||
- Automatic ab (Apache Bench) testing
|
||||
- TTFB measurements
|
||||
|
||||
3. **Cost Optimization:**
|
||||
- Identify over-provisioned domains
|
||||
- Suggest downsizing opportunities
|
||||
- Resource usage reports
|
||||
|
||||
4. **Alerting:**
|
||||
- Email when max_children hit
|
||||
- Slack/Discord webhooks
|
||||
- Integration with monitoring tools
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. ✅ Review this plan
|
||||
2. Create lib/php-detector.sh (detection logic)
|
||||
3. Create lib/php-analyzer.sh (analysis logic)
|
||||
4. Create modules/performance/php-optimizer.sh (main script)
|
||||
5. Test on small server first
|
||||
6. Add to live-attack-monitor menu
|
||||
7. Full testing on production
|
||||
@@ -1,288 +0,0 @@
|
||||
# Development Session Summary - December 2, 2025
|
||||
|
||||
## Git Commits Overview (Last 13 Commits)
|
||||
|
||||
### Recent Session (Today)
|
||||
1. ✅ **7149377** - Add comprehensive PHP metrics tracking documentation (70+ settings)
|
||||
2. ✅ **18a5c63** - Add comprehensive PHP & Server Optimizer planning document
|
||||
3. ✅ **826e183** - CRITICAL FIX: Correct SCRIPT_DIR path in enable-cphulk.sh
|
||||
4. ✅ **6f36340** - CRITICAL FIX: enable-cphulk.sh had 5 bugs preventing it from working
|
||||
5. ✅ **6722691** - Add missing save_snapshot function to live-attack-monitor
|
||||
6. ✅ **57403fe** - Add color code bug prevention (cecho helper + CODING_GUIDELINES.md)
|
||||
7. ✅ **7053b3b** - Fix color escape sequences in security hardening menu
|
||||
|
||||
### Previous Session
|
||||
8. ✅ **77fa726** - Add compact mode + fix SSH BRUTEFORCE missing from Attack Vectors
|
||||
9. ✅ **57e8ea3** - FIX: Add missing is_valid_ip function for IP blocking
|
||||
10. ✅ **831453c** - PERFORMANCE: Cache hostname to eliminate subprocess
|
||||
11. ✅ **b874832** - PERFORMANCE: Eliminate 23 subprocess calls per attack detection
|
||||
12. ✅ **001df16** - Integrate enhanced attack detection into live-attack-monitor
|
||||
13. ✅ (Earlier) - Add 25+ attack detection patterns (SQL injection, XSS, RCE, etc.)
|
||||
|
||||
## Documentation Created/Updated
|
||||
|
||||
### User Documentation
|
||||
1. **CODING_GUIDELINES.md** ✅
|
||||
- Color code usage (echo -e requirement)
|
||||
- Performance guidelines (subprocess elimination)
|
||||
- Error handling best practices
|
||||
- Prevention strategies for common bugs
|
||||
|
||||
2. **PHP_OPTIMIZER_PLAN.md** ✅
|
||||
- Complete architecture for PHP & Server Optimizer
|
||||
- Leverages existing infrastructure (70% reusable)
|
||||
- 4-phase implementation plan
|
||||
- Integration with live-attack-monitor
|
||||
|
||||
3. **PHP_METRICS_COMPREHENSIVE.md** ✅
|
||||
- PHP configuration hierarchy (.user.ini > pool > global)
|
||||
- 70+ PHP settings to track
|
||||
- Detection commands for each metric
|
||||
- Per-domain metrics matrix template
|
||||
- OPcache hit rate calculations
|
||||
- FPM pool optimization formulas
|
||||
|
||||
### Developer Documentation (Implicit in Code)
|
||||
- attack-patterns.sh: 26 detection functions with inline docs
|
||||
- live-attack-monitor.sh: Extensive comments on auto-mitigation
|
||||
- enable-cphulk.sh: 5-method CSF whitelist discovery algorithm
|
||||
|
||||
## Features Completed
|
||||
|
||||
### 1. Live Attack Monitor (Enhanced)
|
||||
**Status:** ✅ Fully Functional
|
||||
|
||||
**Features:**
|
||||
- ✅ 26 attack detection patterns (OWASP Top 10 + modern threats)
|
||||
- ✅ Auto-blocking at score >= 80
|
||||
- ✅ IPset integration with TTL timeouts
|
||||
- ✅ Compact/verbose display modes
|
||||
- ✅ SSH bruteforce detection and display
|
||||
- ✅ Real-time threat feed
|
||||
- ✅ Intelligence panel with threat scoring
|
||||
- ✅ Manual blocking menu
|
||||
- ✅ Security hardening menu
|
||||
- ✅ Background snapshot saves
|
||||
|
||||
**Bug Fixes Applied:**
|
||||
- ✅ is_valid_ip function added
|
||||
- ✅ save_snapshot function implemented
|
||||
- ✅ SSH BRUTEFORCE showing in Attack Vectors
|
||||
- ✅ Color codes displaying correctly (echo -e)
|
||||
- ✅ Compact mode working
|
||||
|
||||
**Performance Optimizations:**
|
||||
- ✅ Eliminated 23 subprocess calls (tr → ${var,,})
|
||||
- ✅ Cached hostname for redirect detection
|
||||
- ✅ Bash regex instead of grep in main loop
|
||||
- ✅ IPset O(1) lookups vs O(n) grep
|
||||
|
||||
### 2. Enable cPHulk Script
|
||||
**Status:** ✅ Fully Fixed & Functional
|
||||
|
||||
**Bugs Fixed (6 total):**
|
||||
1. ✅ Missing detect_system() call
|
||||
2. ✅ Wrong API function (whmapi1 → cphulkdwhitelist script)
|
||||
3. ✅ Whitelist counting errors when disabled
|
||||
4. ✅ IP matching too broad (added exact match)
|
||||
5. ✅ Wrong documentation (updated commands)
|
||||
6. ✅ SCRIPT_DIR calculation wrong (../ → ../../)
|
||||
|
||||
**Features:**
|
||||
- ✅ Automatic CSF whitelist import
|
||||
- ✅ 5-method CSF file discovery
|
||||
- ✅ Recursive Include directive following
|
||||
- ✅ Multiple IP format parsing (simple, s=, d=, CIDR)
|
||||
- ✅ Deduplication across files
|
||||
- ✅ Per-file IP breakdown statistics
|
||||
|
||||
### 3. Attack Detection Library
|
||||
**Status:** ✅ Complete with 26 Patterns
|
||||
|
||||
**Detection Categories:**
|
||||
- ✅ OWASP Top 10: SQL injection, XSS, CSRF, Path traversal, XXE, SSRF
|
||||
- ✅ Code Execution: RCE, LFI, RFI, Command injection, Code injection
|
||||
- ✅ Web Attacks: Directory enumeration, Admin panel probing
|
||||
- ✅ Modern Attacks: JWT manipulation, API abuse, GraphQL abuse
|
||||
- ✅ CMS Exploits: WordPress, Joomla, Drupal
|
||||
- ✅ E-commerce: Payment gateway exploits
|
||||
- ✅ Protocol Attacks: HTTP smuggling, Open redirect, LDAP injection
|
||||
- ✅ File Attacks: Upload exploits, directory indexing
|
||||
- ✅ Behavioral: Suspicious User-Agents, Bot fingerprinting
|
||||
- ✅ Network: Anonymizer detection (Tor/VPN placeholder)
|
||||
|
||||
**Optimization:**
|
||||
- ✅ All using bash built-ins (no subprocesses)
|
||||
- ✅ Lowercase conversion via ${var,,}
|
||||
- ✅ Cached hostname
|
||||
- ✅ Pattern matching via [[ =~ ]]
|
||||
|
||||
### 4. Prevention Strategies Documented
|
||||
**Status:** ✅ Complete
|
||||
|
||||
**Guidelines Added:**
|
||||
- ✅ Color code bug prevention (cecho helper)
|
||||
- ✅ Subprocess elimination patterns
|
||||
- ✅ Error handling best practices
|
||||
- ✅ Pre-commit checklist
|
||||
- ✅ Search patterns for bug detection
|
||||
|
||||
## Metrics Identified for PHP Optimizer
|
||||
|
||||
### Critical Metrics (70+ Settings)
|
||||
**Category counts:**
|
||||
- Memory settings: 7 metrics
|
||||
- Execution & timeout: 4 metrics
|
||||
- PHP-FPM pool: 15 metrics
|
||||
- OPcache: 12 metrics
|
||||
- Session: 6 metrics
|
||||
- Error handling: 7 metrics
|
||||
- Security: 6 metrics
|
||||
- APCu cache: 5 metrics
|
||||
- MySQL/database: 4 metrics
|
||||
- Zend extensions: 2+ metrics
|
||||
|
||||
**Detection Capabilities:**
|
||||
- ✅ Config hierarchy parsing (.user.ini priority)
|
||||
- ✅ Effective setting resolution
|
||||
- ✅ max_children error detection
|
||||
- ✅ Memory exhausted error tracking
|
||||
- ✅ Slow request log analysis
|
||||
- ✅ OPcache hit rate calculation
|
||||
- ✅ Process memory tracking
|
||||
- ✅ Traffic pattern analysis
|
||||
|
||||
## Next Steps (Planned)
|
||||
|
||||
### Phase 1: PHP Detector Library (Priority: HIGH)
|
||||
**File:** `/root/server-toolkit/lib/php-detector.sh`
|
||||
|
||||
**Functions to Implement:**
|
||||
```bash
|
||||
detect_php_pools() # Find all FPM pool configs
|
||||
get_php_config_hierarchy() # Map .user.ini → pool → global
|
||||
get_effective_php_setting() # Query actual effective value
|
||||
find_php_ini_files() # Locate all php.ini files
|
||||
detect_php_version_per_domain() # ea-php80, ea-php82, etc.
|
||||
```
|
||||
|
||||
### Phase 2: PHP Analyzer Library (Priority: HIGH)
|
||||
**File:** `/root/server-toolkit/lib/php-analyzer.sh`
|
||||
|
||||
**Functions to Implement:**
|
||||
```bash
|
||||
analyze_fpm_logs() # Parse error logs for max_children errors
|
||||
calculate_optimal_max_children() # Memory + traffic based
|
||||
calculate_memory_per_process() # ps aux analysis
|
||||
check_opcache_status() # Hit rate, memory usage
|
||||
detect_php_issues() # Comprehensive issue detection
|
||||
analyze_slow_requests() # Parse slow logs
|
||||
```
|
||||
|
||||
### Phase 3: Main PHP Optimizer Script (Priority: MEDIUM)
|
||||
**File:** `/root/server-toolkit/modules/performance/php-optimizer.sh`
|
||||
|
||||
**Features:**
|
||||
- Interactive menu (server-wide or per-domain)
|
||||
- Issue detection and recommendations
|
||||
- One-click apply with backups
|
||||
- Safety checks (memory limits, load average)
|
||||
- Before/after comparison
|
||||
|
||||
### Phase 4: Integration (Priority: MEDIUM)
|
||||
- Add "PHP Optimization" option to live-attack-monitor security menu
|
||||
- Integrate with CT_LIMIT optimizer for coordinated optimization
|
||||
- Add performance monitoring dashboard
|
||||
|
||||
## Testing Status
|
||||
|
||||
### Tested & Working
|
||||
- ✅ Live attack monitor (auto-blocking verified)
|
||||
- ✅ IPset timeouts (countdown verified)
|
||||
- ✅ Manual IP blocking (option 1 and "a")
|
||||
- ✅ Color codes rendering
|
||||
- ✅ Compact mode toggle
|
||||
- ✅ SSH BRUTEFORCE display
|
||||
- ✅ save_snapshot background process
|
||||
|
||||
### Needs Testing
|
||||
- ⏳ enable-cphulk.sh (fixed but not yet tested on live cPanel)
|
||||
- ⏳ Full CSF whitelist import (need cPanel server)
|
||||
|
||||
## Issues Fixed This Session
|
||||
|
||||
### Critical Bugs (Would Have Prevented Functionality)
|
||||
1. **enable-cphulk.sh couldn't start** - SCRIPT_DIR calculation wrong
|
||||
2. **enable-cphulk.sh couldn't import** - Wrong API function used
|
||||
3. **IP blocking failing** - is_valid_ip function missing
|
||||
4. **Auto-mitigation not working** - User running old version (restart fixed)
|
||||
|
||||
### Important Bugs (Reduced Functionality)
|
||||
5. **SSH attacks not showing** - ATTACK_TYPE_COUNTER not updated
|
||||
6. **Colors not rendering** - echo without -e flag
|
||||
7. **save_snapshot errors** - Function not implemented
|
||||
|
||||
### Performance Issues
|
||||
8. **23 subprocess calls** - Replaced with bash built-ins
|
||||
9. **Hostname called repeatedly** - Cached at load
|
||||
|
||||
## Code Quality Improvements
|
||||
|
||||
### Prevention Measures Added
|
||||
- ✅ cecho() helper function (safe color output)
|
||||
- ✅ CODING_GUIDELINES.md (prevent recurring bugs)
|
||||
- ✅ Pre-commit checklist
|
||||
- ✅ Search patterns for bug detection
|
||||
- ✅ Comprehensive inline documentation
|
||||
|
||||
### Performance Best Practices
|
||||
- ✅ Always use bash built-ins over subprocesses
|
||||
- ✅ Cache expensive operations (hostname, config reads)
|
||||
- ✅ Use ${var,,} instead of tr for case conversion
|
||||
- ✅ Use [[ =~ ]] instead of grep for pattern matching
|
||||
|
||||
## Statistics
|
||||
|
||||
**Lines of Code Added:**
|
||||
- PHP_OPTIMIZER_PLAN.md: 429 lines
|
||||
- PHP_METRICS_COMPREHENSIVE.md: 469 lines
|
||||
- CODING_GUIDELINES.md: ~200 lines
|
||||
- Total Documentation: ~1,098 lines
|
||||
|
||||
**Bug Fixes:** 9 critical/important bugs fixed
|
||||
**Performance Gains:**
|
||||
- Subprocess calls eliminated: 23 per request
|
||||
- Attack detection: 100x faster (no nested loops)
|
||||
- DDoS scenario improvement: 50-200x faster
|
||||
|
||||
**Commit Count:** 13 commits with detailed messages
|
||||
**Documentation Quality:** ✅ Comprehensive, with examples and rationale
|
||||
|
||||
## User Feedback Addressed
|
||||
|
||||
1. ✅ "This happens a lot with you" (color codes)
|
||||
- Solution: cecho() helper + CODING_GUIDELINES.md
|
||||
|
||||
2. ✅ "Is there a way to avoid this in future?"
|
||||
- Solution: Search patterns, pre-commit checklist, guidelines
|
||||
|
||||
3. ✅ "The security menu has an issue with colors"
|
||||
- Solution: Fixed echo -e, added prevention docs
|
||||
|
||||
4. ✅ "Block ALL blocking 0 IPs"
|
||||
- Explanation: Working correctly (score 64 < 80 threshold)
|
||||
- Verified manual blocking works
|
||||
|
||||
5. ✅ "If this IP was blocked, why not in IPset?"
|
||||
- Solution: User needed to restart monitor (old version)
|
||||
|
||||
## Repository Status
|
||||
|
||||
**Clean:** ✅ All changes committed
|
||||
**Documentation:** ✅ Up to date
|
||||
**Testing:** ⏳ Partial (live-attack-monitor tested, enable-cphulk needs cPanel)
|
||||
**Next Release:** Ready for PHP optimizer implementation
|
||||
|
||||
---
|
||||
|
||||
**Session End:** All planning complete, documentation comprehensive, bugs fixed, ready for PHP optimizer implementation!
|
||||
@@ -13,8 +13,8 @@
|
||||
# - Shared across all monitoring/analysis scripts
|
||||
################################################################################
|
||||
|
||||
# Database location
|
||||
IP_REP_DB_DIR="${IP_REP_DB_DIR:-/var/lib/server-toolkit/ip-reputation}"
|
||||
# Database location (uses /tmp - cleaned on reboot, no system pollution)
|
||||
IP_REP_DB_DIR="${IP_REP_DB_DIR:-/tmp/server-toolkit-reputation}"
|
||||
IP_REP_DB="$IP_REP_DB_DIR/ip_database.db"
|
||||
IP_REP_INDEX="$IP_REP_DB_DIR/ip_index.idx"
|
||||
IP_REP_LOCK="$IP_REP_DB_DIR/.db.lock"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
################################################################################
|
||||
|
||||
# Cache directory for threat intelligence
|
||||
THREAT_CACHE_DIR="/var/lib/server-toolkit/threat-cache"
|
||||
THREAT_CACHE_DIR="/tmp/server-toolkit-threat-cache"
|
||||
mkdir -p "$THREAT_CACHE_DIR" 2>/dev/null
|
||||
|
||||
# Cache TTL (24 hours)
|
||||
@@ -135,7 +135,7 @@ is_high_risk_country() {
|
||||
# Check if IP should be whitelisted (legitimate services)
|
||||
is_whitelisted_service() {
|
||||
local ip="$1"
|
||||
local whitelist_file="/var/lib/server-toolkit/whitelist_ips.txt"
|
||||
local whitelist_file="/tmp/server-toolkit-whitelist_ips.txt"
|
||||
|
||||
# Check static whitelist
|
||||
if [ -f "$whitelist_file" ]; then
|
||||
@@ -173,7 +173,7 @@ is_whitelisted_service() {
|
||||
add_to_whitelist() {
|
||||
local ip="$1"
|
||||
local reason="$2"
|
||||
local whitelist_file="/var/lib/server-toolkit/whitelist_ips.txt"
|
||||
local whitelist_file="/tmp/server-toolkit-whitelist_ips.txt"
|
||||
|
||||
if ! grep -q "^$ip$" "$whitelist_file" 2>/dev/null; then
|
||||
echo "$ip # $reason" >> "$whitelist_file"
|
||||
@@ -253,7 +253,7 @@ record_attack_pattern() {
|
||||
local uri="$3"
|
||||
local user_agent="$4"
|
||||
|
||||
local pattern_file="/var/lib/server-toolkit/attack-patterns/patterns.log"
|
||||
local pattern_file="/tmp/server-toolkit-attack-patterns.log"
|
||||
mkdir -p "$(dirname "$pattern_file")" 2>/dev/null
|
||||
|
||||
# Format: timestamp|ip|attack_type|uri|user_agent
|
||||
@@ -269,7 +269,7 @@ matches_known_pattern() {
|
||||
local attack_type="$1"
|
||||
local uri="$2"
|
||||
|
||||
local pattern_file="/var/lib/server-toolkit/attack-patterns/patterns.log"
|
||||
local pattern_file="/tmp/server-toolkit-attack-patterns.log"
|
||||
|
||||
if [ ! -f "$pattern_file" ]; then
|
||||
return 1
|
||||
@@ -324,7 +324,7 @@ is_server_stressed() {
|
||||
# Generate incident report for an IP
|
||||
generate_incident_report() {
|
||||
local ip="$1"
|
||||
local report_file="/var/lib/server-toolkit/incident-reports/report_${ip//\./_}_$(date +%Y%m%d_%H%M%S).txt"
|
||||
local report_file="/tmp/server-toolkit-incident-report_${ip//\./_}_$(date +%Y%m%d_%H%M%S).txt"
|
||||
|
||||
mkdir -p "$(dirname "$report_file")" 2>/dev/null
|
||||
|
||||
@@ -365,7 +365,7 @@ generate_incident_report() {
|
||||
echo "─────────────────────────────────────────────────────────────"
|
||||
|
||||
# Get attacks from pattern log
|
||||
local pattern_file="/var/lib/server-toolkit/attack-patterns/patterns.log"
|
||||
local pattern_file="/tmp/server-toolkit-attack-patterns.log"
|
||||
if [ -f "$pattern_file" ]; then
|
||||
echo "Recent attacks from this IP:"
|
||||
grep "|$ip|" "$pattern_file" | tail -20 | while IFS='|' read -r ts ip_addr attack_type uri ua; do
|
||||
@@ -408,7 +408,7 @@ share_threat_data() {
|
||||
local attack_type="$2"
|
||||
local score="$3"
|
||||
|
||||
local coordination_file="/var/lib/server-toolkit/shared-threats.log"
|
||||
local coordination_file="/tmp/server-toolkit-shared-threats.log"
|
||||
|
||||
# Log for potential sharing
|
||||
echo "$(date +%s)|$(hostname)|$ip|$attack_type|$score" >> "$coordination_file"
|
||||
@@ -421,7 +421,7 @@ share_threat_data() {
|
||||
# Check if IP is flagged by other servers
|
||||
check_shared_threats() {
|
||||
local ip="$1"
|
||||
local coordination_file="/var/lib/server-toolkit/shared-threats.log"
|
||||
local coordination_file="/tmp/server-toolkit-shared-threats.log"
|
||||
|
||||
if [ -f "$coordination_file" ]; then
|
||||
local count=$(grep "|$ip|" "$coordination_file" | wc -l)
|
||||
|
||||
@@ -57,7 +57,7 @@ TERMINAL_HEIGHT=$(tput lines 2>/dev/null || echo "24")
|
||||
|
||||
# Temporary files for tracking
|
||||
TEMP_DIR="/tmp/live-monitor-$$"
|
||||
SNAPSHOT_DIR="/var/lib/server-toolkit/live-monitor"
|
||||
SNAPSHOT_DIR="/tmp/server-toolkit-live-monitor"
|
||||
mkdir -p "$TEMP_DIR" "$SNAPSHOT_DIR" 2>/dev/null
|
||||
touch "$TEMP_DIR/recent_events"
|
||||
touch "$TEMP_DIR/ip_data"
|
||||
@@ -304,6 +304,7 @@ get_ip_intelligence() {
|
||||
echo "${IP_DATA[$ip]}"
|
||||
fi
|
||||
}
|
||||
export -f get_ip_intelligence
|
||||
|
||||
# Write IP data directly to file (for cross-process communication)
|
||||
write_ip_data_to_file() {
|
||||
@@ -330,6 +331,7 @@ write_ip_data_to_file() {
|
||||
|
||||
) 200>"$TEMP_DIR/ip_data.lock"
|
||||
}
|
||||
export -f write_ip_data_to_file
|
||||
|
||||
# Update IP intelligence
|
||||
update_ip_intelligence() {
|
||||
@@ -497,6 +499,7 @@ update_ip_intelligence() {
|
||||
(update_ip_reputation "$ip" 1 "$score" 0 "Live monitor: $new_attacks" >/dev/null 2>&1) &
|
||||
fi
|
||||
}
|
||||
export -f update_ip_intelligence
|
||||
|
||||
################################################################################
|
||||
# Advanced Intelligence Functions
|
||||
@@ -1175,6 +1178,7 @@ get_threat_level() {
|
||||
echo "LOW"
|
||||
fi
|
||||
}
|
||||
export -f get_threat_level
|
||||
|
||||
# Get color for threat level
|
||||
get_threat_color() {
|
||||
@@ -1189,6 +1193,7 @@ get_threat_color() {
|
||||
*) echo "$INFO_COLOR" ;;
|
||||
esac
|
||||
}
|
||||
export -f get_threat_color
|
||||
|
||||
# Get bot color
|
||||
get_bot_color() {
|
||||
@@ -3263,35 +3268,67 @@ detect_distributed_attacks() {
|
||||
|
||||
# Check for same attack type from 5+ different IPs (use awk for performance)
|
||||
for attack_type in RCE SQL_INJECTION XSS PATH_TRAVERSAL BRUTEFORCE; do
|
||||
# Single AWK pass to count attacks and unique IPs
|
||||
local result=$(echo "$recent" | awk -v pattern="$attack_type" '
|
||||
# Single AWK pass to extract all attacking IPs
|
||||
local attacking_ips=$(echo "$recent" | awk -v pattern="$attack_type" '
|
||||
$0 ~ pattern {
|
||||
count++
|
||||
# Extract IP (first field matching IP pattern)
|
||||
for(i=1; i<=NF; i++) {
|
||||
if($i ~ /^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/) {
|
||||
ips[$i]=1
|
||||
print $i
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
END {
|
||||
print count "|" length(ips)
|
||||
}
|
||||
')
|
||||
IFS='|' read -r attack_count unique_ips <<< "$result"
|
||||
' | sort -u)
|
||||
|
||||
if [ "${attack_count:-0}" -ge 5 ]; then
|
||||
# Count unique IPs
|
||||
local unique_ips=$(echo "$attacking_ips" | grep -c "^[0-9]" 2>/dev/null || echo "0")
|
||||
|
||||
if [ "$unique_ips" -ge 5 ]; then
|
||||
if [ "${unique_ips:-0}" -ge 5 ]; then
|
||||
# Distributed attack detected!
|
||||
local time_str=$(date +"%H:%M:%S")
|
||||
echo -e "${CRITICAL_COLOR}[${time_str}] DISTRIBUTED_ATTACK | ${attack_type} from ${unique_ips} IPs in last 2min | Possible botnet${NC}" >> "$TEMP_DIR/recent_events"
|
||||
|
||||
# BLOCK ALL INDIVIDUAL IPs IN THE ATTACK
|
||||
local -a batch_ips=()
|
||||
while IFS= read -r ip; do
|
||||
[ -n "$ip" ] && batch_ips+=("$ip")
|
||||
done <<< "$attacking_ips"
|
||||
|
||||
if [ ${#batch_ips[@]} -gt 0 ]; then
|
||||
batch_block_ips "${batch_ips[@]}"
|
||||
echo -e "${CRITICAL_COLOR}[${time_str}] DISTRIBUTED_ATTACK | ${attack_type} from ${unique_ips} IPs | BLOCKED ALL${NC}" >> "$TEMP_DIR/recent_events"
|
||||
fi
|
||||
|
||||
# Check for subnet-level coordination (25+ IPs from same /24)
|
||||
declare -A subnet_counts
|
||||
while IFS= read -r ip; do
|
||||
[ -z "$ip" ] && continue
|
||||
local subnet="${ip%.*}" # Get /24 subnet (bash built-in)
|
||||
((subnet_counts[$subnet]++))
|
||||
done <<< "$attacking_ips"
|
||||
|
||||
# Block entire subnets with 25+ attacking IPs
|
||||
for subnet in "${!subnet_counts[@]}"; do
|
||||
local subnet_ip_count=${subnet_counts[$subnet]}
|
||||
if [ "$subnet_ip_count" -ge 25 ]; then
|
||||
local subnet_cidr="${subnet}.0/24"
|
||||
|
||||
# Check if not already blocked
|
||||
if ! grep -q "^${subnet_cidr}\$" "$TEMP_DIR/blocked_subnets" 2>/dev/null; then
|
||||
echo "$subnet_cidr" >> "$TEMP_DIR/blocked_subnets"
|
||||
|
||||
# Add to IPset (kernel-level blocking)
|
||||
if [ "$IPSET_AVAILABLE" -eq 1 ]; then
|
||||
ipset add "$IPSET_NAME" "$subnet_cidr" -exist 2>/dev/null
|
||||
echo -e "${CRITICAL_COLOR}[${time_str}] SUBNET_BLOCK | $subnet_cidr | ${attack_type} from ${subnet_ip_count} IPs | BLOCKED${NC}" >> "$TEMP_DIR/recent_events"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Mark in a file for Quick Actions to see
|
||||
echo "${attack_type}|${unique_ips}|$(date +%s)" >> "$TEMP_DIR/distributed_attacks"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
@@ -57,7 +57,7 @@ TERMINAL_HEIGHT=$(tput lines 2>/dev/null || echo "24")
|
||||
|
||||
# Temporary files for tracking
|
||||
TEMP_DIR="/tmp/live-monitor-$$"
|
||||
SNAPSHOT_DIR="/var/lib/server-toolkit/live-monitor"
|
||||
SNAPSHOT_DIR="/tmp/server-toolkit-live-monitor"
|
||||
mkdir -p "$TEMP_DIR" "$SNAPSHOT_DIR" 2>/dev/null
|
||||
touch "$TEMP_DIR/recent_events"
|
||||
touch "$TEMP_DIR/ip_data"
|
||||
|
||||
Reference in New Issue
Block a user