Cada vez que PHP ejecuta un script tiene que leerlo, analizarlo y compilarlo a opcodes. OPcache guarda esos opcodes compilados en memoria compartida para que las siguientes peticiones se salten ese trabajo, lo que reduce el uso de CPU y el tiempo de respuesta, sobre todo en frameworks y CMS con cientos o miles de ficheros. En este tutorial ajustarás OPcache para PHP 8.3 con PHP-FPM en Ubuntu 24.04, decidirás cómo se detectan los cambios de código, activarás opcionalmente el JIT y comprobarás con un script que la caché funciona y tiene espacio suficiente.

Requisitos previos

Para seguir esta guía necesitas:

  • Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath.
  • Un usuario no root con privilegios sudo.
  • PHP 8.3 con PHP-FPM y un servidor web (Nginx o Apache) sirviendo una aplicación PHP.

Paso 1: Comprobar que OPcache está instalado

En Ubuntu 24.04 OPcache se distribuye en el paquete php8.3-opcache, que normalmente ya se instala junto con PHP-FPM. Asegúrate de que está presente:

sudo apt install php8.3-opcache

El paquete activa la extensión con el fichero /etc/php/8.3/mods-available/opcache.ini, enlazado en el directorio de configuración de PHP-FPM:

ls /etc/php/8.3/fpm/conf.d/ | grep opcache
cat /etc/php/8.3/mods-available/opcache.ini
10-opcache.ini
; configuration for php opcache module
; priority=10
zend_extension=opcache.so
opcache.jit=off

OPcache ya está activo para PHP-FPM con los valores por defecto de PHP, que son bastante conservadores: 128 MB de memoria y hasta 10.000 ficheros. Ubuntu además desactiva el JIT de forma explícita con opcache.jit=off.

Paso 2: Dimensionar la caché para tu aplicación

Hay dos límites que conviene ajustar a tu código:

  • opcache.max_accelerated_files: número máximo de scripts en caché. Debe ser mayor que el número de ficheros PHP de todas las aplicaciones que sirve el pool.
  • opcache.memory_consumption: memoria compartida en MB para los opcodes.

Cuenta los ficheros PHP de tus aplicaciones (sustituye /var/www si tu código está en otra ruta):

find /var/www -type f -name '*.php' | wc -l
14873

Con unos 15.000 ficheros, un valor de 20000 deja margen. PHP redondea internamente al siguiente número primo de una tabla fija, así que el máximo real que veas después será algo mayor. Para la memoria, 128 MB suele bastar para un WordPress con pocos plugins; 256 MB es un buen punto de partida para Laravel, Symfony, Magento o varias webs en el mismo servidor. En el paso 4 verás cuánta se usa realmente.

Paso 3: Crear un fichero de ajustes de OPcache

En lugar de editar el php.ini principal, crea un fichero propio en conf.d con un prefijo alto para que se cargue después de los del paquete y sus valores tengan prioridad:

sudo nano /etc/php/8.3/fpm/conf.d/99-opcache-tuning.ini
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000

; Revisar cambios en los ficheros como máximo cada 2 segundos
opcache.validate_timestamps=1
opcache.revalidate_freq=2

Qué hace cada directiva:

  • opcache.interned_strings_buffer: memoria en MB para cadenas repetidas (nombres de clases, métodos, claves de arrays) compartidas entre procesos. El valor por defecto es 8; 16 es adecuado para frameworks grandes.
  • opcache.validate_timestamps=1: OPcache comprueba si el fichero ha cambiado en disco y lo recompila si es así.
  • opcache.revalidate_freq=2: esa comprobación se hace como máximo una vez cada 2 segundos por fichero.

Comprueba la sintaxis y recarga PHP-FPM. La recarga también vacía la caché de OPcache:

sudo php-fpm8.3 -t
sudo systemctl reload php8.3-fpm
[25-Sep-2026 12:04:17] NOTICE: configuration file /etc/php/8.3/fpm/php-fpm.conf test is successful

Producción: desactivar la comprobación de cambios

Si despliegas el código de forma controlada (git, CI, rsync) y no editas ficheros a mano en el servidor, puedes evitar que PHP consulte el disco en cada revalidación:

opcache.validate_timestamps=0

Con este valor OPcache nunca detecta cambios por sí solo. Debes recargar PHP-FPM al terminar cada despliegue, o seguirás sirviendo el código antiguo:

sudo systemctl reload php8.3-fpm

Si no controlas cuándo cambia el código (por ejemplo, un WordPress que actualiza plugins desde el panel), mantén opcache.validate_timestamps=1.

Paso 4: Comprobar el estado de OPcache

Para ver la configuración y el uso reales de PHP-FPM, crea un pequeño script fuera del directorio público de la web:

sudo mkdir -p /var/www/tools
sudo nano /var/www/tools/opcache-status.php
<?php
$s  = opcache_get_status(false);
$m  = $s['memory_usage'];
$st = $s['opcache_statistics'];

