PHP Performance Tuning on VPS: OPcache, PHP-FPM, and JIT Compiler Configuration

PHP Performance Tuning on VPS: OPcache, PHP-FPM, and JIT Compiler Configuration

PHP 8.x with proper OPcache configuration delivers 3–10× better performance than PHP 7.x with default settings. OPcache eliminates PHP’s most expensive operation — parsing and compiling PHP scripts on every request — by caching compiled bytecode in shared memory. The JIT compiler (PHP 8.0+) converts hot bytecode to native machine code. PHP-FPM pool tuning determines how many concurrent requests your VPS handles efficiently.

Baseline: Measure Before Optimizing

# Benchmark current performance with Apache Bench
ab -n 500 -c 10 https://yourdomain.com/

# Key metrics to record before and after:
# - Requests per second: X #/sec
# - Mean time per request: X ms
# - 95th percentile response time: X ms

Step 1: Configure OPcache

OPcache is the single highest-impact PHP performance change — it eliminates PHP compilation on every request by caching compiled bytecode in shared memory.

sudo nano /etc/php/8.2/fpm/conf.d/10-opcache.ini
[opcache]
; Enable OPcache
opcache.enable=1
opcache.enable_cli=0              ; Don't cache CLI (Composer, WP-CLI) — not needed

; Shared memory for compiled bytecode
; WordPress with active plugins typically needs 128–256 MB
opcache.memory_consumption=256

; Shared memory for string interning (class/function names)
opcache.interned_strings_buffer=32

; Maximum number of PHP files to cache
; Count your PHP files: find /var/www -name "*.php" | wc -l
; Set to 2× that count to avoid evictions
opcache.max_accelerated_files=20000

; How often to check for file changes (seconds)
; 0 = check every request (development only!)
; 300 = check every 5 minutes (production recommended)
opcache.revalidate_freq=300

; Must be 1 for Laravel, WordPress, and most frameworks
opcache.save_comments=1

; Fast shutdown improves memory release speed
opcache.fast_shutdown=1

; Override file_exists() checks for cached files
opcache.enable_file_override=1

Step 2: Enable JIT Compiler (PHP 8.0+)

JIT converts PHP bytecode to native machine code at runtime. Significant benefit for CPU-intensive code; minimal benefit for I/O-bound apps like typical WordPress installs.

# Add to /etc/php/8.2/fpm/conf.d/10-opcache.ini:

; JIT buffer size (native code cache)
opcache.jit_buffer_size=128M

; JIT mode:
; tracing  = Best for web workloads (profiles actual execution paths)
; function = Per-function JIT (good for libraries)
; on       = Alias for tracing
opcache.jit=tracing

JIT benefit by workload type:

  • High benefit: Image processing (GD, Imagick), cryptography, mathematical computation, data transformation scripts
  • Moderate benefit: Laravel/Symfony framework boot, template rendering
  • Low benefit: WordPress page rendering (mostly I/O — database queries, file reads)
sudo systemctl restart php8.2-fpm

Step 3: PHP-FPM Pool Tuning

sudo nano /etc/php/8.2/fpm/pool.d/www.conf

Dynamic Mode (Recommended for Most Sites)

[www]
user = www-data
group = www-data
listen = /run/php/php8.2-fpm.sock
listen.owner = www-data
listen.group = www-data

; Dynamic: scales worker count with demand
pm = dynamic

; Worker count formula: (available RAM - 200 MB OS overhead) / avg PHP process size
; Average WordPress PHP process: 40–80 MB
; Example for 2 GB VPS: (2000 - 200) / 60 MB = ~30 max, start conservatively
pm.max_children = 10

; Workers at startup
pm.start_servers = 3

; Minimum idle workers (always ready for traffic)
pm.min_spare_servers = 2

; Maximum idle workers (kill extras when traffic drops)
pm.max_spare_servers = 5

; Restart each worker after N requests (prevents gradual memory leak)
pm.max_requests = 500

; Kill requests taking longer than this (seconds)
request_terminate_timeout = 120

