PHP-FPM on Performance VPS Tune the PHP-FPM pool (pm, pm.max_children, slowlog) on a HolyCloud Performance VPS to maximize PHP throughput without saturating RAM. ~12 min read Intermediate #php-fpm #php #performance #nginx PHP-FPM on Performance VPS PHP-FPM runs PHP scripts in processes separate from the web server. On a HolyCloud Performance VPS, a poorly sized pool causes 502 errors (exhausted workers) or saturated RAM (too many max_children). Prerequisites VPS with Nginx or Apache + PHP-FPM (e.g. PHP 8.2/8.3) sudo access and knowledge of the pool path (/etc/php/8.x/fpm/pool.d/) Per-worker memory estimate (see below) Test or staging site to validate under load Locate configuration php-fpm8.3 -tt 2>/dev/null | head ls /etc/php/8.3/fpm/pool.d/ sudo nano /etc/php/8.3/fpm/pool.d/www.conf Typical [www] pool: [www] user = www-data group = www-data listen = /run/php/php8.3-fpm.sock pm = dynamic pm.max_children = 20 pm.start_servers = 4 pm.min_spare_servers = 2 pm.max_spare_servers = 6 pm.max_requests = 500 Calculate pm.max_children Starting formula: max_children ≈ (RAM available for PHP) / (average memory per worker) Measure worker memory under real load: ps -o rss,cmd -C php-fpm8.3 | awk '{sum+=$1} END {print sum/NR/1024 " MB moyenne"}' Example: 8 GB RAM VPS, OS + MySQL + Redis ≈ 3 GB left for PHP, worker ~80 MB: 5120 MB / 80 MB ≈ 64 → start at 40–50 and increase gradually pm modes: which to choose? | Mode | Usage | |------|-------| | dynamic | Default web — balance latency / RAM | | ondemand | Very sporadic traffic — slower startup | | static | Constant, predictable traffic — fixed RAM | Frequent e-commerce production: pm = dynamic pm.max_children = 48 pm.start_servers = 8 pm.min_spare_servers = 8 pm.max_spare_servers = 16 Timeouts and queues request_terminate_timeout = 120s request_slowlog_timeout = 5s slowlog = /var/log/php8.3-fpm-slow.log Avoid request_terminate_timeout = 0 (unlimited) — a stuck script monopolizes a worker. Opcache (essential) File /etc/php/8.3/mods-available/opcache.ini: opcache.enable=1 opcache.memory_consumption=256 opcache.max_accelerated_files=20000 opcache.validate_timestamps=0 validate_timestamps=0 in production after controlled deployment; set 1 in dev. Restart: sudo systemctl restart php8.3-fpm Nginx: gateway to the socket location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/run/php/php8.3-fpm.sock; fastcgi_buffers 16 16k; fastcgi_buffer_size 32k; fastcgi_read_timeout 120s; } Verification under load # FPM status (if pm.status_path enabled) curl -s http://127.0.0.1/status?full # logs sudo tail -f /var/log/php8.3-fpm.log Light HTTP test: hey -n 1000 -c 50 https://votre-site.tld/ Monitor during the test: watch -n1 'ps -C php-fpm8.3 | wc -l; free -h' Advanced tuning ; avoid long leaks pm.max_requests = 1000 ; process manager — ping for healthcheck pm.status_path = /fpm-status ping.path = /fpm-ping Protect /fpm-status by IP or Nginx auth. Troubleshooting | Symptom | Action | |----------|--------| | 502 Bad Gateway | Workers exhausted → increase max_children or optimize code | | Swap increasing | Reduce max_children, enable Redis cache | | PHP CPU 100% | Profile (Xdebug off in prod), object cache | | Slowlog filling | SQL queries, loops, synchronous API calls | Need help? Attach to support: www.conf excerpt, free -h, slowlog excerpt (no sensitive client data), and Performance VPS plan. Continue reading Previous article Optimize NVMe disks Read Next article Prometheus + Grafana + node_exporter Read