PHP-FPM (FastCGI Process Manager) is the standard way to run PHP on modern web servers. A well-configured PHP-FPM setup can make the difference between a slow and a fast website. At Theory7, we often see that default configurations are not optimal for the specific workload. In this guide, you will learn how to correctly configure and optimize PHP-FPM for maximum performance.

What is PHP-FPM?

PHP-FPM manages a pool of PHP worker processes. When a PHP page is requested, one of these workers handles the request. The way workers are managed largely determines the performance of your website. This is crucial, especially for websites with high visitor numbers or intensive applications.

Benefits of PHP-FPM:

  • Better resource management than mod_php, allowing your server to use available resources more efficiently.
  • Process isolation per website, which increases security and stability.
  • Graceful restarts without downtime, which is essential for websites that need to be continuously available.
  • Advanced logging options, giving you better insight into performance and potential issues.

Pool Configuration

The pool configuration determines how many PHP processes are running. This file is usually found at:

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

Replace 8.2 with your PHP version. It is important to adjust this configuration to the specific needs of your application.

Process Manager Modes

PHP-FPM has three modes:

  • static - Fixed number of workers
    pm = static
    pm.max_children = 20

    Best for dedicated servers with predictable load.
  • dynamic - Automatically scales
    pm = dynamic
    pm.max_children = 50
    pm.start_servers = 10
    pm.min_spare_servers = 5
    pm.max_spare_servers = 20

    Best for most situations, especially with fluctuating visitor numbers.
  • ondemand - Workers only on requests
    pm = ondemand
    pm.max_children = 50
    pm.process_idle_timeout = 10s

    Best for servers with low traffic or limited memory.

Calculating max_children

The max_children value depends on your available memory. It is crucial to calculate this value correctly to prevent server overload:

max_children = (Available RAM - Other usage) / Average PHP process size

Example calculation:

  • 4 GB RAM server
  • 1 GB for OS and database
  • Average PHP process: 50 MB
  • max_children = 3000 MB / 50 MB = 60

Check the average memory usage per PHP process with the following command:

ps --no-headers -o "rss" -C php-fpm | awk '{ sum+=$1 } END { print sum/NR/1024 " MB" }'

Request Limits

Prevent memory leaks by periodically refreshing processes. You can set this with:

pm.max_requests = 500

After 500 requests, a worker will be restarted. This prevents memory growth due to poorly written code, which is crucial for the stability of your application.

php.ini Optimization

In addition to the pool configuration, the php.ini is also important for the performance of your PHP applications.

Memory and Execution Limits

Set the memory and execution limits based on the needs of your application:

memory_limit = 256M
max_execution_time = 300
max_input_time = 300

Adjust these according to your application. For example, WordPress often requires 256M, while large imports require more memory.

Upload Limits

Set the upload limits to ensure your application can handle large files:

upload_max_filesize = 64M
post_max_size = 64M
max_file_uploads = 20

Note: post_max_size must be equal to or greater than upload_max_filesize.

OPcache Configuration

OPcache stores compiled PHP code in memory, which can significantly speed up your application's load time:

opcache.enable = 1
opcache.memory_consumption = 128
opcache.interned_strings_buffer = 16
opcache.max_accelerated_files = 10000
opcache.revalidate_freq = 60
opcache.validate_timestamps = 1
opcache.fast_shutdown = 1

For production, you can set validate_timestamps to 0 for extra speed, but you will need to manually clear OPcache on code changes.

Realpath Cache

To reduce filesystem calls for include/require statements, you can configure the realpath cache:

realpath_cache_size = 4M
realpath_cache_ttl = 600

Applying Configuration

After making changes, you need to restart PHP-FPM to apply the new settings:

# Systemd
sudo systemctl restart php8.2-fpm

# Or for other versions
sudo systemctl restart php7.4-fpm

Test if the configuration is valid with:

sudo php-fpm8.2 -t

Multiple Pools for Multiple Sites

For better isolation, you can create a separate pool for each website. This is especially useful for hosting providers or developers managing multiple projects:

sudo cp /etc/php/8.2/fpm/pool.d/www.conf /etc/php/8.2/fpm/pool.d/mysite.conf

Adjust in mysite.conf:

[mysite]
user = myuser
group = myuser
listen = /run/php/php8.2-fpm-mysite.sock

Configure your web server to use the correct socket for each site, so that each site has its own resources and performs better.

Monitoring PHP-FPM Status

Activate the status page to monitor your PHP-FPM processes:

pm.status_path = /fpm-status

Configure your web server to serve this (only locally):

location /fpm-status {
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
include fastcgi_params;
allow 127.0.0.1;
deny all;
}

Troubleshooting

502 Bad Gateway

This may mean that PHP-FPM is not running or that the socket is misconfigured. Check the status with:

sudo systemctl status php8.2-fpm

Slow Performance

If you notice that performance is slow, check if max_children is set too low. You can do this by checking the logs:

sudo tail -f /var/log/php8.2-fpm.log

Look for messages like "server reached max_children" to see if you need to add more workers.

Memory Errors

If you encounter memory errors, consider increasing memory_limit or optimizing your code to use less memory.

Need Help?

We are here for you! Are you facing any issues or do you have questions? Our support team is happy to assist you personally. Send us a message via the ticket system - we usually respond within a few hours and are happy to help.