; Log slow requests (helps find slow queries or plugins)
slowlog = /var/log/php8.2-fpm-slow.log
request_slowlog_timeout = 5s

; Enable status endpoint (for monitoring)
pm.status_path = /fpm-status

OnDemand Mode (Low-Traffic or Shared VPS)

; Start workers only when requests arrive — saves RAM when idle
pm = ondemand
pm.max_children = 10
pm.process_idle_timeout = 10s   ; Kill idle workers after 10 seconds
pm.max_requests = 200
sudo systemctl restart php8.2-fpm

Step 4: Per-Site PHP-FPM Pools

For multiple sites on one VPS, separate pools prevent one site’s traffic from starving others:

sudo cp /etc/php/8.2/fpm/pool.d/www.conf /etc/php/8.2/fpm/pool.d/site1.conf
sudo nano /etc/php/8.2/fpm/pool.d/site1.conf
[site1]
user = site1_user
group = site1_user
listen = /run/php/php8.2-site1.sock    ; Unique socket per site
pm = dynamic
pm.max_children = 5
pm.start_servers = 1
pm.min_spare_servers = 1
pm.max_spare_servers = 3
pm.max_requests = 200
sudo systemctl restart php8.2-fpm

Reference the site-specific socket in Nginx:

fastcgi_pass unix:/run/php/php8.2-site1.sock;

Step 5: Check OPcache Effectiveness

# Create a one-time status check script
sudo -u www-data php -r "
\$s = opcache_get_status();
echo 'Hit rate: ' . round(\$s['opcache_statistics']['opcache_hit_rate'], 2) . \"%\n\";
echo 'Cached files: ' . \$s['opcache_statistics']['num_cached_scripts'] . \"\n\";
echo 'Memory used: ' . round(\$s['memory_usage']['used_memory'] / 1024 / 1024, 1) . \" MB\n\";
echo 'Memory free: ' . round(\$s['memory_usage']['free_memory'] / 1024 / 1024, 1) . \" MB\n\";
"

Healthy OPcache targets:

  • Hit rate > 95%: If below 90%, increase max_accelerated_files or memory_consumption
  • Memory used < 80% of limit: If above 90%, increase memory_consumption
  • Cached files ≈ your PHP file count: If much lower, increase max_accelerated_files

Step 6: Force OPcache Flush After Deployments

When deploying new PHP code, OPcache may serve the old compiled version until revalidate_freq expires:

# Reset entire OPcache (run as www-data)
sudo -u www-data php -r "opcache_reset(); echo 'OPcache cleared\n';"

# Graceful PHP-FPM reload (faster than full restart, no dropped requests)
sudo systemctl reload php8.2-fpm

Expected Performance Improvements

Configuration WordPress Requests/sec TTFB
Default PHP 8.2 (no OPcache) ~15 ~400ms
OPcache enabled (defaults) ~45 ~150ms
OPcache tuned (this guide) ~65 ~100ms
OPcache + Redis object cache ~80 ~70ms
OPcache + Redis + Nginx page cache ~3,000+ ~5ms

Getting Started

OPcache tuning is the highest-impact, zero-cost PHP performance improvement — configuration changes to an existing installation, no code changes required. All Ubuntu VPS plans at VPS.DO include PHP 8.2+ with OPcache available. Apply these settings, run the benchmark again, and compare — the improvement is typically 3–5× for WordPress sites.

Conclusion

PHP performance on a VPS is determined by three configuration decisions: OPcache memory allocation (eliminate recompilation), PHP-FPM process count (match to available RAM), and request-based worker recycling (prevent memory leaks). JIT adds benefit for CPU-intensive workloads. Together, these changes deliver 3–5× throughput improvement over default PHP configurations — the highest-ROI optimization available for PHP-based VPS hosting.

Fast • Reliable • Affordable VPS - DO It Now!

Get top VPS hosting with VPS.DO’s fast, low-cost plans. Try risk-free with our 7-day no-questions-asked refund and start today!