Rate Limiting, Throttling and Tenant Isolation in Web-CP — Protecting Multi-Tenant Environments at the Apache Layer
The fundamental operational challenge of multi-tenant shared hosting is resource contention. A single tenant running a misconfigured application, executing a runaway script, or being targeted by a volumetric attack can consume the server's available bandwidth, process pool, or MySQL connection limit — degrading or denying service to every other account on the system. In a hosting environment where resource fairness is an implicit part of the service contract, this is both a technical failure and a business failure.
Web-CP's architecture — with its four-tier control panel model separating server, reseller, domain, and personal views — provides a natural framework for implementing resource controls at the appropriate level. The following covers the Apache-layer mechanisms that enforce those controls, and how they integrate with the Web-CP configuration model.
The Resource Contention Problem — What Actually Fails
Before implementing controls, it is worth being precise about what fails in an unprotected multi-tenant environment.
Connection pool exhaustion. Apache's prefork and worker MPMs maintain a bounded pool of active processes or threads. A single tenant endpoint receiving sustained traffic — legitimately or through an attack — can saturate the pool, causing 503 Service Unavailable responses for all other domains on the server. The attack does not need to target the server's IP directly; it only needs to overwhelm the process pool.
MySQL connection limits. The MySQL max_connections setting is global. A tenant application with a connection leak, or one that opens connections without properly pooling them, can exhaust the connection table. New connection attempts from other tenants receive Too many connections errors until the leaking application is corrected or isolated.
Bandwidth saturation. In environments without per-tenant bandwidth limits, a single domain serving large files or receiving high download traffic can saturate the server's network interface. Other tenants experience increased latency or timeouts without any indication of what is causing the degradation.
Log disk space. Apache and application-level error logs in multi-tenant environments can fill the log partition if a single tenant generates high error volume. A full log partition causes Apache to stop writing logs for all tenants, which breaks the audit trail for security investigations.
Apache mod_ratelimit — Per-Directory Bandwidth Control
mod_ratelimit provides bandwidth throttling at the Apache virtual host or directory level. It limits the rate at which Apache delivers response data to a client, expressed in KiB/s.
# Enable in a VirtualHost template — manageable through Web-CP's VirtualHost editor
<VirtualHost *:80>
ServerName tenant-domain.com
DocumentRoot /home/tenant/public_html
# Throttle all responses to 500 KiB/s per connection
<Directory /home/tenant/public_html>
SetOutputFilter RATE_LIMIT
SetEnv rate-limit 500
</Directory>
# Apply different limits to media directories
<Directory /home/tenant/public_html/downloads>
SetOutputFilter RATE_LIMIT
SetEnv rate-limit 200
</Directory>
</VirtualHost>
The rate-limit environment variable is expressed in KiB/s per connection, not per tenant. A tenant with many concurrent connections can still consume significant bandwidth — mod_ratelimit is a per-connection control, not a per-IP or per-account aggregate control. Combine it with connection limits (below) for aggregate bandwidth management.
Integration with Web-CP: Web-CP's VirtualHost templates can be modified at the server level to include mod_ratelimit directives for all hosted domains, or the reseller control panel can expose per-domain bandwidth settings that map to specific rate-limit values.
Apache mod_evasive — Connection Rate Limiting and DDoS Mitigation
mod_evasive monitors incoming request rates and blocks IPs that exceed configurable thresholds. It is a defensive control against HTTP flooding and application-layer DDoS attacks.

