--- title: "How to Configure PHP OPcache for PHP-FPM on Ubuntu 24.04" description: "Tune PHP OPcache for PHP-FPM on Ubuntu 24.04: size its memory and file limits, choose a revalidation strategy, clear it on deploys and check the hit rate." category: "Performance Optimization" language: en source: https://cubepath.com/docs/performance-optimization/opcache-configuration-for-php updated: 2026-09-25 --- # How to Configure PHP OPcache for PHP-FPM on Ubuntu 24.04 Every time PHP runs a script, it has to read the file, parse it and compile it to opcodes before it can execute anything. OPcache stores those compiled opcodes in shared memory, so PHP-FPM workers skip that work on every following request. It is enabled by default on Ubuntu 24.04, but its default limits are too small for large applications such as WordPress with many plugins, Laravel, Symfony or Magento. In this tutorial you will check OPcache, size it for your code base, choose how it detects code changes, clear it safely during deployments and monitor its hit rate. ## Prerequisites - A server running Ubuntu 24.04 LTS, for example a CubePath VPS. - A non-root user with `sudo` privileges. - PHP 8.3 with PHP-FPM serving a PHP application (for example behind Nginx). Install it with `sudo apt install php8.3-fpm` if needed. This guide uses the PHP 8.3 paths from Ubuntu 24.04. If you run another PHP version, replace `8.3` in paths and service names. ## Step 1 - Checking that OPcache is enabled OPcache is packaged as `php8.3-opcache` and installed together with PHP-FPM. Make sure it is present: ```bash sudo apt install php8.3-opcache ``` Check the version banner of PHP. The last line confirms that the extension is loaded: ```bash php -v ``` ```output PHP 8.3.6 (cli) (built: Jul 14 2026 18:30:55) (NTS) Copyright (c) The PHP Group Zend Engine v4.3.6, Copyright (c) Zend Technologies with Zend OPcache v8.3.6, Copyright (c), by Zend Technologies ``` The command-line PHP and PHP-FPM read different configuration directories (`/etc/php/8.3/cli/` and `/etc/php/8.3/fpm/`), and OPcache is disabled for the CLI by default. What matters for your website is the FPM configuration. Show its current OPcache settings: ```bash php-fpm8.3 -i | grep -E "^opcache\.(enable|memory_consumption|interned_strings_buffer|max_accelerated_files|validate_timestamps|revalidate_freq|jit_buffer_size) " ``` ```output opcache.enable => On => On opcache.interned_strings_buffer => 8 => 8 opcache.jit_buffer_size => 0 => 0 opcache.max_accelerated_files => 10000 => 10000 opcache.memory_consumption => 128 => 128 opcache.revalidate_freq => 2 => 2 opcache.validate_timestamps => On => On ``` These are the built-in defaults: 128 MB of shared memory, 8 MB for interned strings, room for 10,000 files, and a check for changed files at most every 2 seconds. ## Step 2 - Adding a status script to measure OPcache Before changing anything, set up a way to see how full OPcache is. OPcache lives in the memory of the PHP-FPM master process, so the status must be read through PHP-FPM, not with the `php` command line. Create a small status script outside the web root so it is never reachable from the internet: ```bash sudo nano /var/www/opcache-status.php ``` ```php 32 => 32 opcache.max_accelerated_files => 20000 => 20000 opcache.memory_consumption => 256 => 256 opcache.revalidate_freq => 60 => 60 ``` After the site has warmed up again, run the status script from Step 2. You want free memory left over, `oom` at 0 and a hit rate above 99 percent once the cache is warm. ## Step 4 - Choosing how OPcache detects code changes By default OPcache checks the timestamp of each file every `opcache.revalidate_freq` seconds and recompiles it when it changed. That costs a `stat()` call per file per interval, which is small but not free. You have two sensible strategies: | Setting | Behaviour | Use it when | |---|---|---| | `validate_timestamps=1`, `revalidate_freq=60` | Changes appear within a minute without any action | Files are edited in place, for example WordPress updating plugins itself | | `validate_timestamps=0` | Files are never rechecked; code only changes after a reload or reset | Code is only changed by a deployment process you control | For development, set `opcache.revalidate_freq=0` so every change is visible immediately. With `validate_timestamps=0`, PHP never notices edited files on its own. Only use it if every deployment clears the cache as shown in the next step, and never on sites where the application updates its own code (WordPress, Drupal or Joomla installing updates from the admin panel). To use it, change the two lines in your tuning file: ```bash sudo nano /etc/php/8.3/fpm/conf.d/99-opcache-tuning.ini ``` ```ini opcache.validate_timestamps=0 opcache.revalidate_freq=0 ``` Then apply the change: ```bash sudo systemctl reload php8.3-fpm ``` ## Step 5 - Clearing OPcache during deployments When you deploy new code, OPcache may still hold the old version of the files. The simplest and most reliable way to clear it is a graceful reload of PHP-FPM, which lets requests in progress finish, starts new workers and empties the cache: ```bash sudo systemctl reload php8.3-fpm ``` Add this command as the last step of your deployment, after the new code is in place. If your deployment switches a `current` symlink to a new release directory, the reload is also what makes PHP resolve the symlink to the new path. Resetting from the command line with `php -r 'opcache_reset();'` does **not** work: it resets the separate, empty cache of the CLI process, not the cache of PHP-FPM. If you cannot reload the service, run `opcache_reset()` through the PHP-FPM socket with the same `cgi-fcgi` technique as in Step 2, using a script outside the web root. Verify the reset worked by running the status script right after the reload. The number of cached scripts starts low again and grows as requests arrive: ```bash sudo env SCRIPT_FILENAME=/var/www/opcache-status.php REQUEST_METHOD=GET cgi-fcgi -bind -connect /run/php/php8.3-fpm.sock | grep "Cached scripts" ``` ```output Cached scripts: 1 (keys 1 of 32531) ``` The single cached script is the status script itself. ## Step 6 - Enabling the JIT compiler (optional) PHP 8 includes a JIT compiler that turns hot code paths into machine code. It gives large gains for CPU-heavy work (image processing, math, parsers) but little for typical web applications, which spend most of their time waiting for the database. In PHP 8.3 the JIT is off because `opcache.jit_buffer_size` defaults to `0`. To try it, add these lines to your tuning file: ```bash sudo nano /etc/php/8.3/fpm/conf.d/99-opcache-tuning.ini ``` ```ini opcache.jit=tracing opcache.jit_buffer_size=64M ``` Restart PHP-FPM, because the JIT buffer is allocated at startup: ```bash sudo systemctl restart php8.3-fpm ``` Run the status script and confirm that the last line shows `JIT: on`. Then compare response times and CPU usage of your real application before and after. If you do not see a clear improvement, remove the two lines again: the JIT uses extra memory and is one more component that can misbehave with some extensions. ## Step 7 - Cleaning up and monitoring The status script lives outside the web root, so it is not exposed, but you can remove it once you no longer need it: ```bash sudo rm /var/www/opcache-status.php ``` If you keep it for monitoring, check these values after deployments and whenever performance changes: - **Free memory and `oom` restarts**: if memory is full or `oom_restarts` grows, increase `opcache.memory_consumption`. - **Keys used versus maximum**: if `num_cached_keys` approaches `max_cached_keys`, increase `opcache.max_accelerated_files`. - **Interned strings**: if the buffer is full, increase `opcache.interned_strings_buffer`. - **Wasted memory**: memory left behind by outdated scripts. OPcache restarts itself when it exceeds `opcache.max_wasted_percentage` (5 percent by default) and memory is full. A reload after each deployment keeps it low. - **Hit rate**: should be above 99 percent on a warm cache. A lower rate on a site that is not being deployed usually means the cache is too small. ## Troubleshooting **Changes to PHP files do not appear on the site.** With `validate_timestamps=0` this is expected; reload PHP-FPM. With the default settings, wait for `revalidate_freq` seconds or reload. **Settings changed in `/etc/php/8.3/cli/php.ini` have no effect on the website.** The CLI and PHP-FPM use separate configuration files. Put OPcache settings in `/etc/php/8.3/fpm/conf.d/` and check them with `php-fpm8.3 -i`, not `php -i`. **`opcache_get_status()` returns `false` in the command line.** OPcache is disabled for the CLI (`opcache.enable_cli=0`). Read the status through PHP-FPM as shown in Step 2. **PHP-FPM fails to start after editing the tuning file.** Run `sudo php-fpm8.3 -t` and `sudo journalctl -u php8.3-fpm -n 30` to see which line is invalid. ## Conclusion You checked OPcache on Ubuntu 24.04, sized its memory, interned strings and file limit from your own code base, chose between timestamp validation and explicit resets, integrated a reload into your deployments and learned which status values to watch. OPcache is one of the cheapest performance improvements for any PHP site, as long as it is large enough for the code it has to hold. As next steps, tune the PHP-FPM pool so the number of workers matches your server's memory, add an object cache such as Redis for database-heavy applications, and consider OPcache preloading (`opcache.preload`) for frameworks that support it.