printf("OPcache activo: %s\n", $s['opcache_enabled'] ? 'si' : 'no');
printf("Memoria usada: %.1f MB, libre: %.1f MB\n", $m['used_memory'] / 1048576, $m['free_memory'] / 1048576);
printf("Scripts en cache: %d de %d\n", $st['num_cached_scripts'], $st['max_cached_keys']);
printf("Tasa de aciertos: %.2f%%\n", $st['opcache_hit_rate']);
printf("Reinicios por memoria llena: %d\n", $st['oom_restarts']);
printf("JIT: %s (buffer %s)\n", ini_get('opcache.jit'), ini_get('opcache.jit_buffer_size'));

Ejecútalo a través del socket de PHP-FPM con cgi-fcgi, para no tener que publicarlo en el servidor web:

sudo apt install libfcgi-bin
sudo SCRIPT_FILENAME=/var/www/tools/opcache-status.php REQUEST_METHOD=GET cgi-fcgi -bind -connect /run/php/php8.3-fpm.sock

Tras un rato de tráfico real verás algo parecido a esto:

Content-type: text/html; charset=UTF-8

OPcache activo: si
Memoria usada: 142.6 MB, libre: 113.4 MB
Scripts en cache: 9120 de 32531
Tasa de aciertos: 99.87%
Reinicios por memoria llena: 0
JIT: off (buffer 0)

Cómo leerlo:

  • Tasa de aciertos: debe estar por encima del 99 % con tráfico estable. Justo después de una recarga será baja hasta que se compilen los scripts.
  • Memoria libre: si baja de un 10 % del total o Reinicios por memoria llena es mayor que 0, sube opcache.memory_consumption.
  • Scripts en cache: si se acerca al máximo, sube opcache.max_accelerated_files.

Paso 5: Activar el JIT (opcional)

PHP 8 incluye un compilador JIT que traduce los opcodes más usados a código máquina. Mejora mucho el código de cálculo intensivo (procesamiento de imágenes, algoritmos, scripts matemáticos), pero en aplicaciones web típicas, que pasan la mayor parte del tiempo esperando a la base de datos, la mejora suele ser pequeña. Actívalo solo si tus pruebas muestran una mejora.

Añade estas líneas a /etc/php/8.3/fpm/conf.d/99-opcache-tuning.ini:

opcache.jit=tracing
opcache.jit_buffer_size=64M

El JIT solo funciona si opcache.jit_buffer_size es mayor que 0. Recarga PHP-FPM y vuelve a ejecutar el script de estado:

sudo systemctl reload php8.3-fpm
sudo SCRIPT_FILENAME=/var/www/tools/opcache-status.php REQUEST_METHOD=GET cgi-fcgi -bind -connect /run/php/php8.3-fpm.sock | grep JIT
JIT: tracing (buffer 64M)

Mide el antes y el después con una herramienta como Apache Bench contra una página real de tu aplicación. Si no hay diferencia, vuelve a opcache.jit=off para ahorrar esa memoria.

Paso 6: Medir la mejora

Para confirmar el efecto de OPcache, compara las peticiones por segundo con la caché activada y desactivada. Instala Apache Bench:

sudo apt install apache2-utils

Lanza 500 peticiones con 10 conexiones concurrentes contra una página PHP de tu aplicación (your_domain):

ab -n 500 -c 10 https://your_domain/

Anota el valor de Requests per second. Después, pon temporalmente opcache.enable=0 en 99-opcache-tuning.ini, recarga PHP-FPM, repite la prueba y vuelve a activarlo. En aplicaciones basadas en frameworks es habitual que las peticiones por segundo se multipliquen por dos o por tres con OPcache activo.

Solución de problemas

  • Los cambios de código no aparecen: tienes opcache.validate_timestamps=0 o un revalidate_freq alto. Recarga PHP-FPM con sudo systemctl reload php8.3-fpm.
  • Call to undefined function opcache_get_status(): la extensión no está cargada en PHP-FPM. Comprueba que existe /etc/php/8.3/fpm/conf.d/10-opcache.ini y ejecuta sudo phpenmod opcache si no.
  • Los ajustes no se aplican: otro fichero de conf.d con un número mayor los sobrescribe, o los estás comprobando con php -i (CLI). Usa siempre el script del paso 4.
  • Tasa de aciertos baja de forma permanente: la caché se llena y se reinicia. Revisa los reinicios por memoria llena y sube los límites del paso 2.

Conclusión

OPcache está ahora dimensionado para tu código, con una estrategia clara para detectar cambios en cada despliegue y un script que te dice si la caché tiene memoria y capacidad suficientes. Como siguientes pasos, ajusta el tamaño de los pools de PHP-FPM a la memoria disponible, añade una caché de datos con Memcached o Redis y activa la compresión Gzip o Brotli en tu servidor web.