ServerPilot is a commercial web hosting control panel designed specifically for WordPress hosting on Ubuntu and Debian servers. Unlike traditional control panels, ServerPilot uses a cloud-based management interface with local agents installed on each server. It automates SSL certificates (Let’s Encrypt), server updates, and WordPress deployment. ServerPilot’s simplified architecture and focus on WordPress makes it popular among developers and agencies, but proper security hardening is still essential for production environments.
ServerPilot supports TOTP-based 2FA for all user accounts. Enable it immediately after registration.
Enable 2FA via ServerPilot Dashboard:
Force 2FA for team members:
Secure your ServerPilot account:
# ServerPilot is cloud-managed; most security is via dashboard
# But you should secure SSH access to your servers
# Change server root password
sudo passwd root
Best practices:
Manage team members via ServerPilot Dashboard:
Remove unused team members:
Restrict server access by IP:
Using UFW (ServerPilot servers):
# Allow only from management network for SSH
sudo ufw allow from 10.0.0.0/24 to any port 22
# Allow ServerPilot IPs (required for panel functionality)
# ServerPilot uses various IPs; don't block outbound
# Allow HTTP/HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Enable firewall
sudo ufw enable
Using iptables:
# Allow only from management network for SSH
sudo iptables -A INPUT -p tcp --dport 22 -s 10.0.0.0/24 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 22 -j DROP
# Allow HTTP/HTTPS
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
sudo iptables-save > /etc/iptables/rules.v4
Note: ServerPilot requires outbound connectivity to function. Don’t block outbound traffic to ServerPilot services.
ServerPilot cloud dashboard session settings:
Secure SSH session on servers:
# Edit /etc/ssh/sshd_config
sudo nano /etc/ssh/sshd_config
# Session settings
ClientAliveInterval 300
ClientAliveCountMax 2
LoginGraceTime 60
MaxAuthTries 3
Restart SSH:
sudo systemctl restart sshd
ServerPilot dashboard password requirements:
Server-level password policy:
# Install libpam-pwquality
sudo apt install libpam-pwquality
# Configure /etc/pam.d/common-password
password required pam_pwquality.so retry=3 minlen=12 dcredit=-1 ucredit=-1 ocredit=-1 lcredit=-1
# Password history (prevent reuse)
sudo apt install libpam-pwhistory
password required pam_pwhistory.so use_authtok remember=12 enforce_for_root
ServerPilot automatically provisions Let’s Encrypt certificates:
Verify SSL status:
# Check certificate status
sudo serverpilot-check-certs
# Or manually check
sudo ls -la /etc/letsencrypt/live/
Force HTTPS for WordPress sites:
# ServerPilot dashboard → Select App → WordPress
# Enable "Force HTTPS" option
# Or via wp-config.php
define('FORCE_SSL_ADMIN', true);
Custom SSL certificates (if needed):
# ServerPilot allows custom certificates
# Dashboard → App → SSL → Upload Custom Certificate
# Or via CLI for advanced users
sudo cp /path/to/cert.crt /etc/letsencrypt/live/domain.com/fullchain.pem
sudo cp /path/to/key.key /etc/letsencrypt/live/domain.com/privkey.pem
Default ServerPilot ports:
| Port | Service | Required |
|---|---|---|
| 80 | HTTP | Yes |
| 443 | HTTPS | Yes |
| 22 | SSH | Recommended |
| 3306 | MySQL | No (localhost only) |
ServerPilot automatically configures UFW:
# Check firewall status
sudo ufw status verbose
# ServerPilot typically allows:
# - Port 80 (HTTP)
# - Port 443 (HTTPS)
# - Port 22 (SSH) - configurable
Additional firewall hardening:
# Rate limit SSH
sudo ufw limit 22/tcp
# Deny MySQL from external access (should already be bound to localhost)
sudo ufw deny 3306/tcp
# Log denied packets
sudo ufw logging on
Verify firewall rules:
sudo ufw status numbered
ServerPilot includes fail2ban by default:
Check fail2ban status:
sudo systemctl status fail2ban
sudo fail2ban-client status
ServerPilot default jails:
# List available jails
sudo fail2ban-client status
# Typically includes:
# - apache-auth (Apache authentication failures)
# - apache-overflows (Apache overflow attacks)
# - apache-badbots (Apache bad bot activity)
# - sshd (SSH brute force)
View banned IPs:
# Check SSH jail
sudo fail2ban-client status sshd
# Check Apache jails
sudo fail2ban-client status apache-auth
# Unban IP if needed
sudo fail2ban-client set sshd unbanip <IP>
Custom fail2ban configuration:
# Edit /etc/fail2ban/jail.local
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 300
[apache-auth]
enabled = true
port = http,https
filter = apache-auth
logpath = /var/log/apache2/*error.log
maxretry = 5
bantime = 7200
findtime = 300
Restart fail2ban:
sudo systemctl restart fail2ban
ServerPilot uses Nginx as reverse proxy. Configure rate limiting:
Edit Nginx configuration:
# /etc/nginx/nginx.conf or /etc/nginx/conf.d/rate-limit.conf
http {
# Rate limiting zone
limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
# Apply to WordPress login
server {
location /wp-login.php {
limit_req zone=login burst=3 nodelay;
}
location /xmlrpc.php {
limit_req zone=login burst=3 nodelay;
# Or deny entirely if not needed
# deny all;
}
location / {
limit_req zone=one burst=10 nodelay;
}
}
}
Test Nginx configuration:
sudo nginx -t
sudo systemctl reload nginx
Protect against XML-RPC attacks:
# Disable XML-RPC if not needed (Jetpack, etc.)
# Add to .htaccess or Nginx config
# Nginx:
location = /xmlrpc.php {
deny all;
access_log off;
log_not_found off;
}
ServerPilot agent configuration:
# Agent config location
cat /etc/serverpilot/config.json
# Agent runs as root, manages web server
# Don't modify config unless instructed by ServerPilot support
Disable automatic updates (not recommended):
# ServerPilot automatically updates packages for security
# Disabling is not recommended, but can be done:
# Edit /etc/serverpilot/config.json
# Set "auto_updates": false
# Restart agent
sudo systemctl restart serverpilot-agent
ServerPilot 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 MySQL (/etc/mysql/mysql.conf.d/mysqld.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
ServerPilot database user management:
# ServerPilot creates database users automatically
# Users are restricted to their databases only
# View database users
mysql -u root -p -e "SELECT User, Host FROM mysql.user;"
# Verify users are localhost only
# Should show 'username'@'localhost' not 'username'@'%'
ServerPilot manages PHP versions. Configure security settings:
Edit PHP configuration (/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
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
[Open Basedir]
open_basedir = /var/www:/tmp:/var/tmp
Restart PHP-FPM:
sudo systemctl restart php*-fpm
ServerPilot PHP version management:
# List available PHP versions
serverpilot-list-php
# Change PHP version for an app
serverpilot-update-php <app-id> 8.1
# Check current PHP version
php -v
ServerPilot default permissions:
# Web root permissions
ls -la /var/www/
# Should be:
# owner: www-data:www-data
# directories: 755
# files: 644
Secure WordPress installation:
# WordPress core files
find /var/www/app-name/public_html -type f -exec chmod 644 {} \;
find /var/www/app-name/public_html -type d -exec chmod 755 {} \;
# wp-config.php
chmod 600 /var/www/app-name/public_html/wp-config.php
# Uploads directory
chmod 755 /var/www/app-name/public_html/wp-content/uploads
chown www-data:www-data /var/www/app-name/public_html/wp-content/uploads
Protect sensitive files:
# /etc/apache2/conf-available/security.conf or .htaccess
# Prevent access to sensitive files
<FilesMatch "(wp-config\.php|\.sql|\.log|\.bak|\.old)$">
Require all denied
</FilesMatch>
# Prevent directory listing
<Directory /var/www>
Options -Indexes
</Directory>
Disable PHP execution in uploads:
# /var/www/app-name/public_html/wp-content/uploads/.htaccess
<FilesMatch "\.(php|php3|php4|php5|phtml)$">
Deny from all
</FilesMatch>
Secure SSH access:
# Edit /etc/ssh/sshd_config
sudo nano /etc/ssh/sshd_config
# Key settings:
Port 2222 # Change from default (optional)
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AuthenticationMethods publickey
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2
AllowUsers your-username
X11Forwarding no
AllowTcpForwarding no
Restart SSH:
sudo systemctl restart sshd
Use SSH keys:
# Generate key pair
ssh-keygen -t ed25519 -C "your-email@example.com"
# Copy to server
ssh-copy-id -p 22 user@server-ip
# Test key authentication
ssh -p 22 user@server-ip
ServerPilot is WordPress-focused. Harden WordPress:
Security plugins (recommended):
wp-config.php hardening:
// Add to wp-config.php
define('DISALLOW_FILE_EDIT', true);
define('DISALLOW_FILE_MODS', true);
define('WP_AUTO_UPDATE_CORE', 'minor');
define('FORCE_SSL_ADMIN', true);
define('SECURE_AUTH_KEY', 'unique-phrase-here');
define('LOGGED_IN_KEY', 'unique-phrase-here');
define('NONCE_KEY', 'unique-phrase-here');
define('SECURE_AUTH_SALT', 'unique-phrase-here');
define('LOGGED_IN_SALT', 'unique-phrase-here');
define('NONCE_SALT', 'unique-phrase-here');
// Limit post revisions
define('WP_POST_REVISIONS', 3);
// Set autosave interval
define('AUTOSAVE_INTERVAL', 300);
Security headers via ServerPilot:
# ServerPilot dashboard → App → Add Config File
# Name: security-headers.conf
# Add headers:
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';"
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
ServerPilot manages updates automatically:
Check update status:
# Check agent status
sudo systemctl status serverpilot-agent
# Check for pending updates
sudo apt update
sudo apt list --upgradable
Manual WordPress updates:
# Via ServerPilot dashboard
# Apps → Select App → WordPress → Update
# Or via WP-CLI
cd /var/www/app-name/public_html
wp core update
wp plugin update --all
wp theme update --all
ServerPilot log locations:
| Log File | Purpose |
|---|---|
/var/log/serverpilot/ |
ServerPilot agent logs |
/var/log/serverpilot/agent.log |
Agent operation logs |
/var/log/apache2/ |
Apache access/error logs |
/var/log/nginx/ |
Nginx access/error logs |
/var/log/mysql/error.log |
Database errors |
/var/log/auth.log |
Authentication logs |
/var/log/fail2ban/fail2ban.log |
Fail2ban actions |
View recent activity:
# ServerPilot agent logs
tail -f /var/log/serverpilot/agent.log
# Apache access logs
tail -f /var/log/apache2/access.log
# Filter for login events
grep -i "login\|auth" /var/log/auth.log
# Failed login attempts
grep -i "failed\|invalid" /var/log/auth.log | tail -50
# Nginx logs
tail -f /var/log/nginx/error.log
Set up alerts for:
Configure log rotation:
# /etc/logrotate.d/serverpilot
/var/log/serverpilot/*.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 640 root adm
}
Rsyslog configuration:
# /etc/rsyslog.d/serverpilot.conf
:filename, contains, "serverpilot" /var/log/serverpilot/central.log
:filename, contains, "serverpilot" @syslog.example.com:514
:filename, contains, "apache" @syslog.example.com:514
# Restart rsyslog
sudo systemctl restart rsyslog
Filebeat for ELK stack:
# /etc/filebeat/modules.d/serverpilot.yml
- module: serverpilot
agent:
enabled: true
var.paths: ["/var/log/serverpilot/agent.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 paths in /etc/aide/aide.conf
/var/www/ p+i+n+u+g+s+m+c+acl+selinux+xattrs+sha512
/etc/letsencrypt/ p+i+n+u+g+s+m+c+acl+selinux+xattrs+sha512
/etc/serverpilot/ p+i+n+u+g+s+m+c+acl+selinux+xattrs+sha512
# Schedule daily checks
0 5 * * * /usr/bin/aide --check
Install Wordfence or similar:
# Via WP-CLI
cd /var/www/app-name/public_html
wp plugin install wordfence --activate
# Configure via WordPress admin
# Dashboard → Wordfence → Scan
Monitor file changes:
# Wordfence real-time monitoring
# Or use AIDE for system-level monitoring
# Check for modified WordPress files
wp core verify-checksums
wp plugin verify-checksums --all
wp theme verify-checksums --all
ServerPilot provides REST API for automation. Secure it properly:
Generate API keys:
API security best practices:
Example API call:
curl -X GET "https://api.serverpilot.io/v2/servers" \
-H "Authorization: Bearer YOUR_API_KEY"
Audit API usage:
# ServerPilot dashboard shows API usage
# Account Settings → API Keys → View Usage
# Monitor for unusual activity
# Set up alerts for high API usage
| Control | Status | Notes |
|---|---|---|
| 2FA enabled for dashboard | ☐ | Via account settings |
| HTTPS with Let’s Encrypt | ☐ | Auto-provisioned |
| Firewall configured | ☐ | UFW with ServerPilot rules |
| fail2ban deployed | ☐ | Default jails enabled |
| Database hardened | ☐ | mysql_secure_installation |
| PHP hardening applied | ☐ | Disable dangerous functions |
| File permissions secured | ☐ | WordPress best practices |
| SSH hardened | ☐ | Key-only auth recommended |
| WordPress hardened | ☐ | Security plugin + headers |
| API keys secured | ☐ | If using API |
| Centralized logging | ☐ | Forward to SIEM |
| File integrity monitoring | ☐ | AIDE or Wordfence |
If you suspect a security breach:
Isolate affected WordPress sites
# Put site in maintenance mode
# ServerPilot dashboard → App → Maintenance Mode
# Or via .htaccess
echo "RewriteEngine On
RewriteCond %{REMOTE_ADDR} !^10\.0\.0\."
RewriteRule .* /maintenance.html [R=302,L]" > /var/www/app-name/public_html/.htaccess
Preserve evidence
cp -r /var/log/serverpilot /root/serverpilot-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/www/app-name/public_html /root/wp-backup-$(date +%Y%m%d-%H%M%S)
mysqldump -u root -p app_database > /root/db-$(date +%Y%m%d-%H%M%S).sql
Review recent activity
# Failed logins
grep -i "failed" /var/log/auth.log | tail -100
# WordPress activity (if logging enabled)
grep "wp-login" /var/log/apache2/access.log | tail -50
# Check for new users
mysql -u root -p app_database -e "SELECT * FROM wp_users ORDER BY ID DESC LIMIT 10"
Check for unauthorized changes
# Compare with AIDE database
sudo aide --check
# Verify WordPress checksums
cd /var/www/app-name/public_html
wp core verify-checksums
wp plugin verify-checksums --all
Scan for malware
# Wordfence scan
# WordPress Admin → Wordfence → Scan
# Or via CLI
sudo apt install clamav clamav-daemon
sudo freshclam
sudo clamscan -r /var/www --move=/home/quarantine
Change all credentials - ServerPilot password, WordPress admin passwords, database passwords, API keys
Restore from clean backup - If compromise is severe
# ServerPilot dashboard → Backups → Restore
# Or manual restore from your backup solution
Notify affected users - If customer data was exposed