yumupgrades for production use, this is the repository for you.
Active subscription is required.
Ingredients of a sane and fast PHP setup
1. A website has a website user
You surely created a separate PHP-FPM pool user for your website.
You use that same user to set up your cron job with.
2. File-based PHP OPcache
Thanks to the file-based OPcache, we can run faster PHP cron jobs and significantly reduce the CPU usage.
A website typically needs many cron jobs.
Example of an ugly cron job table for a website
@daily /path/to/php -d memory_limit=-1 -d opcache.file_cache_only=1 -d opcache.enable_cli=1 -d opcache.file_cache=/home/username/.cache/opcache /path/to/cron.php @daily /path/to/php -d memory_limit=-1 -d opcache.file_cache_only=1 -d opcache.enable_cli=1 -d opcache.file_cache=/home/username/.cache/opcache /path/to/cron-other.php
Hardcoding file-based OPcache directory
We hardcoded OPcache directory, e.g.
/home/username/.cache/opcache in every cron job…
And while running PHP in CLI, we also have to specify it in order to benefit from faster PHP.
You absolutely want a sane
memory_limit applied to all your PHP-FPM pools. This allows you to find faulty scripts easily which unnecessarily eat up your RAM.
But you typically want unlimited or much larger memory allocation towards your PHP runs on the CLI. That means having to provide
-d memory_limit=-1 flag, for unlimited case, every time. Not good also.
Hardcoding PHP version
Furthermore, different sites may run different PHP versions via different PHP-FPM pools.
One site may be using PHP 8.0 binary under
The other, system’s default PHP 7.2 binary at
Running things in CLI means having to remember which site uses which PHP version… And having to hardcode PHP binary paths in cron jobs or while running PHP in CLI… Bad.
So overall, you can see from there, there’s a lot of repetitive hardcoding. Moreover, when you want to invoke something interactively, it is quite common to simply type
php which is prone to invoking the wrong version of PHP interpreter and not making benefit from file-based OPcache.
But there’s an easy fix.
Setting up great PHP CLI and cron jobs
Now it’s time for some elegant and consistent setup where we reduce hardcoding to the minimum and make everything clean and nice.
For each PHP version, we can create a launcher with the necessary settings. A launcher is actually a bash wrapper around actual
php. It will invoke the correct actual
php binary with the correct/necessary arguments.
php file inside it with contents:
#!/bin/bash /usr/bin/php -d memory_limit=-1 -d opcache.enable_cli=1 -d opcache.file_cache=$HOME/.cache/opcache "$@"
Noticed anything special? We hardcoded all our paths in this binary. And this is the only time we ever hardcode anything, per PHP version.
"$@" ensures that we pass whichever arguments our wrapper accepts, into an actual
Make it executable. Now symlink
~/.local/bin/php of every user that will run the PHP version that is default for the system.
Log in with a website user, and run:
ln -s /opt/php-cli/system/bin/php ~/.local/bin/php
For every non-default version, e.g. if you have a 7.4 software collection from Remi, create another launcher, e.g.
/opt/php-cli/7.4/bin/php would have these contents:
#!/bin/bash /opt/remi/php74/root/usr/bin/php -d memory_limit=-1 -d opcache.enable_cli=1 -d opcache.file_cache=$HOME/.cache/opcache "$@"
And similarly symlink
~/.local/bin/php of the users who run PHP using this version of interpreter.
Now our cron jobs have to ensure that
~/.local/bin is in cron’s
PATH by adding
This allows us to simply put
php in every cron entry for the site:
PATH=/home/foo/.local/bin:/usr/bin:/bin @daily php /path/to/cron.php @daily php /path/to/cron-other.php
Note that we must use a literal
PATH value for user
foo, because the environment variables specification in crontab does not allow using variables in the assigned value.
While we reached our goal of reducing duplication, we have a hardcoded username in a crontab. Not a problem if you use Ansible for setting up servers.
Otherwise, see the next section.
If you want to avoid hardcoding the username in crontab and reduce hardcoding of PHP version …
Simply set the path to a launcher’s
bin directory instead of
Now, as for the CLI, ensure that
~/.local/bin is in your website user’s
PATH and has priority over other paths.
Simply ensure that there’s no
PATH setting in your
~/.bash_profile and the following is in your
# User specific environment if ! [[ "$PATH" =~ "$HOME/.local/bin:$HOME/bin:" ]]; then PATH="$HOME/.local/bin:$HOME/bin:$PATH" fi export PATH
For a detailed explanation about it, see CentOS/RHEL: where is my PATH?.
This way of setting ensures that
~/.local/bin is on the right-side from
$PATH, and thus,
/usr/bin/php would be looked up first.
After changes to your
~/.bashrc, you may wish to log out and back into the server in order to update your
PATH now. This is preferred over running
source ~/.bashrc because that might create duplicates in the
Now typing just
php magically becomes that faster and less error-prone.