Securing CloudPanel on Ubuntu 24.04 Part 4 and 5

16/11/2024 16/11/2024 security 5 mins read
Table Of Contents

Part 4 & 5: Advanced Security Controls and PHP Configuration Management #

Let’s create a security system that integrates traffic analysis and PHP configuration management based on CloudPanel.

First, let’s create our main security management script:

Terminal window
# Create the security management script
sudo nano /usr/local/bin/cloudpanel-php-security-manager.sh

#

#!/bin/bash
# CloudPanel PHP Security Manager
# Manages PHP-FPM configurations and security settings across different PHP versions
set -euo pipefail
# Core paths based on CloudPanel structure
CP_HOME="/home/clp"
DB_PATH="${CP_HOME}/htdocs/app/data/db.sq3"
SITES_ROOT="/home"
LOG_DIR="${CP_HOME}/logs/php"
mkdir -p "$LOG_DIR"
# Function to handle logging with timestamps and levels
log() {
local level="$1"
local message="$2"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $message" | tee -a "${LOG_DIR}/security.log"
}
# Validate database existence
validate_db() {
if [ ! -f "$DB_PATH" ]; then
log "ERROR" "CloudPanel database not found at $DB_PATH"
exit 1
fi
}
# Retrieve sites with their PHP settings from database
# This function joins site and php_settings tables to get complete configuration
get_sites_with_php() {
sqlite3 "$DB_PATH" "
SELECT
s.id,
s.domain_name,
s.user,
s.root_directory,
p.php_version,
p.id as php_settings_id,
p.memory_limit,
p.max_execution_time,
p.additional_configuration,
p.pool_port
FROM site s
INNER JOIN php_settings p ON s.php_settings_id = p.id
WHERE s.type = 'vhost';"
}
# Configure PHP version specific settings
configure_php_version() {
local php_version="$1"
local version_number="${php_version/./}" # Convert 7.4 to 74
# Verify PHP version installation
if [ ! -d "/etc/php/${php_version}" ]; then
log "ERROR" "PHP version ${php_version} not installed"
return 1
fi
# Setup PHP-FPM pool directory
local fpm_pool_dir="/etc/php/${php_version}/fpm/pool.d"
mkdir -p "$fpm_pool_dir"
# Create base PHP-FPM configuration if missing
local fpm_conf="/etc/php/${php_version}/fpm/php-fpm.conf"
if [ ! -f "$fpm_conf" ]; then
cat > "$fpm_conf" << EOF
[global]
pid = /run/php/php${php_version}-fpm.pid
error_log = /var/log/php${version_number}-fpm.log
log_level = notice
emergency_restart_threshold = 10
emergency_restart_interval = 1m
process_control_timeout = 10s
daemonize = yes
include=/etc/php/${php_version}/fpm/pool.d/*.conf
EOF
fi
# Enable PHP-FPM service
systemctl enable "php${version_number}-fpm" 2>/dev/null || true
}
# Configure PHP settings for a specific site
configure_site_php() {
local domain="$1"
local user="$2"
local php_version="$3"
local root_dir="$4"
local memory_limit="$5"
local max_exec="$6"
local additional_config="$7"
local pool_port="$8"
local version_number="${php_version/./}"
local pool_config="/etc/php/${php_version}/fpm/pool.d/${domain}.conf"
local user_php_log_dir="${SITES_ROOT}/${user}/logs/php"
# Create and set permissions for log directory
mkdir -p "$user_php_log_dir"
chown "${user}:${user}" "$user_php_log_dir"
# Create PHP-FPM pool configuration
cat > "$pool_config" << EOF
[${domain}]
user = ${user}
group = ${user}
listen = 127.0.0.1:${pool_port}
; Process Management
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 2
pm.max_spare_servers = 10
; Path Settings
chdir = ${root_dir}
; PHP Settings
php_admin_flag[log_errors] = on
php_admin_value[error_log] = ${user_php_log_dir}/php-${domain}-error.log
php_admin_value[memory_limit] = ${memory_limit}
php_admin_value[max_execution_time] = ${max_exec}
php_admin_value[session.save_handler] = files
php_admin_value[session.save_path] = ${SITES_ROOT}/${user}/tmp/sessions
php_admin_value[upload_tmp_dir] = ${SITES_ROOT}/${user}/tmp/upload
; Security Settings
php_admin_flag[allow_url_fopen] = off
php_admin_flag[allow_url_include] = off
php_admin_value[disable_functions] = exec,passthru,shell_exec,system,proc_open,popen
php_admin_value[open_basedir] = ${root_dir}:/tmp:${SITES_ROOT}/${user}/tmp
; Custom Configuration
${additional_config}
EOF
# Setup temporary directories with proper permissions
mkdir -p "${SITES_ROOT}/${user}/tmp/"{sessions,upload}
chown -R "${user}:${user}" "${SITES_ROOT}/${user}/tmp"
chmod -R 750 "${SITES_ROOT}/${user}/tmp"
log "INFO" "Configured PHP-FPM pool for ${domain} (PHP ${php_version})"
}
# Setup log rotation for PHP logs
setup_log_rotation() {
local user="$1"
local domain="$2"
cat > "/etc/logrotate.d/php-${domain}" << EOF
${SITES_ROOT}/${user}/logs/php/php-${domain}-error.log {
daily
rotate 14
missingok
notifempty
compress
delaycompress
create 0640 ${user} ${user}
}
EOF
}
# Main execution function
main() {
log "INFO" "Starting CloudPanel PHP security configuration"
validate_db
# Create backup directory
local backup_date=$(date +%Y%m%d_%H%M%S)
local backup_dir="${CP_HOME}/backups/php_security_${backup_date}"
mkdir -p "$backup_dir"
# Track configured PHP versions
declare -A configured_versions
# Process each site
while IFS='|' read -r site_id domain user root_dir php_version settings_id mem_limit max_exec additional port; do
if [ -z "${configured_versions[$php_version]:-}" ]; then
configure_php_version "$php_version"
configured_versions[$php_version]=1
# Backup existing configuration
if [ -d "/etc/php/${php_version}" ]; then
cp -r "/etc/php/${php_version}" "${backup_dir}/php${php_version}"
fi
fi
configure_site_php "$domain" "$user" "$php_version" "$root_dir" "$mem_limit" "$max_exec" "$additional" "$port"
setup_log_rotation "$user" "$domain"
done < <(get_sites_with_php)
log "INFO" "PHP security configuration completed"
log "INFO" "Backup stored in: $backup_dir"
# Reload PHP-FPM for each configured version
for version in "${!configured_versions[@]}"; do
version_num="${version/./}"
systemctl reload "php${version_num}-fpm" || log "ERROR" "Failed to reload PHP-FPM for version ${version}"
done
}
main "$@"

This unified script:

  1. Reads site configurations directly from CloudPanel
  2. Configures PHP-FPM pools with settings from the database
  3. Implements security measures for both PHP
  4. Analyzes traffic patterns for suspicious activity
  5. Creates proper backups before making changes

To use this script:

Terminal window
# Make the script executable
chmod +x /usr/local/bin/cloudpanel-php-security-manager.sh
# Run the script
/usr/local/bin/cloudpanel-php-security-manager.sh