Tuning for shared hosting: The default thresholds in mod_evasive are appropriate for single-site servers but may produce false positives in multi-tenant environments where a single IP address may represent a NAT gateway serving many legitimate users. Tune DOSSiteCount upward (100–200) and DOSBlockingPeriod downward (5 seconds) for shared hosting to reduce false positive impact while still blocking sustained floods.
The tenant isolation implication: mod_evasive operates at the server level, not the tenant level. An IP blocked for excessive requests to tenant A is also blocked from accessing tenant B. In a hosting environment, this is usually the correct behavior — an IP conducting a HTTP flood is a server-level threat, not a single-tenant threat. Document this behavior in your terms of service.
Per-Tenant Process Limits with Apache MPM and PHP-FPM
The most effective tenant isolation mechanism is separating PHP execution into per-tenant process pools using PHP-FPM (FastCGI Process Manager). Each tenant's PHP processes run under the tenant's system user, with configurable process count and memory limits.
# /etc/php/8.3/fpm/pool.d/tenant-domain.conf
[tenant-domain]
user = tenant_user
group = tenant_user
; PHP-FPM socket for this pool
listen = /run/php/php8.3-fpm-tenant-domain.sock
listen.owner = www-data
listen.group = www-data
; Process management
pm = dynamic
pm.max_children = 10 ; Maximum concurrent PHP processes for this tenant
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
pm.max_requests = 500 ; Restart worker after 500 requests — prevents memory leaks
; Resource limits
php_admin_value[memory_limit] = 128M
php_admin_value[upload_max_filesize] = 32M
php_admin_value[max_execution_time] = 30
php_admin_flag[allow_url_fopen] = off
; Restrict open_basedir to tenant's directory
php_admin_value[open_basedir] = /home/tenant_user/:/tmp/
The corresponding Apache VirtualHost configuration proxies PHP requests to the tenant-specific FPM socket:
<VirtualHost *:80>
ServerName tenant-domain.com
DocumentRoot /home/tenant_user/public_html
<FilesMatch "\.php$">
SetHandler "proxy:unix:/run/php/php8.3-fpm-tenant-domain.sock|fcgi://localhost"
</FilesMatch>
</VirtualHost>
What this achieves:
A runaway PHP process in one tenant's pool cannot consume process slots allocated to another tenant
Memory exhaustion in one pool does not affect other tenants' PHP execution
Security vulnerabilities in one tenant's application cannot be exploited to read files belonging to another tenant (enforced by
open_basedirand separate user accounts)Resource usage per tenant is visible and auditable through the FPM pool's status endpoint
Integration with Web-CP: Web-CP's domain account creation can be scripted to generate a PHP-FPM pool configuration file for each new domain, using the domain account's system user as the pool user. The server control panel's templating system provides the hook for this automation.
MySQL Per-Tenant Resource Controls
MySQL's resource control mechanisms are less granular than Apache's, but several controls are available at the user level:

MAX_USER_CONNECTIONS is the most important limit for shared hosting. Setting it to 20 per tenant prevents any single tenant from exhausting the server's max_connections limit. The appropriate value depends on the tenant's application profile — a WordPress site with persistent connections needs fewer than an application with poorly managed connection pooling.
Monitoring query performance: Enable the MySQL slow query log to identify tenants running expensive queries:

Queries exceeding the threshold are logged with the database user, query text, and execution time. In a multi-tenant environment, this is the primary tool for identifying tenants whose database usage is degrading shared performance.
Log Rotation and Disk Isolation
Log disk space exhaustion is a common and underappreciated failure mode in shared hosting. Each Apache VirtualHost generates at least one access log and one error log. In a high-traffic environment, a single misbehaving tenant can generate gigabytes of log data per day.
# Per-tenant log configuration in VirtualHost template
<VirtualHost *:80>
ServerName tenant-domain.com
# Separate log files per domain
ErrorLog /var/log/apache2/tenant-domain-error.log
CustomLog /var/log/apache2/tenant-domain-access.log combined
# Pipe logs through rotatelogs to limit individual file size
ErrorLog "|/usr/bin/rotatelogs /var/log/apache2/tenant-domain-error.%Y%m%d.log 86400"
CustomLog "|/usr/bin/rotatelogs /var/log/apache2/tenant-domain-access.%Y%m%d.log 86400" combined
</VirtualHost>
Configure logrotate to enforce retention limits:
# /etc/logrotate.d/web-cp-domains
/var/log/apache2/tenant-*-access.*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
sharedscripts
postrotate
/usr/bin/systemctl reload apache2 > /dev/null 2>&1 || true
endscript
}
Mounting the log partition on a separate filesystem — either a separate physical volume or a dedicated LVM logical volume — ensures that log growth in one area cannot fill the root filesystem and cause system-level failures.
Operationalizing Tenant Isolation
The controls above are individually useful but operationally significant only when they are applied consistently. In a Web-CP environment, consistency requires that:
VirtualHost templates include rate limiting and FPM proxy directives by default — not as optional additions
PHP-FPM pool configuration is generated automatically when a domain account is created
MySQL user creation includes resource limits as part of the standard provisioning script
Log rotation is applied globally through a logrotate configuration that matches all tenant log patterns
The server control panel in Web-CP provides the configuration entry points for VirtualHost and DNS templates. PHP-FPM pool management and MySQL user provisioning require scripting at the server level, but they can be triggered from Web-CP's account creation hooks.
Tenant isolation is not a feature that can be retrofitted to a running hosting environment without operational disruption. It is most effectively built into the provisioning process from the beginning, where the marginal cost of applying it to each new domain is near zero.