Why Tenant Isolation Is Non-Negotiable in 2024#
Shared hosting's biggest liability isn't downtime or slow support — it's the blast radius. A single compromised WordPress plugin on one account can dump /etc/passwd, read neighboring users' wp-config.php files, or spawn cryptominers that throttle the entire node. If you're running a reseller operation or managing multi-tenant cPanel/WHM servers, you've either experienced this or you're living on borrowed time.
CageFS, bundled with CloudLinux OS, creates per-user filesystem containers so each account literally cannot see the others. Combined with PHP Selector and resource limits (LVE), it's the closest thing to container-level isolation you can get without the overhead of full virtualization. This guide walks you through deploying and hardening it properly — not just flipping a switch.
Prerequisites#
Before you start, make sure you have:
- CloudLinux OS installed and activated (convert from CentOS/AlmaLinux with
cldeploy -cif needed) - WHM/cPanel or another supported panel (DirectAdmin, Plesk all work)
- Root SSH access to the server
- A maintenance window — CageFS initial deployment requires remounting the filesystem skeleton
Step 1: Install CageFS#
If CageFS isn't already present, install it via yum:
yum install cagefsThen initialize the skeleton. This creates the base filesystem template that every caged user will see:
/usr/sbin/cagefsctl --initThe skeleton build takes 5–15 minutes depending on disk speed. On NVMe it's fast; on spinning RAID, grab a coffee. The skeleton includes binaries, libraries, and config files that users need — and critically, excludes everything they don't.
Step 2: Enable CageFS for All Users#
cagefsctl --enable-allThis applies the cage to every existing cPanel account. New accounts get caged automatically going forward.
Verify with:
cagefsctl --list-enabledYou should see every username listed. If you want to exclude specific system users (like service accounts), use:
cagefsctl --disable usernameStep 3: Configure the Skeleton Properly#
The default skeleton is a starting point, not a finished product. Edit /etc/cagefs/cagefs.mp to control mount points. The default already includes essentials like /var/cpanel and /usr/local/cpanel, but you'll want to verify:
/usr/local/cpanel
/var/cpanel
/usr/share/ssl
/var/spool/cron
/tmp
/var/tmpCritical: tmp directories. Each caged user should have their own /tmp. CageFS handles this, but confirm that the global /tmp isn't leaking. Check /etc/cagefs/cagefs.base.cfg and ensure tmpwatch is configured per-user.
If you run custom software (Redis, Node.js, Python), add their binaries to the skeleton:
cagefsctl --addrpm redis
/usr/sbin/cagefsctl --force-updateThe --force-update pushes changes to all existing cages.
Step 4: Lock Down Dangerous Binaries#
By default, CageFS exposes common utilities. But some are risky in a shared environment. Edit /etc/cagefs/disable.commands to block:
wget
curl
lynx
links
elinksWait — why block wget and curl? Because attackers use them to pull down malware payloads post-exploitation. If a user legitimately needs them (e.g., for cron-based scripts), you can whitelist per-user by creating a custom skeleton variant. For most shared hosting accounts, blocking outbound fetch utilities dramatically reduces the impact of a compromised PHP application.
After editing:
cagefsctl --force-updateStep 5: Integrate with PHP Selector#
CageFS + PHP Selector is where the real power shows. Install PHP Selector:
yum install ea-php* alt-php*(Use ea-php for cPanel's EasyApache or alt-php for CloudLinux's own builds.)
Users can now pick their PHP version (5.6 through 8.3) and toggle extensions per-site from cPanel. Each version runs inside its own cage, so a customer running legacy PHP 7.4 for one app can't affect a neighbor on PHP 8.3.
Verify the integration:
cagefsctl --validate-configFix any flagged issues before proceeding.
Step 6: Set LVE Resource Limits#
CageFS isolates the filesystem; LVE isolates resources. Without LVE, a single runaway PHP process can eat all CPU cores. Configure defaults in WHM → CloudLinux LVE Manager, or via CLI:
lvectl set default --maxEntryProcs=20 --pmem=1024M --speed=100%Reasonable starting limits for shared hosting:
- CPU: 100% (one full core)
- RAM (PMEM): 1–2 GB
- Entry processes: 20 (prevents fork bombs)
- I/O: 1024 KB/s (prevents disk saturation)
- IOPS: 1024
Tune per-plan after monitoring with lveinfo over a few weeks. Overselling is fine; unmanaged contention is not.
Step 7: Verify and Monitor#
SSH into a caged user to confirm isolation:
su - username -s /bin/bash
ls /home/You should see only that user's home directory. Try cat /etc/shadow — it should fail. Try listing /proc for other users' processes — nothing.
Set up automated alerts for LVE faults:
lveinfo --period=1d --show-faultsAny customer consistently hitting limits needs a plan upgrade, not a free pass to degrade the node.
The Bottom Line#
CageFS with CloudLinux isn't optional for serious shared hosting — it's table stakes. The configuration above takes under an hour on a fresh node and eliminates an entire class of cross-account vulnerabilities. Combined with sensible LVE limits, it lets you safely pack accounts onto nodes without one bad actor ruining everyone's day. If you're running a hosting business on bare CentOS or AlmaLinux without this layer, you're one compromised wp-config.php away from a very bad week.
0 comments
Loading comments…