diff --git a/docs/content/docs/1.getting-started/4.these-images-vs-others.md b/docs/content/docs/1.getting-started/4.these-images-vs-others.md
index f0c70f0ce..c309271b4 100644
--- a/docs/content/docs/1.getting-started/4.these-images-vs-others.md
+++ b/docs/content/docs/1.getting-started/4.these-images-vs-others.md
@@ -77,11 +77,11 @@ We also include additional security hardening:
### Performance Optimized
-Every image includes production-tuned defaults based on real-world PHP applications:
+Every image ships tuned defaults for PHP, OPcache, and PHP-FPM:
**OPcache Configuration**
- Pre-configured for optimal memory usage and caching strategy
-- Easily toggle between development and production modes
+- One variable, `PHP_OPCACHE_ENABLE`, turns OPcache on with tuned defaults
- Smart defaults that work for most applications
**Process Management**
diff --git a/docs/content/docs/1.getting-started/6.default-configurations.md b/docs/content/docs/1.getting-started/6.default-configurations.md
index 609ee6696..5541c2aee 100644
--- a/docs/content/docs/1.getting-started/6.default-configurations.md
+++ b/docs/content/docs/1.getting-started/6.default-configurations.md
@@ -84,7 +84,7 @@ The following extensions are installed by default:
| **Extension** | **Description** | **Why we included it** |
|---------------|-----------------|------------------------|
-| [opcache](https://www.php.net/manual/en/book.opcache.php) | The Zend OPcache provides faster PHP execution through opcode caching and optimization. | This is a must-have for PHP performance.
⚠️ OPcache is disabled by default but can easily be enabled with [`PHP_OPCACHE_ENABLE=1`](/docs/reference/environment-variable-specification).|
+| [opcache](https://www.php.net/manual/en/book.opcache.php) | The Zend OPcache provides faster PHP execution through opcode caching and optimization. | This is a must-have for PHP performance.
⚠️ OPcache is disabled by default so code edits show up right away. Set [`PHP_OPCACHE_ENABLE=1`](/docs/reference/environment-variable-specification) to turn it on with tuned defaults. See the [production performance tuning guide](/docs/guide/production-performance-tuning#php-opcache).|
| [mysqli](https://www.php.net/manual/en/book.mysqli.php) | The "MySQL Improved" extension is an older extension for connecting to MySQL 4.1 and above. | **Enabled for fpm-apache only**. This is a legacy MySQL connector required for WordPress.|
| [pcntl](https://www.php.net/manual/en/intro.pcntl.php) | Process Control support in PHP implements the Unix style of process creation, program execution, signal handling and process termination. | This is required for [Laravel queues and Laravel Horizon](https://laravel.com/docs/10.x/queues#timeout)|
| [pdo_mysql](https://www.php.net/manual/en/ref.pdo-mysql.php) | The MySQL PDO extension allows you to connect to MySQL databases. | MySQL and MariaDB databases are very popular. |
diff --git a/docs/content/docs/2.image-variations/frankenphp.md b/docs/content/docs/2.image-variations/frankenphp.md
index f432b9277..936bd7762 100644
--- a/docs/content/docs/2.image-variations/frankenphp.md
+++ b/docs/content/docs/2.image-variations/frankenphp.md
@@ -370,8 +370,8 @@ For a complete list of available environment variables, see the [Environment Var
| `PHP_MAX_FILE_UPLOADS` | `20` | Maximum number of files per request |
| `PHP_POST_MAX_SIZE` | `100M` | Maximum POST request size |
| `PHP_OPCACHE_ENABLE` | `0` | Enable OPcache (`0`/`1`) |
-| `PHP_OPCACHE_REVALIDATE_FREQ` | `2` | How often to check for file changes (seconds) |
-| `PHP_OPCACHE_VALIDATE_TIMESTAMPS` | `1` | Whether to validate timestamps (`0`/`1`) |
+| `PHP_OPCACHE_REVALIDATE_FREQ` | `2` | How often to check for file changes (seconds), only when timestamps are validated |
+| `PHP_OPCACHE_VALIDATE_TIMESTAMPS` | `0` | Whether to check files for changes (`0`/`1`). Set to `1` when mounting code as a volume with OPcache enabled |
## Caddy Configuration
FrankenPHP uses Caddy's configuration format (Caddyfile) instead of NGINX configuration.
diff --git a/docs/content/docs/3.framework-guides/2.wordpress/4.using-wordpress-with-docker.md b/docs/content/docs/3.framework-guides/2.wordpress/4.using-wordpress-with-docker.md
index 790ee30c5..3995e405b 100644
--- a/docs/content/docs/3.framework-guides/2.wordpress/4.using-wordpress-with-docker.md
+++ b/docs/content/docs/3.framework-guides/2.wordpress/4.using-wordpress-with-docker.md
@@ -156,6 +156,10 @@ git pull origin main
This approach prioritizes plugin compatibility over modern deployment practices. It works reliably with the widest range of WordPress plugins while still benefiting from containerized infrastructure.
::
+::warning
+With `PHP_OPCACHE_ENABLE=1`, PHP files are cached until the container restarts because [`PHP_OPCACHE_VALIDATE_TIMESTAMPS`](/docs/reference/environment-variable-specification) defaults to `0`. Updates made through the WordPress admin still work because WordPress clears the cache for the files it writes with [`wp_opcache_invalidate()`](https://developer.wordpress.org/reference/functions/wp_opcache_invalidate/){target="_blank"}. Changes made with `git pull`, WP-CLI, SFTP, or plugins that write PHP files directly are not picked up until you restart the container. If you deploy this way, either restart the container after each update or set `PHP_OPCACHE_VALIDATE_TIMESTAMPS=1`. [Learn more in the production performance tuning guide →](/docs/guide/production-performance-tuning#php-opcache)
+::
+
### Which approach should you choose?
- **Volume-based**: Best for sites heavily dependent on third-party plugins or when you need maximum WordPress ecosystem compatibility
diff --git a/docs/content/docs/5.guide/5.major-version-migrations.md b/docs/content/docs/5.guide/5.major-version-migrations.md
index ebc18aab8..3c60b6fb5 100644
--- a/docs/content/docs/5.guide/5.major-version-migrations.md
+++ b/docs/content/docs/5.guide/5.major-version-migrations.md
@@ -23,6 +23,69 @@ Debian Bullseye and Alpine 3.16 were dropped at the same time. Debian 11 reached
If you are on one of these, move to PHP 8.2 or newer on `bookworm`, `trixie`, `alpine3.23`, or `alpine3.24`. See [EOL versions and the legacy-modernization path](https://github.com/serversideup/docker-php/blob/main/SECURITY.md#eol-versions-and-the-legacy-modernization-path).
+## Version 4 → Version 5 Migration
+Version 5 is about OPcache. Setting `PHP_OPCACHE_ENABLE=1` now gives you tuned defaults instead of PHP's stock values. There is one breaking change, and it only affects you if you run with OPcache enabled while your code is mounted as a volume.
+
+If you want to stay on Version 4 while you review the changes, pin your image tag to the last v4 release. Version-pinned tags are never rebuilt, so you will not receive security updates until you move to v5. See [how our releases work](/docs/getting-started/upgrade-guide#how-our-releases-work).
+
+```yml [compose.yml] {3}
+services:
+ php:
+ image: serversideup/php:8.5-fpm-nginx-v4.5.1
+```
+
+### Why we changed OPcache
+Most people start with these images in development, so OPcache stays off by default to keep your edits showing up instantly. But when you flip it on for production, the settings behind it should be the ones you would have picked yourself after reading the docs. They were not. Version 4 checked every cached file for changes every two seconds, shipped PHP's stock memory sizes, and documented an environment variable that did nothing. Version 5 fixes all of that with the values from [Symfony's performance guide](https://symfony.com/doc/current/performance.html#configure-opcache-for-maximum-performance){target="_blank"}, which says "The default OPcache configuration is not suited for Symfony applications." [FrankenPHP's performance guide](https://frankenphp.dev/docs/performance/){target="_blank"} points to the same page "even if you don't use Symfony." [Read the production performance tuning guide →](/docs/guide/production-performance-tuning#php-opcache)
+
+### Breaking changes in Version 5
+::caution
+The following change alters behavior for existing configurations that set `PHP_OPCACHE_ENABLE=1`.
+::
+
+#### `PHP_OPCACHE_VALIDATE_TIMESTAMPS` now defaults to `0`
+With OPcache enabled, PHP files are now cached until the container restarts. PHP no longer checks the filesystem for changes on every request. This is the correct setting for code that is built into the image, which is how we recommend deploying.
+
+You are affected if you set `PHP_OPCACHE_ENABLE=1` **and** any of these apply:
+
+- Your code is mounted as a volume and you edit it in place
+- You follow the [volume-based WordPress approach](/docs/framework-guides/wordpress/using-wordpress-with-docker#volume-based-approach-traditional) and update with `git pull`, WP-CLI, or SFTP
+- You run commands like `docker exec php artisan optimize` against a live container and expect the web workers to pick up the new files
+
+The fix is one of two things: restart the container after code changes (recommended), or set `PHP_OPCACHE_VALIDATE_TIMESTAMPS=1` to restore the Version 4 behavior.
+
+### Fixes
+- `PHP_OPCACHE_FORCE_RESTART_TIMEOUT` existed in Version 4 but never reached `php.ini`. It now works. The default of `180` matches PHP's own default, so nothing changes unless you had set it to something else.
+
+### Changed defaults
+The OPcache values apply only when `PHP_OPCACHE_ENABLE=1`, and the memory is only used as files are cached. `PHP_REALPATH_CACHE_TTL` is not an OPcache setting and applies whether OPcache is on or off. It comes from the same [Symfony recommendation](https://symfony.com/doc/current/performance.html#configure-the-php-realpath-cache){target="_blank"}.
+
+| Variable | Version 4 | Version 5 |
+|----------|-----------|-----------|
+| `PHP_OPCACHE_VALIDATE_TIMESTAMPS` | `1` | `0` |
+| `PHP_OPCACHE_MEMORY_CONSUMPTION` | `128` | `256` |
+| `PHP_OPCACHE_INTERNED_STRINGS_BUFFER` | `8` | `32` |
+| `PHP_OPCACHE_MAX_ACCELERATED_FILES` | `10000` | `32531` |
+| `PHP_REALPATH_CACHE_TTL` | `120` | `600` |
+
+### New variables
+- `PHP_OPCACHE_ENABLE_CLI` - Whether CLI commands use OPcache when `PHP_OPCACHE_ENABLE=1`. Defaults to `1`, which is what Version 4 did. Set it to `0` to keep OPcache on for the web server only.
+- `PHP_OPCACHE_PRELOAD` - Path to a preload script. Symfony generates one for you and [recommends it](https://symfony.com/doc/current/performance.html#use-the-opcache-class-preloading){target="_blank"}.
+- `PHP_OPCACHE_PRELOAD_USER` - The user to preload as when the container runs as root.
+
+[See the full list of environment variables →](/docs/reference/environment-variable-specification)
+
+### V5 Migration Checklist
+
+#### Docker Compose
+- Update the image tag
+- If your code is mounted as a volume with `PHP_OPCACHE_ENABLE=1`, either turn OPcache off for that environment or add `PHP_OPCACHE_VALIDATE_TIMESTAMPS=1`
+- If you deploy WordPress on a volume, add `PHP_OPCACHE_VALIDATE_TIMESTAMPS=1` or restart the container after updates made outside the WordPress admin
+- Replace any `docker exec ... artisan optimize` style deployment steps with a container restart
+
+#### Dockerfile
+- Nothing is required
+- If you add `PHP_OPCACHE_PRELOAD`, prefer setting it on the running service rather than as an `ENV` in the Dockerfile, so build steps like `RUN composer install` do not depend on the preload script
+
## Version 3 → Version 4 Migration
Version 3 to Version 4 is a much easier migration compared to previous versions. There are **no breaking changes**, so you can simply update your image tag to the latest version and take advantage of the new features.
diff --git a/docs/content/docs/5.guide/6.production-performance-tuning.md b/docs/content/docs/5.guide/6.production-performance-tuning.md
new file mode 100644
index 000000000..1aae13fea
--- /dev/null
+++ b/docs/content/docs/5.guide/6.production-performance-tuning.md
@@ -0,0 +1,189 @@
+---
+head.title: 'Production Performance Tuning - Docker PHP - Server Side Up'
+description: 'The settings that matter for PHP performance in production, where our defaults come from, and how to measure and tune them for your application.'
+layout: docs
+title: Production performance tuning
+---
+
+::lead-p
+This guide covers the settings that matter for performance once your application is in production, where our defaults come from, and how to tune them when your app needs more.
+::
+
+## PHP OPcache
+
+OPcache "improves PHP performance by storing precompiled script bytecode in shared memory, thereby removing the need for PHP to load and parse scripts on each request" ([PHP manual](https://www.php.net/manual/en/book.opcache.php){target="_blank"}). This means that every request skips the work of reading and parsing your PHP files, so it is faster. It also means that changes to your code are not seen until the cache is cleared, which is why we keep it off by default.
+
+### Turning it on
+
+OPcache is controlled by one switch, [`PHP_OPCACHE_ENABLE`](/docs/reference/environment-variable-specification).
+
+| Setting | What happens |
+|---------|--------------|
+| `PHP_OPCACHE_ENABLE=0` (default) | OPcache is off. Every request reads your files fresh, so edits show up right away when your code is mounted as a volume. |
+| `PHP_OPCACHE_ENABLE=1` | OPcache is on with the tuned defaults below. Files are compiled once and cached until the container restarts. |
+
+We keep OPcache off by default so nobody loses an afternoon wondering why a change is not showing up. Turn it on anywhere you are not editing code in place, such as production or staging:
+
+```yml [compose.yml] {5}
+services:
+ php:
+ image: serversideup/php:8.5-fpm-nginx
+ environment:
+ PHP_OPCACHE_ENABLE: "1"
+```
+
+::note
+CLI commands like `php artisan` also use OPcache when `PHP_OPCACHE_ENABLE_CLI=1`, which is the default. A CLI process gets its own cache that ends when the process exits, so the gain there is optimized code rather than caching. Set `PHP_OPCACHE_ENABLE_CLI=0` to keep OPcache on for the web server only.
+::
+
+### Defaults
+
+When `PHP_OPCACHE_ENABLE=1`, these are the defaults you get. Override any of them with the same variable:
+
+| Variable | Default | What it controls |
+|----------|---------|------------------|
+| `PHP_OPCACHE_VALIDATE_TIMESTAMPS` | `0` | Whether OPcache checks if a file changed. `0` caches files until the container restarts, so `PHP_OPCACHE_REVALIDATE_FREQ` is never used. |
+| `PHP_OPCACHE_MEMORY_CONSUMPTION` | `256` | Size of the shared memory segment in megabytes. |
+| `PHP_OPCACHE_INTERNED_STRINGS_BUFFER` | `32` | Megabytes inside that segment for interned strings. |
+| `PHP_OPCACHE_MAX_ACCELERATED_FILES` | `32531` | Maximum number of files in the cache. |
+| `PHP_OPCACHE_FORCE_RESTART_TIMEOUT` | `180` | Seconds to wait for a scheduled restart before OPcache forces it. |
+| `PHP_OPCACHE_SAVE_COMMENTS` | `1` | Keep doc comments in the cache. Disabling it "may break applications and frameworks that rely on comment parsing for annotations, including Doctrine, Zend Framework 2 and PHPUnit." |
+| `PHP_OPCACHE_ENABLE_FILE_OVERRIDE` | `0` | Let OPcache answer `file_exists()` from its cache. Left off because it "risks returning stale data if opcache.validate_timestamps is disabled." |
+| `PHP_OPCACHE_JIT` | `off` | The JIT compiler. See [JIT](#jit). |
+| `PHP_OPCACHE_JIT_BUFFER_SIZE` | `0` | Memory for JIT code. |
+| `PHP_OPCACHE_PRELOAD` | `""` | Path to a preload script. See [Preloading](#preloading). |
+| `PHP_OPCACHE_PRELOAD_USER` | `""` | User to run the preload script as. Only needed when running as root. |
+
+These are not our numbers. The memory size, file count, interned strings buffer, and `validate_timestamps=0` are the values in [Symfony's performance guide](https://symfony.com/doc/current/performance.html#configure-opcache-for-maximum-performance){target="_blank"}, which [FrankenPHP's performance guide](https://frankenphp.dev/docs/performance/){target="_blank"} recommends "even if you don't use Symfony." Laravel does not publish OPcache values, but [Laravel Forge's OPcache option](https://laravel.com/forge/docs/servers/php#opcache){target="_blank"} asks the same thing of you that this configuration does: reload PHP after every deployment. Every variable links to the PHP manual in the [environment variable specification](/docs/reference/environment-variable-specification).
+
+The most important one is `PHP_OPCACHE_VALIDATE_TIMESTAMPS=0`. Symfony's guide puts it plainly: "In production servers, PHP files should never change, unless a new application version is deployed." When your code is built into the image, checking for changes is wasted work.
+
+### Memory
+
+OPcache reserves one shared memory segment of `PHP_OPCACHE_MEMORY_CONSUMPTION` megabytes when PHP starts. The interned strings buffer lives inside that segment. With the defaults, 256 MB is reserved, 32 MB of it holds interned strings, and 224 MB holds compiled code. The JIT buffer is different: when the JIT is on, PHP adds `PHP_OPCACHE_JIT_BUFFER_SIZE` on top, so "its total size is this value plus opcache.jit_buffer_size" ([PHP manual](https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.memory-consumption){target="_blank"}).
+
+Reserving memory is not the same as using it. The container only pays for pages that are written, and every PHP-FPM worker shares the same segment.
+
+### Measuring
+
+PHP reports how full the cache is. Put this file in your public directory and open it in a browser or with `curl`. It has to go through the web server, since the CLI has its own cache:
+
+```php [public/opcache-status.php]
+ round($bytes / 1048576) . ' MB';
+$files = "{$stats['num_cached_keys']} of {$stats['max_cached_keys']}";
+
+$report = [
+ 'Cache full' => $status['cache_full'] ? 'yes' : 'no',
+ 'Cached files' => $files,
+ 'Memory used' => $toMegabytes($memory['used_memory']),
+ 'Memory free' => $toMegabytes($memory['free_memory']),
+ 'Interned strings free' => $toMegabytes($strings['free_memory']),
+ 'Out of memory restarts' => $stats['oom_restarts'],
+ 'Hash restarts' => $stats['hash_restarts'],
+];
+
+foreach ($report as $label => $value) {
+ echo "$label: $value
+";
+}
+```
+
+::caution
+This file exposes cache and memory statistics. Remove it before deploying, or protect it.
+::
+
+Two of these numbers are available before you serve real traffic. Count the PHP files in your image with `find /var/www/html -name '*.php' | wc -l` for an upper bound on the file limit, and run your smoke tests or a [preload script](#preloading) to fill the cache before you read the memory numbers. Then check:
+
+- **Cache full is `yes`** or **out of memory restarts** is climbing: raise `PHP_OPCACHE_MEMORY_CONSUMPTION`.
+- **Cached files** is close to the maximum or **hash restarts** is climbing: raise `PHP_OPCACHE_MAX_ACCELERATED_FILES`.
+- **Interned strings free** is near zero: raise `PHP_OPCACHE_INTERNED_STRINGS_BUFFER`.
+
+Restarts are what you want to avoid. When OPcache runs out of room it restarts and clears the whole cache, so requests are slower until it fills back up.
+
+### Deploying
+
+With OPcache enabled, files are cached until the container restarts, so every deployment should start a new container. The PHP manual is direct about this: with timestamps off, "you must reset OPcache manually via opcache_reset(), opcache_invalidate() or by restarting the Web server for changes to the filesystem to take effect" ([PHP manual](https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.validate-timestamps){target="_blank"}).
+
+A few things that catch people out:
+
+- **Running cache commands in a live container** like `docker exec php artisan optimize` writes new files, but the running web workers keep serving the old cached copies. Restart the container instead.
+- **`opcache_reset()` from the CLI does nothing for the web server.** The CLI has its own cache in its own process.
+- **Mounting code as a volume with OPcache enabled** means your edits will not show up. Leave OPcache off in development, or set `PHP_OPCACHE_VALIDATE_TIMESTAMPS=1`.
+
+::note
+If you need change detection with OPcache enabled, `PHP_OPCACHE_VALIDATE_TIMESTAMPS=1` restores the Version 4 behavior with a check every `PHP_OPCACHE_REVALIDATE_FREQ` seconds.
+::
+
+### Framework notes
+
+#### Laravel
+
+Our [Laravel automations](/docs/framework-guides/laravel/automations) run `php artisan optimize` in the entrypoint before the web server starts. That includes `view:cache`, which "precompiles all your Blade views so they are not compiled on demand" ([Laravel docs](https://laravel.com/docs/12.x/deployment#optimizing-view-loading){target="_blank"}), so the cached config, routes, events, and views are on disk before OPcache sees them.
+
+Queue workers, Horizon, the scheduler, Reverb, and Octane on Swoole or RoadRunner are CLI processes, so they follow `PHP_OPCACHE_ENABLE_CLI`. Laravel's own advice applies to all of them: after a deploy, "any long-running services such as queue workers, Laravel Reverb, or Laravel Octane should be reloaded / restarted to use the new code" ([Laravel docs](https://laravel.com/docs/12.x/deployment#reloading-services){target="_blank"}). A container restart does that.
+
+#### WordPress
+
+WordPress clears OPcache for the files it writes during core, plugin, and theme updates through the admin, using [`wp_opcache_invalidate()`](https://developer.wordpress.org/reference/functions/wp_opcache_invalidate/){target="_blank"}, so those updates keep working. Files changed outside of WordPress (`git pull`, WP-CLI, SFTP, or plugins that write PHP files directly) are not picked up until the container restarts. If you use the [volume-based approach](/docs/framework-guides/wordpress/using-wordpress-with-docker#volume-based-approach-traditional), restart after those changes or set `PHP_OPCACHE_VALIDATE_TIMESTAMPS=1`.
+
+### Preloading
+
+Preloading compiles a set of files into OPcache when PHP starts and keeps them there "until the server is shut down" ([PHP manual](https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.preload){target="_blank"}). Requests skip the autoloader for those classes. [Symfony generates a preload file for you](https://symfony.com/doc/current/performance.html#use-the-opcache-class-preloading){target="_blank"} at `config/preload.php`. Laravel does not ship one.
+
+Point `PHP_OPCACHE_PRELOAD` at your script:
+
+```yml [compose.yml] {6}
+services:
+ php:
+ image: my-app:latest
+ environment:
+ PHP_OPCACHE_ENABLE: "1"
+ PHP_OPCACHE_PRELOAD: "/var/www/html/config/preload.php"
+```
+
+Things to know before you turn it on:
+
+- **The file must exist.** PHP refuses to start if the preload script is missing or throws.
+- **Preloading as root needs `PHP_OPCACHE_PRELOAD_USER`.** Our images run as an unprivileged user, so this only matters if you run the container as root. The CLI is exempt on PHP 8.3 and newer ([PHP manual](https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.preload-user){target="_blank"}).
+- **The CLI runs it too.** With `PHP_OPCACHE_ENABLE_CLI=1`, every `php` command preloads before it runs, so the script must work outside of a web request. Set `PHP_OPCACHE_ENABLE_CLI=0` if you do not want that. Set `PHP_OPCACHE_PRELOAD` on your running service rather than as an `ENV` in your Dockerfile, so build steps like `RUN composer install` do not depend on it.
+- **Preloaded files never change.** Even with `PHP_OPCACHE_VALIDATE_TIMESTAMPS=1`, preloaded code stays until restart.
+
+### JIT
+
+The JIT compiler is off by default, as it is in PHP itself ([PHP manual](https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.jit){target="_blank"}). The [PHP JIT RFC](https://wiki.php.net/rfc/jit){target="_blank"} found it "doesn't seem to significantly improve real-life apps like WordPress" while the benefit in "non-Web, CPU-intensive scenarios" is "very substantial." Xdebug also turns it off: "When Xdebug is loaded with PHP's JIT on, you will get a warning, and JIT will be disabled" ([Xdebug docs](https://xdebug.org/docs/compat){target="_blank"}).
+
+To enable it, set both variables. The buffer is added on top of `PHP_OPCACHE_MEMORY_CONSUMPTION`, so `64M` with the default makes a 320 MB segment:
+
+```yml [compose.yml] {6-7}
+services:
+ php:
+ image: my-app:latest
+ environment:
+ PHP_OPCACHE_ENABLE: "1"
+ PHP_OPCACHE_JIT: "tracing"
+ PHP_OPCACHE_JIT_BUFFER_SIZE: "64M"
+```
+
+Measure before and after. If your response times do not move, leave it off.
+
+### Advanced settings
+
+If there are options that you don't see in the environment variables, you can set them through a [custom ini file](/docs/customizing-the-image/changing-common-php-settings). For example, in some ocasions you may want to set:
+
+- `opcache.huge_code_pages=1` copies compiled code into huge pages. It "requires appropriate OS configuration" ([PHP manual](https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.huge_code_pages){target="_blank"}).
+- `opcache.file_cache=/path` adds a second-level cache on disk that helps "at server restart or SHM reset" ([PHP manual](https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.file-cache){target="_blank"}).
+
+## PHP realpath cache
+
+PHP caches the resolved path of every file it opens so it does not repeat the lookup on each request. Symfony's guide pairs this cache with OPcache and says applications that open many PHP files "should use at least" `realpath_cache_size=4096K` and `realpath_cache_ttl=600` ([Symfony docs](https://symfony.com/doc/current/performance.html#configure-the-php-realpath-cache){target="_blank"}). Our images ship both as `PHP_REALPATH_CACHE_SIZE` and `PHP_REALPATH_CACHE_TTL`. PHP disables this cache when `open_basedir` is set, so leave `PHP_OPEN_BASEDIR` empty in production unless you need it.
+
+::tip{to="/docs/reference/environment-variable-specification"}
+The full list of variables and their defaults is in the environment variable specification.
+::
diff --git a/docs/content/docs/8.reference/1.environment-variable-specification.md b/docs/content/docs/8.reference/1.environment-variable-specification.md
index da54e6911..00abcfdf0 100644
--- a/docs/content/docs/8.reference/1.environment-variable-specification.md
+++ b/docs/content/docs/8.reference/1.environment-variable-specification.md
@@ -100,21 +100,24 @@ Setting environment variables all depends on what method you're using to run you
`PHP_MAX_INPUT_TIME`
*Default: "-1"*|This sets the maximum time in seconds a script is allowed to parse input data, like POST and GET. Timing begins at the moment PHP is invoked at the server and ends when execution begins. The default setting is -1, which means that max_execution_time is used instead. Set to 0 to allow unlimited time. This directive is hardcoded to -1 for the CLI SAPI by PHP. (Official docs)|all
`PHP_MAX_INPUT_VARS`
*Default: "1000"*|Set the limits for number of input variables (e.g., POST, GET, or COOKIE variables) that PHP will process in a single request. (Official docs)|all
`PHP_MEMORY_LIMIT`
*Default: "256M"*|Set the maximum amount of memory in bytes that a script is allowed to allocate. (Official docs)|all
-`PHP_OPCACHE_ENABLE`
*Default: "0" (to keep developers sane)*|Enable or disable OPcache. ⚠️ This will set **both values** for `opcache.enable` and `opcache.enable_cli`. (Official docs)|all
+`PHP_OPCACHE_ENABLE`
*Default: "0" (to keep developers sane)*|Enable or disable OPcache. `1` also applies the tuned `PHP_OPCACHE_*` defaults below. CLI commands like `php artisan` also use OPcache when `PHP_OPCACHE_ENABLE_CLI=1`. See the [production performance tuning guide](/docs/guide/production-performance-tuning#php-opcache). (Official docs)|all
+`PHP_OPCACHE_ENABLE_CLI`
*Default: "1"*|Enable or disable OPcache for CLI commands like `php artisan`. Only takes effect when `PHP_OPCACHE_ENABLE=1`. Set to `0` to keep OPcache on for the web server only, for example so `PHP_OPCACHE_PRELOAD` does not run on every CLI command. (Official docs)|all
`PHP_OPCACHE_ENABLE_FILE_OVERRIDE`
*Default: "0"*|Enable or disable file existence override (file_exists, etc.). (Official docs)|all
`PHP_OPCACHE_FORCE_RESTART_TIMEOUT`
*Default: "180"*|The number of seconds to wait for a scheduled restart to begin if the cache isn't active, in seconds. If the timeout is hit, then OPcache assumes that something is wrong and will kill the processes holding locks on the cache to permit a restart. (Official docs)|all
-`PHP_OPCACHE_INTERNED_STRINGS_BUFFER`
*Default: "8"*|The amount of memory used to store interned strings, in megabytes. (Official docs)|all
-`PHP_OPCACHE_JIT`
*Default: "off"*|Enable or disable the JIT compiler. (Official docs)|all
-`PHP_OPCACHE_JIT_BUFFER_SIZE`
*Default: "0"*|The amount of shared memory to reserve for compiled JIT code. A zero value disables the JIT. (Official docs)|all
-`PHP_OPCACHE_MAX_ACCELERATED_FILES`
*Default: "10000"*|The maximum number of keys (scripts) in the OPcache hash table. (Official docs)|all
-`PHP_OPCACHE_MEMORY_CONSUMPTION`
*Default: "128"*|The amount of memory used by the OPcache engine, in megabytes. (Official docs)|all
-`PHP_OPCACHE_REVALIDATE_FREQ`
*Default: "2"*|How often the OPcache checks for updates to cached files (in seconds). (Official docs)|all
-`PHP_OPCACHE_SAVE_COMMENTS`
*Default: "1"*|Remove comments from OPcache to minify a bit further. Note: any code that depends on PHPDoc annotations can break from this. (Official docs)|all
-`PHP_OPCACHE_VALIDATE_TIMESTAMPS`
*Default: "1"*|Whether OPcache checks for changes to files, or requires reload of PHP to revalidate OPcache. (Official docs)|all
+`PHP_OPCACHE_INTERNED_STRINGS_BUFFER`
*Default: "32"*|The amount of memory used to store interned strings, in megabytes. This is reserved inside `PHP_OPCACHE_MEMORY_CONSUMPTION`, not in addition to it. (Official docs)|all
+`PHP_OPCACHE_JIT`
*Default: "off"*|Enable or disable the JIT compiler. To turn it on, set this to `tracing` **and** set `PHP_OPCACHE_JIT_BUFFER_SIZE` to a non-zero value like `64M`. (Official docs)|all
+`PHP_OPCACHE_JIT_BUFFER_SIZE`
*Default: "0"*|The amount of shared memory to reserve for compiled JIT code. A zero value disables the JIT. This is added on top of `PHP_OPCACHE_MEMORY_CONSUMPTION`, so the shared memory segment becomes the sum of both. (Official docs)|all
+`PHP_OPCACHE_MAX_ACCELERATED_FILES`
*Default: "32531"*|The maximum number of keys (scripts) in the OPcache hash table. PHP rounds this up to the next value in its prime number table (16229, 32531, 65407, and so on), so `32531` is the exact value PHP uses and reports in `opcache_get_status()`. (Official docs)|all
+`PHP_OPCACHE_MEMORY_CONSUMPTION`
*Default: "256"*|The amount of shared memory reserved for OPcache, in megabytes. Memory is only used as files are cached, so a larger value costs nothing until it is needed. (Official docs)|all
+`PHP_OPCACHE_PRELOAD`
*Default: ""*|Path to a PHP script that OPcache compiles and runs at startup (preloading). Empty disables preloading. ⚠️ The script also runs on every `php` command unless `PHP_OPCACHE_ENABLE_CLI=0`. Preloading as root requires `PHP_OPCACHE_PRELOAD_USER`. See the [production performance tuning guide](/docs/guide/production-performance-tuning#php-opcache). (Official docs)|all
+`PHP_OPCACHE_PRELOAD_USER`
*Default: ""*|The system user to run the preload script as. Only needed when the web server runs as root, since PHP refuses to preload as root without it. (Official docs)|all
+`PHP_OPCACHE_REVALIDATE_FREQ`
*Default: "2"*|How often the OPcache checks for updates to cached files (in seconds). Only applies when `PHP_OPCACHE_VALIDATE_TIMESTAMPS=1`. (Official docs)|all
+`PHP_OPCACHE_SAVE_COMMENTS`
*Default: "1"*|Keep PHPDoc comments in the cached code. Setting this to `0` saves a little memory but breaks any code that reads PHPDoc annotations at runtime (Doctrine, Zend Framework 2, and PHPUnit). (Official docs)|all
+`PHP_OPCACHE_VALIDATE_TIMESTAMPS`
*Default: "0"*|Whether OPcache checks for changes to files. With `0`, PHP files are cached until the container restarts, which is ideal for immutable containers. Set to `1` if you mount your code as a volume and still want OPcache enabled. (Official docs)|all
`PHP_OPEN_BASEDIR`
*Default: "None"* |Limit the files that can be accessed by PHP to the specified directory-tree, including the file itself. `open_basedir` is just an extra safety net, that is in no way comprehensive, and can therefore not be relied upon when security is needed. (Official docs)| all
`PHP_POST_MAX_SIZE`
*Default: "100M"*|Sets max size of post data allowed. (Official docs)|all
`PHP_REALPATH_CACHE_SIZE`
*Default: "4096K"*|Size of the realpath cache. Applications with many files (large `vendor/` directories) may benefit from a larger cache. Note: the cache is disabled when `PHP_OPEN_BASEDIR` is set. (Official docs)|all
-`PHP_REALPATH_CACHE_TTL`
*Default: "120"*|The duration of time, in seconds for which to cache realpath information for a given file or directory. (Official docs)|all
+`PHP_REALPATH_CACHE_TTL`
*Default: "600"*|The duration of time, in seconds for which to cache realpath information for a given file or directory. `600` is the value Symfony's performance guide recommends for applications that open many PHP files. (Symfony docs) (Official docs)|all
`PHP_SESSION_COOKIE_HTTPONLY`
*Default: "On"*|Add the `HttpOnly` flag to the session cookie so browser scripts cannot read it. On by default as recommended by PHP. Only applies to native PHP sessions. Laravel manages its own session cookie flags. (Official docs)|all
`PHP_SESSION_COOKIE_SECURE`
*Default: "false"*|Specifies whether the session cookie should only be sent over HTTPS. Off by default so local development over HTTP works. Set to `true` in production when serving over HTTPS. Only applies to native PHP sessions. Laravel manages its own session cookie flags. (Official docs)|all
`PHP_UPLOAD_MAX_FILE_SIZE`
*Default: "100M"*|The maximum size of an uploaded file. (Official docs)|all
diff --git a/scripts/test-image.sh b/scripts/test-image.sh
index fe73ae9cd..0aab5bdf0 100755
--- a/scripts/test-image.sh
+++ b/scripts/test-image.sh
@@ -48,15 +48,24 @@ pass "Extensions loaded: $expected_extensions"
# PHP_* environment variables reach php.ini through ${VAR} substitution. Override a few
# of the different value types (size, boolean, list) and confirm PHP sees them.
+# OPcache is enabled so the CLI SAPI also allocates the shared cache with the tuned defaults.
ini_values=$(docker run --rm \
--env PHP_MEMORY_LIMIT=512M \
--env PHP_REALPATH_CACHE_SIZE=8M \
--env PHP_SESSION_COOKIE_HTTPONLY=0 \
--env PHP_DISABLE_FUNCTIONS=shell_exec \
- "$image" php -r 'echo ini_get("memory_limit"), " ", ini_get("realpath_cache_size"), " ", ini_get("session.cookie_httponly"), " ", ini_get("disable_functions");' | tail -n1)
-[ "$ini_values" = "512M 8M 0 shell_exec" ] || fail "PHP_* environment variables did not apply to php.ini. Got: $ini_values"
+ --env PHP_OPCACHE_ENABLE=1 \
+ --env PHP_OPCACHE_FORCE_RESTART_TIMEOUT=60 \
+ "$image" php -r 'echo ini_get("memory_limit"), " ", ini_get("realpath_cache_size"), " ", ini_get("session.cookie_httponly"), " ", ini_get("disable_functions"), " ", ini_get("opcache.force_restart_timeout");' | tail -n1)
+[ "$ini_values" = "512M 8M 0 shell_exec 60" ] || fail "PHP_* environment variables did not apply to php.ini. Got: $ini_values"
pass "Environment variables apply to php.ini"
+# PHP_OPCACHE_ENABLE_CLI turns OPcache off for the CLI SAPI while opcache.enable stays on for the web server.
+cli_opcache=$(docker run --rm --env PHP_OPCACHE_ENABLE=1 --env PHP_OPCACHE_ENABLE_CLI=0 \
+ "$image" php -r 'echo function_exists("opcache_get_status") && opcache_get_status(false) !== false ? "on" : "off";' | tail -n1)
+[ "$cli_opcache" = "off" ] || fail "PHP_OPCACHE_ENABLE_CLI=0 did not disable OPcache for the CLI. Got: $cli_opcache"
+pass "PHP_OPCACHE_ENABLE_CLI disables the CLI cache"
+
has_healthcheck=$(docker image inspect --format '{{if .Config.Healthcheck}}yes{{end}}' "$image")
if [ -z "$has_healthcheck" ]; then
pass "No HEALTHCHECK defined, skipping startup check"
@@ -76,7 +85,9 @@ for pair in NGINX_HTTP_PORT:NGINX_WEBROOT APACHE_HTTP_PORT:APACHE_DOCUMENT_ROOT
fi
done
-run_args=(--detach --rm)
+# Web images run with OPcache enabled so the health check and the served page
+# cover the FPM and FrankenPHP SAPIs starting with the tuned defaults.
+run_args=(--detach --rm --env PHP_OPCACHE_ENABLE=1)
if [ -n "$http_port" ]; then
# The container runs unprivileged, so the mounted document root must be world readable.
web_dir=$(mktemp -d)
diff --git a/src/common/etc/entrypoint.d/0-container-info.sh b/src/common/etc/entrypoint.d/0-container-info.sh
index 7ef26e334..bf8124eaa 100644
--- a/src/common/etc/entrypoint.d/0-container-info.sh
+++ b/src/common/etc/entrypoint.d/0-container-info.sh
@@ -9,6 +9,7 @@ fi
# Get OPcache status
PHP_OPCACHE_STATUS=$(php -r 'echo ini_get("opcache.enable");')
+PHP_OPCACHE_VALIDATE_TIMESTAMPS_STATUS=$(php -r 'echo ini_get("opcache.validate_timestamps");')
if [ "$PHP_OPCACHE_STATUS" = "1" ]; then
PHP_OPCACHE_MESSAGE="✅ Enabled"
@@ -61,4 +62,6 @@ Brought to you by serversideup.net
if [ "$PHP_OPCACHE_STATUS" = "0" ]; then
echo "👉 [NOTICE]: Improve PHP performance by setting PHP_OPCACHE_ENABLE=1 (recommended for production)."
+elif [ "$PHP_OPCACHE_VALIDATE_TIMESTAMPS_STATUS" = "0" ]; then
+ echo "👉 [NOTICE]: OPcache is enabled and PHP_OPCACHE_VALIDATE_TIMESTAMPS=0. Code changes require a container restart. Learn more: https://serversideup.net/docker-php/performance/"
fi
\ No newline at end of file
diff --git a/src/common/usr/local/etc/php/conf.d/serversideup-docker-php.ini b/src/common/usr/local/etc/php/conf.d/serversideup-docker-php.ini
index 93dffa04b..e8b443c36 100644
--- a/src/common/usr/local/etc/php/conf.d/serversideup-docker-php.ini
+++ b/src/common/usr/local/etc/php/conf.d/serversideup-docker-php.ini
@@ -1791,8 +1791,9 @@ ldap.max_links = -1
; Determines if Zend OPCache is enabled
opcache.enable=${PHP_OPCACHE_ENABLE}
-; Determines if Zend OPCache is enabled for the CLI version of PHP
-opcache.enable_cli=${PHP_OPCACHE_ENABLE}
+; Determines if Zend OPCache is enabled for the CLI version of PHP.
+; Only takes effect when opcache.enable is also on.
+opcache.enable_cli=${PHP_OPCACHE_ENABLE_CLI}
; The OPcache shared memory storage size.
opcache.memory_consumption=${PHP_OPCACHE_MEMORY_CONSUMPTION}
@@ -1867,7 +1868,7 @@ opcache.enable_file_override=${PHP_OPCACHE_ENABLE_FILE_OVERRIDE}
; How long to wait (in seconds) for a scheduled restart to begin if the cache
; is not being accessed.
-;opcache.force_restart_timeout=180
+opcache.force_restart_timeout=${PHP_OPCACHE_FORCE_RESTART_TIMEOUT}
; OPcache error_log file name. Empty string assumes "stderr".
;opcache.error_log=
@@ -1937,12 +1938,12 @@ opcache.enable_file_override=${PHP_OPCACHE_ENABLE_FILE_OVERRIDE}
; Specifies a PHP script that is going to be compiled and executed at server
; start-up.
; https://php.net/opcache.preload
-;opcache.preload=
+opcache.preload=${PHP_OPCACHE_PRELOAD}
; Preloading code as root is not allowed for security reasons. This directive
; facilitates to let the preloading to be run as another user.
; https://php.net/opcache.preload_user
-;opcache.preload_user=
+opcache.preload_user=${PHP_OPCACHE_PRELOAD_USER}
; Prevents caching files that are less than this number of seconds old. It
; protects from caching of incompletely updated files. In case all file updates
diff --git a/src/variations/cli/Dockerfile b/src/variations/cli/Dockerfile
index 97358cf5e..f29b7ab1d 100644
--- a/src/variations/cli/Dockerfile
+++ b/src/variations/cli/Dockerfile
@@ -43,20 +43,23 @@ ENV APP_BASE_DIR=/var/www/html \
PHP_MAX_INPUT_VARS="1000" \
PHP_MEMORY_LIMIT="256M" \
PHP_OPCACHE_ENABLE="0" \
+ PHP_OPCACHE_ENABLE_CLI="1" \
PHP_OPCACHE_ENABLE_FILE_OVERRIDE="0" \
PHP_OPCACHE_FORCE_RESTART_TIMEOUT="180" \
- PHP_OPCACHE_INTERNED_STRINGS_BUFFER="8" \
+ PHP_OPCACHE_INTERNED_STRINGS_BUFFER="32" \
PHP_OPCACHE_JIT="off" \
PHP_OPCACHE_JIT_BUFFER_SIZE="0" \
- PHP_OPCACHE_MAX_ACCELERATED_FILES="10000" \
- PHP_OPCACHE_MEMORY_CONSUMPTION="128" \
+ PHP_OPCACHE_MAX_ACCELERATED_FILES="32531" \
+ PHP_OPCACHE_MEMORY_CONSUMPTION="256" \
+ PHP_OPCACHE_PRELOAD="" \
+ PHP_OPCACHE_PRELOAD_USER="" \
PHP_OPCACHE_REVALIDATE_FREQ="2" \
PHP_OPCACHE_SAVE_COMMENTS="1" \
- PHP_OPCACHE_VALIDATE_TIMESTAMPS="1" \
+ PHP_OPCACHE_VALIDATE_TIMESTAMPS="0" \
PHP_OPEN_BASEDIR="" \
PHP_POST_MAX_SIZE="100M" \
PHP_REALPATH_CACHE_SIZE="4096K" \
- PHP_REALPATH_CACHE_TTL="120" \
+ PHP_REALPATH_CACHE_TTL="600" \
PHP_SESSION_COOKIE_HTTPONLY="On" \
PHP_SESSION_COOKIE_SECURE=false \
PHP_UPLOAD_MAX_FILE_SIZE="100M" \
diff --git a/src/variations/fpm-apache/Dockerfile b/src/variations/fpm-apache/Dockerfile
index 240c23f73..04e10ce54 100644
--- a/src/variations/fpm-apache/Dockerfile
+++ b/src/variations/fpm-apache/Dockerfile
@@ -80,20 +80,23 @@ ENV APACHE_DOCUMENT_ROOT=/var/www/html/public \
PHP_MAX_INPUT_VARS="1000" \
PHP_MEMORY_LIMIT="256M" \
PHP_OPCACHE_ENABLE="0" \
+ PHP_OPCACHE_ENABLE_CLI="1" \
PHP_OPCACHE_ENABLE_FILE_OVERRIDE="0" \
PHP_OPCACHE_FORCE_RESTART_TIMEOUT="180" \
- PHP_OPCACHE_INTERNED_STRINGS_BUFFER="8" \
+ PHP_OPCACHE_INTERNED_STRINGS_BUFFER="32" \
PHP_OPCACHE_JIT="off" \
PHP_OPCACHE_JIT_BUFFER_SIZE="0" \
- PHP_OPCACHE_MAX_ACCELERATED_FILES="10000" \
- PHP_OPCACHE_MEMORY_CONSUMPTION="128" \
+ PHP_OPCACHE_MAX_ACCELERATED_FILES="32531" \
+ PHP_OPCACHE_MEMORY_CONSUMPTION="256" \
+ PHP_OPCACHE_PRELOAD="" \
+ PHP_OPCACHE_PRELOAD_USER="" \
PHP_OPCACHE_REVALIDATE_FREQ="2" \
PHP_OPCACHE_SAVE_COMMENTS="1" \
- PHP_OPCACHE_VALIDATE_TIMESTAMPS="1" \
+ PHP_OPCACHE_VALIDATE_TIMESTAMPS="0" \
PHP_OPEN_BASEDIR="" \
PHP_POST_MAX_SIZE="100M" \
PHP_REALPATH_CACHE_SIZE="4096K" \
- PHP_REALPATH_CACHE_TTL="120" \
+ PHP_REALPATH_CACHE_TTL="600" \
PHP_SESSION_COOKIE_HTTPONLY="On" \
PHP_SESSION_COOKIE_SECURE=false \
PHP_UPLOAD_MAX_FILE_SIZE="100M" \
diff --git a/src/variations/fpm-nginx/Dockerfile b/src/variations/fpm-nginx/Dockerfile
index fcbdb9d92..e8d12a90d 100644
--- a/src/variations/fpm-nginx/Dockerfile
+++ b/src/variations/fpm-nginx/Dockerfile
@@ -154,20 +154,23 @@ ENV APP_BASE_DIR=/var/www/html \
PHP_MAX_INPUT_VARS="1000" \
PHP_MEMORY_LIMIT="256M" \
PHP_OPCACHE_ENABLE="0" \
+ PHP_OPCACHE_ENABLE_CLI="1" \
PHP_OPCACHE_ENABLE_FILE_OVERRIDE="0" \
PHP_OPCACHE_FORCE_RESTART_TIMEOUT="180" \
- PHP_OPCACHE_INTERNED_STRINGS_BUFFER="8" \
+ PHP_OPCACHE_INTERNED_STRINGS_BUFFER="32" \
PHP_OPCACHE_JIT="off" \
PHP_OPCACHE_JIT_BUFFER_SIZE="0" \
- PHP_OPCACHE_MAX_ACCELERATED_FILES="10000" \
- PHP_OPCACHE_MEMORY_CONSUMPTION="128" \
+ PHP_OPCACHE_MAX_ACCELERATED_FILES="32531" \
+ PHP_OPCACHE_MEMORY_CONSUMPTION="256" \
+ PHP_OPCACHE_PRELOAD="" \
+ PHP_OPCACHE_PRELOAD_USER="" \
PHP_OPCACHE_REVALIDATE_FREQ="2" \
PHP_OPCACHE_SAVE_COMMENTS="1" \
- PHP_OPCACHE_VALIDATE_TIMESTAMPS="1" \
+ PHP_OPCACHE_VALIDATE_TIMESTAMPS="0" \
PHP_OPEN_BASEDIR="" \
PHP_POST_MAX_SIZE="100M" \
PHP_REALPATH_CACHE_SIZE="4096K" \
- PHP_REALPATH_CACHE_TTL="120" \
+ PHP_REALPATH_CACHE_TTL="600" \
PHP_SESSION_COOKIE_HTTPONLY="On" \
PHP_SESSION_COOKIE_SECURE=false \
PHP_UPLOAD_MAX_FILE_SIZE="100M" \
diff --git a/src/variations/fpm/Dockerfile b/src/variations/fpm/Dockerfile
index bea96aa4f..eeead1f5e 100644
--- a/src/variations/fpm/Dockerfile
+++ b/src/variations/fpm/Dockerfile
@@ -52,20 +52,23 @@ ENV APP_BASE_DIR=/var/www/html \
PHP_MAX_INPUT_VARS="1000" \
PHP_MEMORY_LIMIT="256M" \
PHP_OPCACHE_ENABLE="0" \
+ PHP_OPCACHE_ENABLE_CLI="1" \
PHP_OPCACHE_ENABLE_FILE_OVERRIDE="0" \
PHP_OPCACHE_FORCE_RESTART_TIMEOUT="180" \
- PHP_OPCACHE_INTERNED_STRINGS_BUFFER="8" \
+ PHP_OPCACHE_INTERNED_STRINGS_BUFFER="32" \
PHP_OPCACHE_JIT="off" \
PHP_OPCACHE_JIT_BUFFER_SIZE="0" \
- PHP_OPCACHE_MAX_ACCELERATED_FILES="10000" \
- PHP_OPCACHE_MEMORY_CONSUMPTION="128" \
+ PHP_OPCACHE_MAX_ACCELERATED_FILES="32531" \
+ PHP_OPCACHE_MEMORY_CONSUMPTION="256" \
+ PHP_OPCACHE_PRELOAD="" \
+ PHP_OPCACHE_PRELOAD_USER="" \
PHP_OPCACHE_REVALIDATE_FREQ="2" \
PHP_OPCACHE_SAVE_COMMENTS="1" \
- PHP_OPCACHE_VALIDATE_TIMESTAMPS="1" \
+ PHP_OPCACHE_VALIDATE_TIMESTAMPS="0" \
PHP_OPEN_BASEDIR="" \
PHP_POST_MAX_SIZE="100M" \
PHP_REALPATH_CACHE_SIZE="4096K" \
- PHP_REALPATH_CACHE_TTL="120" \
+ PHP_REALPATH_CACHE_TTL="600" \
PHP_SESSION_COOKIE_HTTPONLY="On" \
PHP_SESSION_COOKIE_SECURE=Off \
PHP_UPLOAD_MAX_FILE_SIZE="100M" \
diff --git a/src/variations/frankenphp/Dockerfile b/src/variations/frankenphp/Dockerfile
index 29a63c595..2ec91e048 100644
--- a/src/variations/frankenphp/Dockerfile
+++ b/src/variations/frankenphp/Dockerfile
@@ -163,20 +163,23 @@ LABEL org.opencontainers.image.title="serversideup/php (frankenphp)" \
PHP_MAX_INPUT_VARS="1000" \
PHP_MEMORY_LIMIT="256M" \
PHP_OPCACHE_ENABLE="0" \
+ PHP_OPCACHE_ENABLE_CLI="1" \
PHP_OPCACHE_ENABLE_FILE_OVERRIDE="0" \
PHP_OPCACHE_FORCE_RESTART_TIMEOUT="180" \
- PHP_OPCACHE_INTERNED_STRINGS_BUFFER="8" \
+ PHP_OPCACHE_INTERNED_STRINGS_BUFFER="32" \
PHP_OPCACHE_JIT="off" \
PHP_OPCACHE_JIT_BUFFER_SIZE="0" \
- PHP_OPCACHE_MAX_ACCELERATED_FILES="10000" \
- PHP_OPCACHE_MEMORY_CONSUMPTION="128" \
+ PHP_OPCACHE_MAX_ACCELERATED_FILES="32531" \
+ PHP_OPCACHE_MEMORY_CONSUMPTION="256" \
+ PHP_OPCACHE_PRELOAD="" \
+ PHP_OPCACHE_PRELOAD_USER="" \
PHP_OPCACHE_REVALIDATE_FREQ="2" \
PHP_OPCACHE_SAVE_COMMENTS="1" \
- PHP_OPCACHE_VALIDATE_TIMESTAMPS="1" \
+ PHP_OPCACHE_VALIDATE_TIMESTAMPS="0" \
PHP_OPEN_BASEDIR="" \
PHP_POST_MAX_SIZE="100M" \
PHP_REALPATH_CACHE_SIZE="4096K" \
- PHP_REALPATH_CACHE_TTL="120" \
+ PHP_REALPATH_CACHE_TTL="600" \
PHP_SESSION_COOKIE_HTTPONLY="On" \
PHP_SESSION_COOKIE_SECURE=false \
PHP_UPLOAD_MAX_FILE_SIZE="100M" \