mod_php requires Apache prefork MPM — mpm_event and mpm_worker are incompatible. This page gives the exact sequence to install PHP as Apache Handler correctly on Ubuntu, Debian, and RHEL.
What is PHP as Apache Handler (mod_php)?
PHP as Apache Handler means PHP is loaded as a module inside the Apache process itself — every Apache worker process has PHP embedded. This is fundamentally different from PHP-FPM, where Apache proxies requests to a separate PHP process pool. With mod_php, there is no PHP process manager to configure, no socket or port to communicate over, and no separate service to restart. PHP runs in the same process space as Apache. The tradeoff is that mod_php is only compatible with Apache’s prefork MPM. The event and worker MPMs use threads rather than processes, and mod_php is not thread-safe (it is not designed to run in a multi-threaded process). Attempting to load mod_php alongside mpm_event results in either a silent failure or an Apache startup error. The correct setup sequence: install the PHP Apache module package, disable mpm_event and mpm_worker, enable mpm_prefork, enable the PHP module, then verify with apache2ctl -M. Skipping the MPM step is the most common installation mistake.
Tools and Commands
# Ubuntu/Debian: install PHP as Apache handler module
apt install libapache2-mod-php8.2
# Disable incompatible MPMs
a2dismod mpm_event
a2dismod mpm_worker
# Enable prefork MPM (required for mod_php)
a2enmod mpm_prefork
# Enable the PHP module
a2enmod php8.2
# Graceful restart (no downtime)
apachectl graceful
# Verify PHP module is loaded
apache2ctl -M | grep php
# Verify PHP SAPI is apache2handler
php -r 'echo php_sapi_name();'
# RHEL/CentOS: install mod_php
yum install php php-mysqlnd
systemctl restart httpdOn Ubuntu/Debian, the package name includes the PHP version: libapache2-mod-php8.2. Installing this package automatically enables the module but does not switch the MPM. The MPM switch must be done manually. On RHEL/CentOS, yum install php installs mod_php by default with the prefork MPM — no MPM switching is needed.
Key Parameters
| Flag / Parameter | Description | Security Note |
|---|---|---|
a2enmod / a2dismod | Enable or disable Apache modules. Creates/removes symlinks in /etc/apache2/mods-enabled/. | Always follow a2dismod mpm_event with a2enmod mpm_prefork in the same step before enabling mod_php. Apache will refuse to start if mpm_event is enabled alongside mod_php. |
mpm_prefork | Apache Multi-Processing Module that uses separate processes (not threads) for each worker. | Required for mod_php. Memory usage is higher than event/worker MPMs because each worker carries a full PHP interpreter. Size MaxRequestWorkers to avoid OOM — see the prefork tuning page. |
php_sapi_name() | PHP function that returns the current Server API. Should return 'apache2handler' when mod_php is active. | If php_sapi_name() returns 'fpm-fcgi' or 'cgi', PHP is NOT running as mod_php — Apache is proxying to PHP-FPM or CGI. Verify the mod_php module is loaded with apache2ctl -M. |
apachectl graceful | Reloads Apache config and modules without dropping active connections. | Use graceful (not restart) after module changes in production — restart drops all active connections, graceful lets them finish. After changing the MPM, a full restart is required: the MPM is loaded at startup. |
apache2ctl -M | List all loaded Apache modules. Verify both mpm_prefork and the PHP module appear. | Look for 'php8.2_module' and 'mpm_prefork_module' in the output. If mpm_event_module appears alongside php, the setup is incorrect and Apache may behave unpredictably. |
Diagnosis and Fix Workflows
Ubuntu 22.04: full mod_php installation sequence
On a fresh Ubuntu 22.04 Apache install, mpm_event is enabled by default. Installing libapache2-mod-php without switching the MPM first causes Apache to fail silently or produce a confusing error. The correct sequence is: install the package, then switch the MPM, then restart.
# Install PHP module package
apt install libapache2-mod-php8.2
# Switch MPM: disable event, enable prefork
a2dismod mpm_event
a2enmod mpm_prefork
# Enable PHP module if not auto-enabled
a2enmod php8.2
# Full restart required after MPM change (graceful is not enough)
systemctl restart apache2
# Verify
apache2ctl -M | grep -E 'php|mpm'
php -r 'echo php_sapi_name() . PHP_EOL;'Verify PHP is running as Apache handler and not as FPM
After installation, create a quick PHP info check to confirm the SAPI. If php_sapi_name() returns anything other than apache2handler, mod_php is not active for web requests — Apache may be proxying to a PHP-FPM socket. Check the Apache virtual host config for SetHandler directives pointing to a FastCGI socket.
# Create a test script
echo '<?php echo php_sapi_name(); ?>' > /var/www/html/sapi_check.php
# Test via curl
curl http://localhost/sapi_check.php
# Should output: apache2handler
# Remove the test file
rm /var/www/html/sapi_check.phpDiagnose an Apache startup failure after module changes
If Apache fails to start after enabling mod_php, the most common cause is an MPM conflict. Check the error log and use apachectl configtest to get the specific error. The message ‘Cannot load mod_php’ or ‘AH00548: NameVirtualHost has no effect and will be removed’ alongside an mpm_event error is diagnostic.
# Check Apache config syntax
apachectl configtest
# Check Apache error log for module load failures
tail -50 /var/log/apache2/error.log
# List currently enabled modules
a2query -m
# If mpm_event is still enabled alongside php:
a2dismod mpm_event && a2enmod mpm_prefork && systemctl restart apache2Performance Impact: MPM Selection Determines Memory and Stability Model
The choice of MPM is not just a compatibility requirement — it fundamentally determines how the server handles memory and concurrency. With mpm_prefork and mod_php, each Apache worker process contains a full PHP interpreter. 30 workers means 30 PHP interpreters in memory simultaneously. The PHP OPcache is shared across all workers (a significant advantage over PHP-FPM per-pool OPcache). Memory usage per worker is predictable and constant. With mpm_event and PHP-FPM, Apache workers are lightweight (no PHP embedded), and PHP-FPM manages its own process pool separately. The advantage is lower Apache memory footprint per worker; the tradeoff is additional process management complexity and the PHP-FPM service as a separate failure point. On servers where stability and simplicity matter more than maximum throughput, mod_php with prefork eliminates the PHP-FPM process manager entirely as a failure point. A PHP-FPM misconfiguration (wrong pm.max_children, wrong socket path) cannot happen when there is no PHP-FPM. The prefork memory model is larger but more predictable — see the prefork tuning page for the correct MaxRequestWorkers formula.
- Never enable mod_php alongside mpm_event or mpm_worker — this causes unpredictable behaviour including request corruption and PHP crashes.
- After switching MPMs, a full Apache restart (not graceful) is required — the MPM is loaded at process startup, not on config reload.
- Each prefork worker with mod_php consumes the base PHP memory overhead (~15-20MB before any script runs) — size MaxRequestWorkers against available RAM, not just desired concurrency.
- On RHEL/AlmaLinux, the default Apache install uses prefork — do not switch to event without also switching to PHP-FPM, or PHP will stop working for web requests.
Practical Examples
Ubuntu 22.04: full mod_php install with MPM switch
# Install
apt install -y libapache2-mod-php8.2
# Switch MPM
a2dismod mpm_event 2>/dev/null
a2dismod mpm_worker 2>/dev/null
a2enmod mpm_prefork
a2enmod php8.2
# Restart
systemctl restart apache2
# Verify all correct modules loaded
apache2ctl -M | grep -E '(mpm|php)'
# Expected output includes:
# php8.2_module (shared)
# mpm_prefork_module (static)The 2>/dev/null on a2dismod suppresses ‘module not enabled’ errors if the MPM was already disabled. This makes the sequence safe to run idempotently. After the restart, both lines in the apache2ctl -M output must be present.
Confirm PHP SAPI is apache2handler via web request
echo '<?php phpinfo(); ?>' > /tmp/phpinfo.php
cp /tmp/phpinfo.php /var/www/html/phpinfo_tmp.php
curl -s http://localhost/phpinfo_tmp.php | grep 'Server API'
# Expected: Server API => Apache 2.0 Handler
rm /var/www/html/phpinfo_tmp.phpcurl checks the actual SAPI for web requests — which is different from the CLI SAPI returned by php -r 'echo php_sapi_name()'. Both should match (apache2handler / CLI) but the web check is the authoritative one for Apache configuration.
Check which MPM is active
apachectl -M | grep mpm
# Should show: mpm_prefork_module (static)
# Alternative:
apachectl -V | grep MPM
# Shows: Server MPM: preforkIf the output shows mpm_event_module, the MPM switch did not take effect. Run the a2dismod/a2enmod sequence again and do a full restart. Note that graceful reload does not change the MPM — only a full restart does.
Troubleshooting Common Issues
Problem: Apache fails to start with 'AH00526: Syntax error' or 'Cannot load modules/mod_php8.2.so'
Solution: Check that the PHP module file exists: ls /usr/lib/apache2/modules/ | grep php. If the file is missing, the libapache2-mod-php package was not installed correctly — run apt install --reinstall libapache2-mod-php8.2. Also run apachectl configtest for the exact error line.
Problem: PHP pages serve as raw text (browser shows PHP source code)
Solution: Apache is not passing .php files to the PHP handler. Verify the PHP module is loaded: apache2ctl -M | grep php. If loaded, check that the virtual host or .htaccess does not have a SetHandler application/x-httpd-php directive missing. Also check that /etc/apache2/mods-enabled/php8.2.conf exists and contains the AddType or SetHandler directives.
Problem: PHP CLI works but web requests return 500 errors after mod_php setup
Solution: Check Apache error log: tail -20 /var/log/apache2/error.log. Common cause: PHP is trying to load a module (like opcache) that conflicts with the Apache module load. Check php -m vs php -r 'print_r(get_loaded_extensions())' via web to compare loaded modules.
Summary
mod_php requires mpm_prefork — mpm_event and mpm_worker are incompatible with it. The installation sequence on Ubuntu: install libapache2-mod-php, disable mpm_event, enable mpm_prefork, enable the PHP module, perform a full restart, then verify with apache2ctl -M | grep php. Confirm the PHP SAPI is apache2handler via a phpinfo() page. On RHEL/Rocky, prefork is the default MPM so the module sequence is simpler. Once mod_php is confirmed, enable OPcache and verify the hit rate.
- Always run
a2dismod mpm_event && a2enmod mpm_preforkbefore enabling mod_php — installing libapache2-mod-php without switching MPM is the most common setup mistake. - After switching MPMs, use
systemctl restart apache2(not graceful) — MPM changes require a full process restart to take effect. - Verify setup with
apache2ctl -M | grep -E '(mpm|php)'— bothmpm_prefork_moduleandphp8.2_modulemust appear in the output.
Related Commands
Apache prefork MPM worker capacity formula • PHP OPcache configuration for Apache mod_php • Apache Handler vs PHP-FPM stability comparison • MySQL slow query diagnosis for PHP applications
Is Your Server Running at Full Performance?
INTRAM manages Linux servers with performance tuning built in from day one — correct MySQL configuration, PHP stack selection, nginx or Apache optimisation, and continuous monitoring so slowdowns are caught before users notice.
Explore Managed Hosting