Configuring OPcache for 1C-Bitrix

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1177
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    747
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    976

Configuring OPcache for 1C-Bitrix

On the first request to a Bitrix page, PHP reads, parses, and compiles dozens of kernel files. Without OPcache, this happens on every request. With properly configured OPcache, compiled bytecode is stored in shared memory — the interpreter skips compilation and response time drops 3–5 times.

The problem isn't enabling OPcache — it's enabled by default since PHP 5.5. The issue is that default parameters are calibrated for "average" PHP applications, not Bitrix, where a single request loads 200–400 files.

Diagnosing Current State

// OPcache status
$status = opcache_get_status();
echo "Cached files: " . $status['opcache_statistics']['num_cached_scripts'] . "\n";
echo "Cache full: " . ($status['cache_full'] ? 'YES' : 'NO') . "\n";
echo "Hit rate: " . round($status['opcache_statistics']['opcache_hit_rate'], 2) . "%\n";
echo "Memory used: " . round($status['memory_usage']['used_memory'] / 1024 / 1024, 1) . " MB\n";
echo "Memory free: " . round($status['memory_usage']['free_memory'] / 1024 / 1024, 1) . " MB\n";

If cache_full = YES — OPcache is full, new files aren't cached. If Hit rate is below 90% — either there's not enough memory or frequent restarts (deployment).

Typical number of PHP files in Bitrix on a standard project:

find /var/www/bitrix/bitrix -name "*.php" | wc -l
# Usually 15000–40000 files

Correct OPcache Settings for Bitrix

In php.ini or /etc/php.d/10-opcache.ini:

[opcache]
opcache.enable = 1
opcache.enable_cli = 0

; Memory size for bytecode. For Bitrix Enterprise — 256M, for Business — 128M
opcache.memory_consumption = 192

; Interned strings table (function names, class names, constants)
opcache.interned_strings_buffer = 16

; Maximum files in cache. Should be greater than actual PHP file count
opcache.max_accelerated_files = 32531

; File change check frequency (seconds)
; On production, set to 0 with manual reset on deploy
opcache.revalidate_freq = 60

; Don't check file modification times (maximum performance)
; Requires manual reset on deploy!
opcache.validate_timestamps = 0

; AST optimizations
opcache.optimization_level = 0x7FFEBFFF

; Cache persistence between PHP-FPM restarts via shared memory
opcache.huge_code_pages = 1

; File cache path (fallback if shared memory is full)
opcache.file_cache = /tmp/opcache

; Don't allow cache reset from code (safer)
opcache.restrict_api = /var/www

validate_timestamps = 0 and Deployment

This is the most debated parameter. With validate_timestamps = 0, OPcache never checks if a file changed on disk. Speed is maximum, but code updates don't apply until PHP-FPM restarts.

Clearing cache after deployment:

# Restart PHP-FPM (reliable but a second of downtime)
systemctl reload php8.1-fpm

# Reset through CLI (PHP must see the same OPcache)
php -r "opcache_reset();"
# Warning: CLI process uses separate OPcache if php-fpm runs as daemon

# Via HTTP request to special script (works for FPM)
curl -s http://127.0.0.1/opcache_reset.php

Script /var/www/bitrix/opcache_reset.php (localhost access only):

<?php
if ($_SERVER['REMOTE_ADDR'] !== '127.0.0.1') {
    http_response_code(403);
    exit;
}
opcache_reset();
echo "OPcache reset OK\n";

opcache.huge_code_pages on Linux

On Linux with kernel 4.0+, you can place cache in huge pages (2 MB instead of 4 KB), reducing CPU TLB load:

# Allocate huge pages
echo 128 > /proc/sys/vm/nr_hugepages

# Add to /etc/sysctl.conf for permanent effect
vm.nr_hugepages = 128

With opcache.huge_code_pages = 1 enabled, PHP automatically uses huge pages for cache. The effect is noticeable on highly loaded projects — CPU reduction of 5–15%.

Production Monitoring

Official OPcache status page from PHP-group:

# Download official script
wget https://raw.githubusercontent.com/amnuts/opcache-gui/master/index.php \
  -O /var/www/bitrix/opcache-status.php
# Add IP or basic auth protection

Metrics for monitoring systems via opcache_get_status():

  • hit_rate — should be 95%+
  • cache_full — if true, increase memory_consumption
  • oom_restarts and hash_restarts — if nonzero, parameter optimization needed