LVE stops one account from using another account's resources. CageFS stops one account from seeing another account's files. It is the second half of what makes a CloudLinux server safe to share, and it is required by PHP Selector, so nearly every CloudLinux server runs it. This guide explains the attack it prevents, how to set it up, what changes for your users, and what to do when something they rely on stops working.
The threat it stops
On a plain shared server, every user can read /etc/passwd and learn every other account's username, look through /proc and see other users' running commands with their arguments, and walk /home looking for world-readable files. That last one is the real problem. A WordPress install with a misconfigured wp-config.php permission, or a symlink placed by a compromised site pointing at another user's config, hands over database credentials. Automated malware does exactly this: land on one account, harvest the credentials of every other account on the box.
CageFS removes the target. Inside the cage, /home contains only the user's own directory, /proc shows only their own processes, /etc/passwd lists only them, and the paths and binaries they can reach are a curated subset of the real server. There is nothing to enumerate and nowhere to point a symlink.
How it works
CageFS builds a skeleton filesystem under /usr/share/cagefs-skeleton: copies of the binaries, libraries and configuration files a hosting user legitimately needs (PHP, Perl, Python, the shell, curl, git, mysql, and so on). When a caged user's process starts, whether it is a PHP request, a cron job or an SSH login, the kernel mounts a private view for it: the skeleton, plus the user's real home directory, plus a private /tmp. Everything the user does happens inside that view. Their files are still exactly where they always were; only their view of the server has changed.
The skeleton is shared and read-only, so the disk cost is paid once, around 7 GB, however many users you have.
Initialise and enable it
Install the package, build the skeleton, and turn it on for everyone:
yum install cagefs
cagefsctl --init
cagefsctl --enable-all--init copies the skeleton and takes several minutes. --enable-all sets the mode so that every current and future user is caged unless individually excluded. The opposite mode, cagefsctl --toggle-mode disable-all, cages nobody unless individually enabled; use it only while you are testing on a live server with one or two accounts:
cagefsctl --toggle-mode disable-all
cagefsctl --enable bob
cagefsctl --list-enabledcagefsctl --disable bob takes a user out of the cage in either mode. In DirectAdmin, Admin Level → Extra Features → CloudLinux Manager → Users shows each account's CageFS status with a toggle.
If you are setting up a new server, the order is in installing CloudLinux on a DirectAdmin server: convert, switch CustomBuild to lsphp, then CageFS, then alt-php.
Keep the skeleton up to date
The skeleton is a copy, so anything you install or update on the server afterwards is not in it until you say so. After every yum update, every CustomBuild PHP rebuild and every new alt-php version:
cagefsctl --update--update only copies what has changed. cagefsctl --force-update rebuilds the whole skeleton and is the fix when something is inexplicably missing. cagefsctl --remount-all re-mounts every user's cage without rebuilding, needed after changing mount points. cagefsctl --update-etc refreshes the filtered copies of /etc files, such as after adding users outside the panel.
To add a binary of your own, say a deploy tool under /usr/local/bin, create a file in /etc/cagefs/conf.d/ listing the paths to copy, then run --update. Directories that must be visible inside every cage rather than copied go in /etc/cagefs/cagefs.mp, followed by --remount-all.
What changes for users
Mostly nothing, which is the goal: a WordPress site does not know it is caged. The differences a user can notice:
/tmp is private. Each user's temporary files land in ~/.cagefs/tmp, and a full one affects only them. Anything that expects to share /tmp with another user breaks, which is rare.
Only the skeleton's binaries exist. which composer may return nothing even though composer is installed on the server, until you add it to the skeleton.
Cron jobs and SSH sessions run inside the cage. A cron command that worked as root while you were testing may fail as the user because the binary or the path is not in the skeleton.
PHP Selector works. Because alt-php lives inside the skeleton, users can switch versions and extensions in Select PHP Version, and PHP Selector refuses to serve a user who is not caged.
Common breakages and fixes
A site broke the moment CageFS was enabled. Usually a missing binary or library the site calls through exec(), such as convert or wkhtmltopdf. Disable the user temporarily to confirm, add the binary via /etc/cagefs/conf.d/, run cagefsctl --update, and re-enable.
A cron job stopped running. Log in as the user and run the command from the crontab by hand; the error tells you what is missing. Check the PHP path is one that exists in the cage, such as /opt/alt/php83/usr/bin/php or the CustomBuild binary the user's domain uses.
A user can see other accounts' processes. They are not caged. cagefsctl --list-enabled will confirm; check whether the user was created while the mode was disable-all, or was added to /etc/cagefs/exclude/ at some point.
PHP Selector says the user is not enabled. Same cause; enable the user in CageFS.
Everything is odd after an update. cagefsctl --force-update, then cldiag --all, which names the failing check.
CageFS and LVE together are what let one server hold customers who have never met. On a VPSPioneer managed VPS we enable CageFS as part of a CloudLinux conversion.