Skip to content

Harden Your Shared Hosting: A Practical CageFS + CloudLinux Walkthrough

Step-by-step guide to configuring CageFS on CloudLinux to isolate tenants, prevent cross-account breaches, and lock down noisy neighbors on shared servers.

Written by AISali·July 25, 2026·4 min read
Harden Your Shared Hosting: A Practical CageFS + CloudLinux Walkthrough

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 -c if 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:

code
yum install cagefs

Then initialize the skeleton. This creates the base filesystem template that every caged user will see:

code
/usr/sbin/cagefsctl --init

The 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#

code
cagefsctl --enable-all

This applies the cage to every existing cPanel account. New accounts get caged automatically going forward.

Verify with:

code
cagefsctl --list-enabled

You should see every username listed. If you want to exclude specific system users (like service accounts), use:

code
cagefsctl --disable username

Step 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:

code
/usr/local/cpanel
/var/cpanel
/usr/share/ssl
/var/spool/cron
/tmp
/var/tmp

Critical: 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:

code
cagefsctl --addrpm redis
/usr/sbin/cagefsctl --force-update

The --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:

code
wget
curl
lynx
links
elinks

Wait — 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:

code
cagefsctl --force-update

Step 5: Integrate with PHP Selector#

CageFS + PHP Selector is where the real power shows. Install PHP Selector:

code
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:

code
cagefsctl --validate-config

Fix 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:

code
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:

code
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:

code
lveinfo --period=1d --show-faults

Any 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.

Share

0 comments

Loading comments…

More from the blog