ISPConfig is a mature, enterprise-grade open-source web hosting control panel for Linux. First released in 2005, it supports multiple servers, multi-language environments, and provides comprehensive management for web domains, email, DNS, databases, and virtual servers. With over 20 years of development, ISPConfig has a strong security foundation, but like any control panel, it requires comprehensive hardening to protect server infrastructure and customer data in production environments.
ISPConfig supports TOTP-based 2FA for all user accounts. Enable it immediately after installation.
Enable 2FA via ISPConfig UI:
Force 2FA for all admin accounts:
# ISPConfig stores 2FA settings in MySQL database
# Login to MySQL
mysql -u root -p dbispconfig
# Enable 2FA enforcement for all admins (ISPConfig 3.2+)
UPDATE sys_user SET twofa_enabled = '1' WHERE typ = 'admin' AND twofa_enabled = '0';
# Verify setting
SELECT username, twofa_enabled FROM sys_user WHERE typ = 'admin';
Note: Database modifications should be tested in staging first. Always backup before making changes.
Secure the default admin account:
# Change admin password via MySQL
mysql -u root -p dbispconfig
UPDATE sys_user SET passwort = PASSWORD('YourNewStrongPassword123!') WHERE username = 'admin';
FLUSH PRIVILEGES;
Or via ISPConfig UI:
Best practices:
Create new admin user via ISPConfig UI:
Delete or disable unused accounts:
# Disable user via MySQL (soft delete)
mysql -u root -p dbispconfig
UPDATE sys_user SET active = 'n' WHERE username = 'oldadmin';
# Or delete permanently (use with caution)
DELETE FROM sys_user WHERE username = 'oldadmin';
Restrict panel access by IP using ISPConfig’s built-in feature:
# Login to ISPConfig
# Go to System → Server Config → Firewall
# Add rules via UI or directly configure iptables/nftables
Configure firewall via ISPConfig UI:
Using iptables directly:
# Allow only from management network
sudo iptables -A INPUT -p tcp --dport 8080 -s 10.0.0.0/24 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 8080 -j DROP
sudo iptables -A INPUT -p tcp --dport 443 -s 10.0.0.0/24 -j ACCEPT # HTTPS
sudo iptables-save > /etc/iptables/rules.v4
# Save rules permanently
sudo iptables-save > /etc/iptables/rules.v4
Using firewalld:
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.0.0/24" port port="8080" protocol="tcp" accept'
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" port port="8080" protocol="tcp" reject'
sudo firewall-cmd --reload
Using UFW:
sudo ufw allow from 10.0.0.0/24 to any port 8080
sudo ufw deny 8080
sudo ufw enable
Configure session settings in ISPConfig:
Edit /usr/local/ispconfig/interface/lib/config.inc.php:
<?php
// Session configuration
$conf['session_timeout'] = 900; // 15 minutes
$conf['session_ip_check'] = true; // Prevent session hijacking
$conf['session_user_agent_check'] = true;
// Security settings
$conf['csrf_protection'] = true;
$conf['clickjacking_protection'] = true;
?>
Secure session handling in PHP (/etc/php/*/apache2/php.ini or /etc/php/*/fpm/php.ini):
[Session]
session.cookie_httponly = 1
session.cookie_secure = 1
session.use_only_cookies = 1
session.cookie_samesite = Strict
session.use_strict_mode = 1
session.gc_maxlifetime = 900
session.name = ISPSESSID # Change default session name
Restart web server:
sudo systemctl restart apache2 # or nginx/php-fpm
Configure password requirements in ISPConfig:
# Edit ISPConfig configuration
sudo nano /usr/local/ispconfig/interface/lib/config.inc.php
# Add password policy settings
$conf['password_min_length'] = 12;
$conf['password_require_special'] = true;
$conf['password_require_numbers'] = true;
$conf['password_require_uppercase'] = true;
$conf['password_require_lowercase'] = true;
Enforce password history (prevent reuse):
# Install pam_pwhistory
sudo apt install libpam-pwquality # Debian/Ubuntu
sudo dnf install libpwquality # RHEL/CentOS
# Configure /etc/pam.d/common-password
password required pam_pwhistory.so use_authtok remember=12 enforce_for_root
password required pam_unix.so use_authtok sha512
ISPConfig uses HTTPS by default. Replace self-signed certificate with valid certificate:
Option 1: Let’s Encrypt via ISPConfig (Recommended for Debian/Ubuntu)
# ISPConfig can auto-generate Let's Encrypt certificates
# Go to System → Server Config → SSL
# Or via CLI (ISPConfig 3.2+)
cd /usr/local/ispconfig/interface
sudo php -q create_letsencrypt_cert.php
Option 2: Manual Let’s Encrypt
sudo apt install certbot
# Generate certificate for panel hostname
sudo certbot certonly --standalone -d ispconfig.example.com
# Link to ISPConfig
sudo cp /etc/letsencrypt/live/ispconfig.example.com/fullchain.pem /usr/local/ispconfig/interface/ssl/ispconfig.crt
sudo cp /etc/letsencrypt/live/ispconfig.example.com/privkey.pem /usr/local/ispconfig/interface/ssl/ispconfig.key
sudo chmod 600 /usr/local/ispconfig/interface/ssl/ispconfig.key
# Restart Apache
sudo systemctl restart apache2
Option 3: Self-signed certificate (testing only)
sudo mkdir -p /usr/local/ispconfig/interface/ssl
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /usr/local/ispconfig/interface/ssl/ispconfig.key \
-out /usr/local/ispconfig/interface/ssl/ispconfig.crt \
-subj "/C=US/ST=State/L=City/O=Organization/CN=ispconfig.example.com"
sudo chmod 600 /usr/local/ispconfig/interface/ssl/ispconfig.key
sudo systemctl restart apache2
Configure Apache for HTTPS (/etc/apache2/sites-available/ispconfig.conf or /etc/apache2/sites-available/ispconfig.vhost):
<VirtualHost *:443>
ServerName ispconfig.example.com
DocumentRoot /usr/local/ispconfig/interface/web
SSLEngine on
SSLCertificateFile /usr/local/ispconfig/interface/ssl/ispconfig.crt
SSLCertificateKeyFile /usr/local/ispconfig/interface/ssl/ispconfig.key
# Security headers
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-XSS-Protection "1; mode=block"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';"
<Directory /usr/local/ispconfig/interface/web>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
# Redirect HTTP to HTTPS
<VirtualHost *:80>
ServerName ispconfig.example.com
Redirect permanent / https://ispconfig.example.com/
</VirtualHost>
Default ISPConfig ports:
| Port | Service | Required |
|---|---|---|
| 8080 | ISPConfig Admin Panel | Yes |
| 80 | HTTP (web domains) | Yes |
| 443 | HTTPS (web domains) | Yes |
| 21 | FTP | If FTP enabled |
| 22 | SSH | Recommended |
| 25 | SMTP | If mail enabled |
| 53 | DNS | If DNS enabled |
| 110/995 | POP3 | If mail enabled |
| 143/993 | IMAP | If mail enabled |
| 3306 | MySQL | No (localhost only) |
| 3307 | MariaDB (ISPConfig) | No (localhost only) |
ISPConfig includes built-in firewall management:
Configure via ISPConfig UI:
Example firewall rules:
# Allow essential services
-A INPUT -p tcp --dport 22 -j ACCEPT # SSH
-A INPUT -p tcp --dport 80 -j ACCEPT # HTTP
-A INPUT -p tcp --dport 443 -j ACCEPT # HTTPS
-A INPUT -p tcp --dport 8080 -s 10.0.0.0/24 -j ACCEPT # ISPConfig from trusted IPs
-A INPUT -p tcp --dport 8080 -j DROP # Block others from panel
# Mail services (if enabled)
-A INPUT -p tcp --dport 25 -j ACCEPT # SMTP
-A INPUT -p tcp --dport 587 -j ACCEPT # Submission
-A INPUT -p tcp --dport 110 -j ACCEPT # POP3
-A INPUT -p tcp --dport 995 -j ACCEPT # POP3S
-A INPUT -p tcp --dport 143 -j ACCEPT # IMAP
-A INPUT -p tcp --dport 993 -j ACCEPT # IMAPS
# DNS (if enabled)
-A INPUT -p udp --dport 53 -j ACCEPT
-A INPUT -p tcp --dport 53 -j ACCEPT
# Default deny
-A INPUT -j DROP
Configure CSF (if installed):
# Edit /etc/csf/csf.conf
TCP_IN = "20,21,22,25,53,80,110,143,443,465,587,993,995,8080"
TCP_OUT = "20,21,25,53,80,110,443,465,587"
# Enable port scan protection
PS_INTERVAL = "60"
# Enable logging
LOG_INTERVAL = "60"
# Restart CSF
csf -r
ISPConfig includes built-in fail2ban integration:
Enable fail2ban protection:
# Install fail2ban (if not already installed)
sudo apt install fail2ban # Debian/Ubuntu
sudo dnf install fail2ban # RHEL/CentOS
ISPConfig fail2ban jails (/etc/fail2ban/jail.local):
[ispconfig-auth]
enabled = true
port = 8080,443
filter = ispconfig-auth
logpath = /var/log/ispconfig/auth.log
maxretry = 5
bantime = 3600
findtime = 300
[ispconfig-bruteforce]
enabled = true
port = 8080,443
filter = ispconfig-bruteforce
logpath = /var/log/ispconfig/auth.log
maxretry = 3
bantime = 7200
findtime = 300
[postfix-sasl]
enabled = true
port = smtp,465,submission
filter = postfix-sasl
logpath = /var/log/mail.log
maxretry = 3
bantime = 3600
[dovecot-pop3imap]
enabled = true
filter = dovecot-pop3imap
logpath = /var/log/mail.log
maxretry = 3
bantime = 3600
Create ISPConfig filter (/etc/fail2ban/filter.d/ispconfig-auth.conf):
[Definition]
failregex = ^.*Failed login.*<HOST>.*$
^.*Authentication failure.*<HOST>.*$
^.*Invalid.*password.*<HOST>.*$
^.*Login failed.*<HOST>.*$
^.*WARNING.*login.*<HOST>.*$
ignoreregex =
Restart fail2ban:
sudo systemctl restart fail2ban
View banned IPs:
fail2ban-client status ispconfig-auth
fail2ban-client set ispconfig-auth unbanip <IP>
Configure Apache rate limiting:
# /etc/apache2/mods-available/ratelimit.conf
<IfModule mod_ratelimit.c>
SetOutputFilter RATE_LIMIT
SetEnv rate-limit 400
SetEnv rate-limit-burst 200
</IfModule>
Configure mod_evasive for DDoS protection:
# /etc/apache2/mods-available/evasive.conf
<IfModule mod_evasive24.c>
DOSHashTableSize 3097
DOSPageCount 2
DOSSiteCount 50
DOSPageInterval 1
DOSSiteInterval 1
DOSBlockingPeriod 10
DOSEmailNotify admin@example.com
DOSSystemCommand "su - root -c 'csf -d %s DDoS Attack'"
</IfModule>
Enable modules:
sudo a2enmod ratelimit
sudo a2enmod evasive
sudo systemctl restart apache2
Edit /usr/local/ispconfig/interface/lib/config.inc.php:
<?php
// Security settings
// Disable debug in production
$conf['debug'] = false;
// Session security
$conf['session_timeout'] = 900;
$conf['session_ip_check'] = true;
$conf['session_user_agent_check'] = true;
// CSRF protection
$conf['csrf_protection'] = true;
// Password requirements
$conf['password_min_length'] = 12;
$conf['password_require_special'] = true;
$conf['password_require_numbers'] = true;
// Login attempt limits
$conf['login_attempts'] = 5;
$conf['login_lockout_time'] = 300; // 5 minutes
// File upload limits
$conf['max_upload_size'] = 10; // MB
?>
Apply configuration:
sudo systemctl restart apache2
ISPConfig uses MySQL/MariaDB. Secure it:
# Run secure installation
sudo mysql_secure_installation
# Key settings:
# - Set root password
# - Remove anonymous users
# - Disallow root login remotely
# - Remove test database
Configure /etc/mysql/mariadb.conf.d/50-server.cnf:
[mysqld]
# Network security - bind to localhost only
bind-address = 127.0.0.1
skip-networking = 1
# Disable local infile
local-infile = 0
# Secure file handling
secure_file_priv = /var/lib/mysql-files
# Logging
log_error = /var/log/mysql/error.log
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
# ISPConfig-specific: use dedicated database user
Create restricted ISPConfig database user:
-- Login to MySQL
mysql -u root -p
-- ISPConfig uses dbispconfig database
-- Ensure user has minimal privileges
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, CREATE TEMPORARY TABLES ON dbispconfig.* TO 'ispconfig'@'localhost' IDENTIFIED BY 'strong-password-here';
FLUSH PRIVILEGES;
-- Do NOT grant: FILE, PROCESS, SUPER, RELOAD, SHUTDOWN, GRANT OPTION
Edit /etc/php/*/apache2/php.ini or /etc/php/*/fpm/php.ini:
[Security]
expose_php = Off
allow_url_fopen = Off
allow_url_include = Off
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source,passthru,leak,fopen,readfile
display_errors = Off
log_errors = On
error_reporting = E_ALL
html_errors = Off
[Resource Limits]
max_execution_time = 30
max_input_time = 60
memory_limit = 256M
post_max_size = 64M
upload_max_filesize = 64M
max_file_uploads = 20
[Session]
session.cookie_httponly = 1
session.cookie_secure = 1
session.use_only_cookies = 1
session.cookie_samesite = Strict
session.use_strict_mode = 1
session.gc_maxlifetime = 900
session.name = ISPSESSID
[Open Basedir]
open_basedir = /usr/local/ispconfig:/var/www:/tmp:/var/tmp
Restart web server:
sudo systemctl restart apache2 # Apache
sudo systemctl restart php*-fpm # PHP-FPM
Secure ISPConfig installation:
# ISPConfig directory permissions
sudo chown -R root:root /usr/local/ispconfig
sudo chmod -R 755 /usr/local/ispconfig
sudo chmod 600 /usr/local/ispconfig/interface/lib/config.inc.php
# Web directory
sudo chown -R www-data:www-data /var/www
sudo chmod -R 755 /var/www
# User home directories
sudo chmod 711 /home
sudo chmod 711 /home/username
# Web directories for customers
sudo chmod 755 /var/www/clients
sudo chown -R web1:client1 /var/www/clients/client1/web1
# Configuration files
sudo chmod 600 /var/www/clients/client1/.my.cnf
sudo chmod 644 /var/www/clients/client1/web1/web/.htaccess
# SSH directories
sudo chmod 700 /home/username/.ssh
sudo chmod 600 /home/username/.ssh/authorized_keys
Protect sensitive files:
# /etc/apache2/conf-available/ispconfig-hardening.conf
<FilesMatch "(config\.php|\.sql|\.log|\.bak|\.old)$">
Require all denied
</FilesMatch>
# Prevent directory listing
<Directory /var/www>
Options -Indexes
</Directory>
Disable PHP execution in upload directories:
# /etc/apache2/conf-available/disable-php-uploads.conf
<Directory "/var/www/clients/client*/web*/web/wp-content/uploads">
php_flag engine off
RemoveHandler .php .php3 .php4 .php5 .phtml
<FilesMatch "\.(php|php3|php4|php5|phtml)$">
Deny from all
</FilesMatch>
</Directory>
<Directory "/var/www/clients/client*/web*/web/images">
php_flag engine off
</Directory>
Secure SSH access:
# Edit /etc/ssh/sshd_config
sudo nano /etc/ssh/sshd_config
# Key settings:
Port 2222 # Change from default
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AuthenticationMethods publickey
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2
AllowUsers admin-user
X11Forwarding no
AllowTcpForwarding no
Restart SSH:
sudo systemctl restart sshd
ISPConfig typically uses Postfix and Dovecot. Secure them:
Postfix configuration (/etc/postfix/main.cf):
# Disable VRFY command
disable_vrfy_command = yes
# Restrict relay
smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination
# Rate limiting
smtpd_client_connection_rate_limit = 50
anvil_rate_time_unit = 60s
# TLS settings
smtpd_tls_security_level = encrypt
smtpd_tls_auth_only = yes
smtpd_tls_mandatory_ciphers = medium
Dovecot configuration (/etc/dovecot/dovecot.conf):
# Disable plaintext auth without SSL
disable_plaintext_auth = yes
# SSL settings
ssl = required
ssl_min_protocol = TLSv1.2
ssl_cipher_list = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
# Logging
log_path = /var/log/dovecot.log
auth_verbose = yes
Restart mail services:
sudo systemctl restart postfix
sudo systemctl restart dovecot
Update ISPConfig:
# Check current version
cat /usr/local/ispconfig/version.txt
# Update via apt (if using repository)
sudo apt update
sudo apt upgrade ispconfig
# Or manual update
cd /tmp
wget https://www.ispconfig.org/downloads/ISPConfig-3-stable.tar.gz
tar xvfz ISPConfig-3-stable.tar.gz
cd ispconfig3_install/install/
sudo php -q update.php
# Follow prompts to update
Enable automatic security updates:
# Install unattended-upgrades
sudo apt install unattended-upgrades
# Configure
sudo dpkg-reconfigure --priority=low unattended-upgrades
Subscribe to security announcements:
ISPConfig log locations:
| Log File | Purpose |
|---|---|
/var/log/ispconfig/ |
Main panel logs |
/var/log/ispconfig/auth.log |
Authentication logs |
/var/log/ispconfig/error.log |
Panel errors |
/var/log/ispconfig/cron.log |
Cron job execution |
/var/log/apache2/ |
Apache access/error logs |
/var/log/mail.log |
Mail server logs |
/var/log/mysql/error.log |
Database errors |
/var/log/fail2ban/fail2ban.log |
Fail2ban actions |
View recent activity:
# ISPConfig logs
tail -f /var/log/ispconfig/auth.log
# Filter for login events
grep -i "login\|auth" /var/log/ispconfig/auth.log
# Failed login attempts
grep -i "failed\|invalid" /var/log/ispconfig/auth.log | tail -50
# Cron execution
tail -f /var/log/ispconfig/cron.log
# Mail logs
tail -f /var/log/mail.log
Set up alerts for:
Configure log rotation:
# /etc/logrotate.d/ispconfig
/var/log/ispconfig/*.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 640 root adm
sharedscripts
postrotate
systemctl reload rsyslog > /dev/null 2>&1 || true
endscript
}
Rsyslog configuration:
# /etc/rsyslog.d/ispconfig.conf
:filename, contains, "ispconfig" /var/log/ispconfig/central.log
:filename, contains, "ispconfig" @syslog.example.com:514
:filename, contains, "mail" @syslog.example.com:514
# Restart rsyslog
sudo systemctl restart rsyslog
Filebeat for ELK stack:
# /etc/filebeat/modules.d/ispconfig.yml
- module: ispconfig
auth:
enabled: true
var.paths: ["/var/log/ispconfig/auth.log"]
error:
enabled: true
var.paths: ["/var/log/ispconfig/error.log"]
apache:
enabled: true
var.paths: ["/var/log/apache2/access.log", "/var/log/apache2/error.log"]
Install AIDE to detect file changes:
# Install AIDE
sudo apt install aide
# Initialize database
sudo aideinit
# Configure ISPConfig paths in /etc/aide/aide.conf
/usr/local/ispconfig/ p+i+n+u+g+s+m+c+acl+selinux+xattrs+sha512
/var/log/ispconfig/ p+i+n+u+g+s+m+c+acl+selinux+xattrs+sha512
/var/www/ p+i+n+u+g+s+m+c+acl+selinux+xattrs+sha512
/etc/postfix/ p+i+n+u+g+s+m+c+acl+selinux+xattrs+sha512
/etc/dovecot/ p+i+n+u+g+s+m+c+acl+selinux+xattrs+sha512
# Schedule daily checks
0 5 * * * /usr/bin/aide --check
ISPConfig provides limited CLI access. Most administration is via the web interface.
Restrict SSH access to administrators:
# Only root and admin users should have SSH access
sudo visudo
# Add specific commands allowed for specific users
admin-user ALL=(ALL) NOPASSWD: /usr/sbin/service apache2 restart
admin-user ALL=(ALL) NOPASSWD: /usr/sbin/service mysql restart
Audit CLI usage:
# Log all sudo commands
echo 'Defaults logfile="/var/log/sudo.log"' >> /etc/sudoers
# Or use auditd
sudo apt install auditd
sudo auditctl -w /usr/local/ispconfig/ -p wa -k ispconfig-changes
ISPConfig backup configuration:
# ISPConfig backups are typically managed via third-party tools
# Configure backup in /usr/local/ispconfig/server/lib/config.inc.php
# Or use external backup tools
# Example: rsync to remote server
rsync -avz --delete /var/www/ backup@example.com:/backup/www/
rsync -avz --delete /var/log/ispconfig/ backup@example.com:/backup/ispconfig-logs/
# MySQL database backup
mysqldump -u root -p --all-databases > /backup/mysql-all-db.sql
Backup security best practices:
chmod 700 /backupmysqldump -u root -p dbispconfig > backup.sql| Control | Status | Notes |
|---|---|---|
| 2FA enabled for all admins | ☐ | Via user settings |
| HTTPS with valid certificate | ☐ | Let’s Encrypt recommended |
| Firewall configured | ☐ | ISPConfig firewall + CSF |
| fail2ban deployed | ☐ | ISPConfig jails configured |
| Database hardened | ☐ | mysql_secure_installation |
| PHP hardening applied | ☐ | Disable dangerous functions |
| File permissions secured | ☐ | Config 600, directories 755 |
| SSH hardened | ☐ | Key-only auth, non-standard port |
| Mail server secured | ☐ | Postfix/Dovecot TLS |
| Backups encrypted | ☐ | Off-server storage |
| Centralized logging | ☐ | Forward to SIEM |
| Regular updates scheduled | ☐ | ISPConfig + system packages |
| File integrity monitoring | ☐ | AIDE configured |
If you suspect a security breach:
Isolate the server
# Block external access via firewall
sudo iptables -P INPUT DROP
sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Or via CSF
csf -d ALL
Preserve evidence
cp -r /var/log/ispconfig /root/ispconfig-logs-$(date +%Y%m%d-%H%M%S)
cp -r /var/log/apache2 /root/apache-logs-$(date +%Y%m%d-%H%M%S)
cp -r /var/log/mail.log /root/mail-log-$(date +%Y%m%d-%H%M%S)
mysqldump -u root -p --all-databases > /root/all-db-$(date +%Y%m%d-%H%M%S).sql
Review recent activity
# Failed logins
grep -i "failed" /var/log/ispconfig/auth.log | tail -100
# Check new accounts
mysql -u root -p dbispconfig -e "SELECT * FROM sys_user ORDER BY created_date DESC LIMIT 10"
# Check new domains
mysql -u root -p dbispconfig -e "SELECT * FROM web_domain ORDER BY created_date DESC LIMIT 10"
Check for unauthorized changes
# Compare with AIDE database
sudo aide --check
# Look for recently modified files
find /usr/local/ispconfig -type f -mtime -7 -ls
find /var/www -type f -mtime -7 -ls
Change all credentials - Admin passwords, database passwords, FTP accounts, SSH keys
Scan for malware
sudo apt install clamav clamav-daemon
sudo freshclam
sudo clamscan -r /var/www --move=/home/quarantine
Patch vulnerabilities - Update ISPConfig, PHP, web server, mail server, and all packages
Restore from clean backup - If compromise is severe
Notify affected users - If customer data was exposed