When configuring Apache for PHP applications on resource-constrained VPS instances, the MPM selection fundamentally impacts performance and stability. The Worker MPM's hybrid process-thread model offers memory efficiency through thread pooling, while Prefork maintains strict process isolation.
Despite common misconceptions, modern PHP versions (5.4+) exhibit decent thread-safety when using ZTS
(Zend Thread Safety) builds. The real constraints emerge from:
// Common non-thread-safe patterns
setlocale(LC_ALL, 'en_US.UTF-8'); // Locale mutation
global $counter; // Shared global state
Benchmarking on a 1GB VPS:
MPM | Concurrent Users | Memory/Req |
---|---|---|
Prefork | ~150 | 8MB |
Worker | ~400 | 3MB |
For Worker MPM with PHP-FPM:
# httpd.conf
ServerLimit 16
StartServers 4
ThreadsPerChild 25
MaxRequestWorkers 400
PHP-FPM pool setup:
[www]
listen = 127.0.0.1:9000
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
- Verify all extensions are thread-safe (opcache, redis)
- Replace
mod_php
withphp-fpm
- Stress-test with
ab -n 1000 -c 50
Legacy applications using:
// Problematic patterns
$_SESSION['cart'] = unserialize($data); // Serialization races
apc_store('cache', $obj); // Shared cache corruption
When configuring Apache for PHP on resource-constrained VPS instances, the MPM choice becomes critical. While benchmarks consistently show Worker's performance advantages, the PHP ecosystem's historical thread-safety concerns create legitimate hesitation.
# Typical Worker configuration (httpd.conf)
StartServers 2
MinSpareThreads 25
MaxSpareThreads 75
ThreadsPerChild 25
MaxRequestWorkers 150
MaxConnectionsPerChild 0
The hybrid threaded model significantly reduces memory overhead compared to Prefork's process-per-connection approach. On my 1GB RAM VPS, Worker handles 150 concurrent requests using ~400MB RAM, while Prefork struggles beyond 50 connections.
Modern PHP versions (7.0+) have dramatically improved thread safety, but caveats remain:
- Extension compatibility (check with
php -m | grep -i thread
) - Session handling requires
php_admin_value session.save_handler = files
- Avoid
setlocale()
in threaded contexts
# Prefork (traditional safe choice)
<IfModule mpm_prefork_module>
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxRequestWorkers 50
MaxConnectionsPerChild 1000
</IfModule>
# Worker (optimized setup)
<IfModule mpm_worker_module>
ServerLimit 4
ThreadLimit 64
StartServers 2
MaxRequestWorkers 150
MinSpareThreads 25
MaxSpareThreads 75
ThreadsPerChild 25
</IfModule>
Testing with ab -n 1000 -c 50
on WordPress:
MPM | Req/sec | Memory | 90% Latency |
---|---|---|---|
Prefork | 98.21 | 512MB | 620ms |
Worker | 142.76 | 310MB | 380ms |
For those considering nginx:
# Sample PHP-FPM pool configuration
[www]
user = www-data
group = www-data
listen = /run/php/php7.4-fpm.sock
pm = dynamic
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 2
pm.max_spare_servers = 8
- Verify PHP extensions with
php -i | grep Thread
- Switch Apache MPM:
a2dismod mpm_prefork && a2enmod mpm_worker
- Install thread-safe PHP:
apt install php-zts
- Monitor with
htop -d 1 -p $(pgrep httpd)