Secure multi‑tenant hosting with CloudLinux: enable CageFS isolation and PHP Selector to sandbox users and assign per‑account PHP versions.
6 min read
Running several websites or applications on a single server is a common cost-saving strategy, but it also raises security concerns. If one account is compromised, an attacker could potentially reach files belonging to other users. CageFS and the PHP Selector are CloudLinux features that isolate each tenant and let you assign the exact PHP version they need, without affecting anyone else.
Why Use CageFS and PHP Selector?
File-system isolation: CageFS creates a virtualized file system for each user, exposing only the files they own and a minimal set of system binaries.
Reduced attack surface: Even if a user gains shell access, they cannot see or modify other users' data.
Flexible PHP versions: The PHP Selector lets each account run the PHP version required by its application (e.g., 7.4, 8.0, 8.2) without changing the global interpreter.
Compliance friendly: Isolated environments help meet security standards such as PCI-DSS or GDPR.
Prerequisites
A CloudLinux installation on a RHEL-compatible distro (AlmaLinux 8 / Rocky 8 / RHEL 8). CloudLinux is not supported on Debian/Ubuntu; migration or alternative isolation tools would be required.
Root (or sudo) access to the server.
cPanel/WHM installed, as CageFS and PHP Selector integrate with it. The steps also work with DirectAdmin, but WHM references are used here.
At least 2 GB of RAM for a small VPS; more memory is recommended for many tenants.
Installing CloudLinux and the Required Packages
First, ensure CloudLinux is active and that the cagefs and alt-php packages are installed.
1. Register the CloudLinux license
# clnreg_activate <YOUR-LICENSE-KEY>
This command contacts CloudLinux’s licensing server and registers the host.
2. Install CageFS and the PHP Selector packages
Run the following commands on an AlmaLinux/Rocky/RHEL 8 system (using dnf):
alt-php – Provides the PHP Selector and the collection of alternate PHP versions.
Enabling and Configuring CageFS
1. Build the initial CageFS skeleton
# cagefsctl --init
This command creates the base skeleton that will be copied into each user’s virtual environment. It includes essential binaries, libraries, and configuration files.
2. Enable CageFS for all existing accounts
# cagefsctl --enable-all
After enabling, each user’s home directory will be automatically wrapped in a CageFS mount when they log in via SSH, FTP, or cPanel.
3. Verify the installation
# cagefsctl --list-enabled
The output should list every account that now runs inside CageFS. You can also test with a regular user:
$ ssh user@example.com
$ cagefsctl --list
If the command shows the user’s virtual file system, CageFS is active.
4. Fine-tune the skeleton (optional)
When an application needs extra binaries (e.g., ffmpeg or git) that are not included by default, add them to the skeleton:
The --rebuild command regenerates the skeleton with the new files.
Setting Up the PHP Selector
1. Enable the PHP Selector in WHM
Log in to WHM as root.
Navigate to Home → Software → PHP Selector.
Click Enable PHP Selector. WHM will automatically populate the list of available PHP versions (e.g., 7.4, 8.0, 8.1, 8.2).
2. Assign a default PHP version for new accounts
In the same interface, set the Default PHP version for new accounts. This version will be used unless the user changes it in their cPanel.
3. Allow users to change their PHP version
Under PHP Selector Settings, enable the option Allow users to select PHP version. Users will then see a Select PHP Version button in their cPanel Software section.
4. Install additional PHP extensions (if needed)
CloudLinux ships with a set of common extensions, but you can add more per version. Example for PHP 8.2:
Replace 82 with 81, 80, etc., to install extensions for other versions.
5. Verify the selector works
Log in to a cPanel account, go to Select PHP Version, and switch to a different version. Then create a phpinfo.php file with the following content:
<?php phpinfo(); ?>
Open the file in a browser. The “PHP Version” line should reflect the version you selected.
Testing the Combined Setup
It’s important to confirm that CageFS and the PHP Selector work together without conflicts.
1. Create two test accounts
In WHM, create userA and userB.
Assign userA PHP 7.4 and userB PHP 8.2 via the PHP Selector.
2. Attempt cross-account file access
Log in as userA via SSH and try to list userB’s home directory:
$ ls /home/userB
The command should return Permission denied, confirming CageFS isolation.
3. Run a PHP script that uses an extension
Place a script in userB that calls mysqli_connect(). With the alt-php82-php-mysqlnd package installed, the script should run without errors. If the extension is missing, PHP will emit an “undefined function” warning, indicating that the extension needs to be installed for that version.
Maintaining and Updating the Environment
Regular updates: Keep CloudLinux and its packages up to date with dnf update. Updates often include security patches for the kernel modules used by CageFS.
Rebuilding the skeleton: Whenever you install new system binaries that should be visible inside cages, run cagefsctl --add <path> && cagefsctl --rebuild.
Monitoring: Use WHM’s CloudLinux → CageFS → Statistics page to view per-user resource usage and detect abnormal activity.
Backup considerations: CageFS does not interfere with standard file backups. Ensure your backup solution runs outside the cage (e.g., via rsync as root) so that all user data is captured.
Conclusion
Enabling CageFS and the PHP Selector on a CloudLinux-based server gives each tenant a sandboxed environment and the exact PHP runtime they need. This combination reduces the risk of cross-account breaches while preserving the flexibility required by modern web applications. Follow the step-by-step instructions above, test the setup thoroughly, and keep the system patched to maintain a secure, multi-tenant hosting platform for your clients.