You need to import a large database dump, restore a massive WordPress backup, or let users upload files exceeding 1GB. You open the configuration file, edit php.ini, save, restart services, and test again. To your frustration, the application still claims the file exceeds the upload limit, and phpinfo() continues to display the old baseline values.
On servers running the DirectAdmin and CloudLinux stack with PHP Selector and CageFS, this is a classic stumbling block. CloudLinux’s layered architecture does not directly parse traditional global /etc/php.ini files for individual tenant accounts. Furthermore, subtle PHP byte shorthand notation traps and Nginx buffer restrictions quietly block large payloads before they ever reach your scripts.
Here is a practical breakdown of how this configuration architecture works, how to avoid syntax pitfalls, and how to reliably force updates from the command line.
1. Where does CloudLinux keep PHP directives?#
In standard shared hosting setups, PHP directives usually reside in predictable system-wide configuration files. Under the CloudLinux PHP Selector, however, every user account is assigned an isolated file system jail (CageFS) and the ability to choose an independent PHP version with custom runtime directives.
When you inspect a user's home directory (e.g., formula), you will notice a specific layout:
[root@server formula]# ls -la
total 92
drwx--x--- 12 formula access 4096 Sep 16 2025 .
drwx--x--x. 1433 root root 40960 May 8 16:55 ..
drwxr-xr-x 2 formula formula 59 May 11 10:42 .cl.selector
drwxrwx--- 2 formula apache 138 May 11 00:26 .php
lrwxrwxrwx 1 formula formula 48 May 29 2025 public_html -> ./domains/mysite.com/public_html
Breaking down those hidden directories:
.php/: Contains execution logs, such asphp-mail.log, and transient session storage. The PHP runtime does not read configuration directives from here..cl.selector/: This is the control directory. It stores account overrides generated whenever settings are saved in the web control panel.
Inside .cl.selector/, configuration files correspond to the active PHP version:
[root@server formula]# ls .cl.selector/
alt_php74.cfg defaults.cfg
The file alt_php74.cfg (where 74 denotes PHP 7.4) holds custom user overrides:
;>=== Start of PHP Selector Custom Options ===
upload_max_filesize=1G
;<=== End of PHP Selector Custom Options =====
2. The decimal syntax trap in PHP configuration#
Suppose your application requires accepting file uploads up to 1.6 GB. The intuitive reaction is to enter:
upload_max_filesize = 1.6G
While readable, PHP's configuration parser does not support floating-point numbers in shorthand byte values (K, M, G). When the parser hits the period (.) in 1.6G, it truncates the input unpredictably, frequently falling back to 1G or even single bytes on legacy releases.
Converting values to megabytes#
To configure exactly 1.6 GB cleanly, convert the target into whole Megabytes:
$$1.6 \times 1024 = 1638.4 \text{ MB} \approx 1638\text{M}$$
The memory directive hierarchy#
Increasing upload_max_filesize on its own will not work. File uploads travel via HTTP POST requests and consume script execution memory. If neighboring thresholds are lower, PHP aborts the request before file processing completes.
Always maintain this operational rule:
$$\text{memory\_limit} \ge \text{post\_max\_size} \ge \text{upload\_max\_filesize}$$
For a 1.6 GB target, the aligned configuration should look like:
upload_max_filesize = 1638M
post_max_size = 1640M
memory_limit = 1700M
3. Why manual edits to .cfg files fail to take effect#
If you edit /home/formula/.cl.selector/alt_php74.cfg directly with an editor, save the file, and refresh your browser, phpinfo() will likely continue reporting the old values.
This occurs because CloudLinux Selector treats the .cfg file as a persistent metadata manifest rather than an active runtime configuration file. The actual .ini files loaded by PHP-FPM and Apache are compiled inside the user's CageFS mount points.
Unless you notify the selector binary to rebuild this compiled structure, manual filesystem changes remain ignored.
Applying changes via CLI: selectorctl#
Attempting undocumented arguments like --replace-config-file triggers usage syntax errors:
[root@server .cl.selector]# selectorctl --user formula --replace-config-file --version=7.4
Usage: /usr/bin/selectorctl [OPTIONS]
The native argument supported by CloudLinux is --replace-options (or -m), which accepts a comma-separated list of key:value pairs:
selectorctl --user formula --version 7.4 --replace-options "upload_max_filesize:1638M,post_max_size:1640M,memory_limit:1700M"
Restarting user PHP-FPM workers#
Even after rebuilding configuration manifests, running PHP-FPM master pools may retain previous parameters in worker memory. Clear active processes for that specific user:
killall -u formula php-fpm
Synchronizing CageFS mount points#
Finally, ensure the user's isolated virtual filesystem maps the updated PHP symlinks correctly:
cagefsctl --update formula
4. Validating settings via CLI without browser caching#
Testing through a web browser can be misleading due to proxy caches, CDN buffering, or cached static headers. The most reliable way to verify active values is to query PHP directly under the user's security identity:
su - formula -s /bin/bash -c "php -i | grep upload_max_filesize"
The output should confirm the target value across both local and master scopes:
upload_max_filesize => 1638M => 1638M
5. The hidden proxy bottleneck (Nginx)#
If phpinfo() reports 1638M, but uploading your 1.6 GB file immediately produces an HTTP 413 Request Entity Too Large error, the file was blocked before reaching PHP.
When Nginx serves as a reverse proxy in front of Apache, Nginx intercepts incoming HTTP traffic first. By default, Nginx enforces a conservative client_max_body_size limit of 1MB or 10MB. Any payload exceeding that limit is dropped at the edge.
Adjusting Nginx body size in DirectAdmin#
- Log in to DirectAdmin with administrative privileges (Admin).
- Go to Custom HTTPD Configurations.
- Select the domain hosting the upload application.
- Locate the nginx.conf customization block and add the following directive:
client_max_body_size 1700M;
- Save the configuration and restart Nginx via terminal to apply the updated buffer rules:
systemctl restart nginx
Operational checklist for frictionless large file uploads#
When tuning upload thresholds in CloudLinux and DirectAdmin environments, follow this concise troubleshooting sequence:
- Avoid decimals: Convert your intended target to whole Megabytes ($1.6\text{ GB} = 1638\text{M}$).
- Align memory ceilings: Ensure that
memory_limit(e.g., 1700M) $\ge$post_max_size(e.g., 1640M) $\ge$upload_max_filesize(e.g., 1638M). - Use
selectorctlinstead of manual edits: Apply parameters cleanly withselectorctl --user USER --version X.Y --replace-options "...". - Kill stale worker processes and sync CageFS: Run
killall -u USER php-fpmfollowed bycagefsctl --update USER. - Inspect the edge proxy: If an HTTP 413 error appears, update
client_max_body_sizeinside Nginx to match your payload expectations.
Following these steps ensures consistent, reliable file transfers without unexpected timeouts or silent configuration drops.
Was this article helpful?
Leave a quick reaction to help prioritize future technical guides:
This post is licensed under CC BY-NC.



Comments
Join the discussion below.
0 comments