OPcache
OPcache improves PHP performance by storing pre-compiled code in shared memory, avoiding reading and recompiling for each request. This saves CPU usage and allows the server to handle significantly more simultaneous accesses.
This tutorial shows how to check, enable, configure, and validate OPcache on a production server.
Prerequisites
- Access
rootto orsudofrom the server - PHP 7.0 or higher (from PHP 5.5 onwards the extension comes with PHP; in PHP 8.x it is part of the core)
- Find out which SAPI you are using: PHP-FPM (Nginx/Apache) or mod_php (Apache)
Step 1: Check if OPcache is already active.
php -v
If the output mentions with Zend OPcache, the extension is installed. To confirm if it is enabled:
php -i | grep -i "opcache.enable"
Step 2: Install the extension (if necessary)
Debian/Ubuntu
sudo apt update
sudo apt install php8.5-opcache
RHEL/Rocky/AlmaLinux (Remi repository)
sudo dnf install php-opcache
Replace 8.5with the PHP version you are using.
Step 3: Locate the configuration file.
php --ini
Common places:
| Distribution | Path (FPM) |
|---|---|
| Debian/Ubuntu | /etc/php/8.5/fpm/conf.d/10-opcache.ini |
| RHEL/Rocky | /etc/php.d/10-opcache.ini |
Tip: Instead of editing the default file (which can be overwritten in updates), create your own file with higher priority, for example 99-opcache-custom.iniin the same folder conf.d.
Step 4: Configure OPcache for production.
Create the file:
sudo nano /etc/php/8.5/fpm/conf.d/99-opcache-custom.ini
Recommended content:
[opcache]
; Enables OPcache
opcache.enable=1
opcache.enable_cli=0
; Memory reserved for bytecode (in MB)
opcache.memory_consumption=256
; Memory for interned strings (in MB)
opcache.interned_strings_buffer=16
; Maximum number of cached files.
; Must be greater than the number of .php files in the project.
opcache.max_accelerated_files=20000
; PRODUCTION: do not check if files have changed
; (higher performance; requires clearing the cache on every deployment)
opcache.validate_timestamps=0
; Only relevant if validate_timestamps=1 (interval in seconds)
opcache.revalidate_freq=0
; Prevents memory waste
opcache.max_wasted_percentage=10
; Stores the full file path in the cache
opcache.use_cwd=1
Explanation of the main parameters
| Directive | Value | Reason |
|---|---|---|
opcache.enable |
1 |
Enable cache |
opcache.enable_cli |
0 |
In the CLI, the cache does not persist between executions, so it's not helpful (except in long-running workers). |
opcache.memory_consumption |
256 |
The standard size (128 MB) is often insufficient for large projects. |
opcache.max_accelerated_files |
20000 |
Use a value greater than the total number of PHP files (include the comma vendor/) . |
opcache.validate_timestamps |
0 |
Eliminates calls stat()on each request, but requires a cache reset on deployment. |
To count how many PHP files your project has:
find /var/www/meuapp -type f -name "*.php" | wc -l
Step 5 (optional): Preload (PHP 7.4+)
This opcache.preload=executes an arbitrary file that is run only once during server startup (PHP-FPM, mod_php, etc.) in persistent memory, which can be very useful in the framework.
Inphinit already provides a script for this use, located in system/boot/preload.php which can be edited manually to configure the most used classes in your application, and to use it, simply point to its location as in the example:
opcache.preload=/path/to/my-app/system/boot/preload.php
opcache.preload_user=www-data
If you have a frequently used class, such as a class installed via composer, you can edit it by adding it to system/boot/preload.php, as in the example:
OPcache::preload(array(
...,
Foo\Bar\Baz::class,
));
After modifying the file, it is necessary to restart PHP-FPM.
Step 6: Restart the service and validate.
Test the configuration before restarting:
sudo php-fpm8.5 -t
Restart:
sudo systemctl restart php8.5-fpm
If you are using Apache with mod_php, the command to restart is:
sudo systemctl restart apache2
Step 7: Clear the cache after each deployment.
With this validate_timestamps=0, the cache needs to be invalidated after each deployment. Options:
Option A: Reload PHP-FPM (the simplest and most reliable)
sudo systemctl reload php8.5-fpm
It reload's a nice feature: workers finish ongoing requests before being replaced, without taking down the service.
Option B: Call opcache_reset()via web request
Create a protected route (for example, accessible only via localhost ) and call it at the end of the deployment:
$app->action('GET', '/opcache/reset', function () {
if (!in_array($_SERVER['REMOTE_ADDR'], ['127.0.0.1', '::1'], true)) {
http_response_code(403);
} elseif (opcache_reset()) {
return 'OPcache limpo.';
}
return 'Falha ao limpar cache.';
});
curl -s http://127.0.0.1/opcache/reset
Problem solving
| Symptom | Probable cause | Solution |
|---|---|---|
| Changes to the code are not showing up. | validate_timestamps=0no reset |
Rode systemctl reload php8.5-fpm |
opcache_get_status()returns false |
OPcache disabled in FPM | Check out opcache.enable=1the FPM ini file. |
| Low success rate | Cache full | Increase memory_consumptionand max_accelerated_files |
| FPM does not increase after activating preload. | Error in preload script | Look journalctl -u php8.5-fpm |