In short: mod_php is PHP as a module in the Apache web server. Every Apache process then contains a complete PHP interpreter and executes PHP code itself; the SAPI is called apache2handler. It is easy to set up but ties PHP to Apache, usually requires the prefork MPM and allows hardly any separation between websites. The PHP manual advises against it for new installations, and with PHP2Shell the PHP team rates the risk highest for mod_php.
What is mod_php?
With mod_php, Apache loads PHP as its own module into its processes. There is no separate PHP service: when Apache is to serve a .php file, the same process that accepted the request also executes the PHP code. For many years this was the standard way to run PHP, and it is still common on older servers and in some Docker images today.
According to the PHP manual, PHP as a server module reads its configuration only once, when the web server starts. Changes to php.ini and updates of the module therefore take effect only after a restart of Apache.
Important for understanding: Apache processes live for a long time. A process accepts many connections one after another before it is replaced; how many is governed by the Apache directive MaxConnectionsPerChild. The embedded PHP interpreter stays the same during this time. Replacing the libphp library on disk changes nothing about the running processes.
For management and project leads this can be summarised as follows: with mod_php, web server and PHP are one unit. Touching one affects the other. A PHP update means a restart of the web server, a flaw in PHP runs with the web server's privileges, and separation between several websites on the same server is hardly possible.
How is mod_php integrated?
The PHP manual shows the integration in two steps: load the module and define which files PHP is to process.
LoadModule php_module modules/libphp.so
<FilesMatch \.php$>
SetHandler application/x-httpd-php
</FilesMatch>
The manual recommends FilesMatch with SetHandler rather than just AddType, so that uploaded files such as bild.php.jpg are not executed as PHP. On Debian and Ubuntu, packages such as libapache2-mod-php8.3 and the commands a2enmod and a2dismod take care of this.
Whether mod_php is active can be checked read-only:
apachectl -M 2>/dev/null | grep -i php # Debian/Ubuntu
httpd -M 2>/dev/null | grep -i php # RHEL family
apachectl -V | grep -i mpm # active MPM (prefork, worker, event)
Prefork, thread safety and resources
Apache distributes requests through a multi-processing module (MPM). According to the PHP manual, mod_php requires the prefork MPM unless PHP was built with Zend Thread Safety (--enable-zts). Most distribution packages are built without thread safety.
Prefork means: one process per simultaneous connection, and each process carries a complete PHP interpreter. Even requests for images or CSS files thus occupy a process with PHP in its baggage. This costs memory and limits the load a server can carry.
| Feature | mod_php | PHP-FPM |
|---|---|---|
| Where does PHP run? | in every Apache process | in its own service |
| Apache MPM | usually prefork |
event possible |
| User per website | no, everything as the Apache user | yes, per pool |
| Restarting PHP | only together with Apache | independent of Apache |
| Settings per directory | php_value in .htaccess |
pool or .user.ini |
For this reason the manual recommends PHP-FPM with mod_proxy_fcgi for all modern installations: better resource management, process separation, restarting PHP without restarting Apache, and compatibility with the event MPM, which has been the default since Apache 2.4. The basics are under PHP-FPM explained.
Settings with .htaccess, php_value and php_admin_value
With mod_php, PHP settings can be set directly in the Apache configuration. The manual distinguishes between change modes: entries marked INI_PERDIR may appear in php.ini, .htaccess or httpd.conf, entries marked INI_SYSTEM only in php.ini or httpd.conf.
# In the VirtualHost configuration: locked against the application
php_admin_flag display_errors off
php_admin_value upload_max_filesize 24M
# Possible in .htaccess, but can be overridden by the application
php_value max_execution_time 60
php_admin_value and php_admin_flag are allowed only in the server configuration, not in .htaccess. This very distinction is important for the interim measures for PHP2Shell, because values such as session.upload_progress.enabled must not be reset by the application.
mod_php and PHP2Shell: why the risk is highest
The PHP team rates the risk from PHP2Shell highest for mod_php: an exploit was demonstrated there before any application code runs at all. Security plugins or checks in the CMS therefore come too late. In addition, with mod_php, PHP runs with the privileges and in the memory of the web server. The detailed assessment is under Why mod_php carries the highest risk.
For operators this means:
- Update the PHP module to 8.5.12, 8.4.27, 8.3.36 or 8.2.35, or a confirmed backport.
- Restart Apache completely, not just reload it, and check the start time of the processes.
- Set interim values via
php_admin_valuein the server configuration if the update is not yet possible. - Then plan the move to PHP-FPM, as described under Securing Apache with mod_php.
How does PHP SOS help?
- Detect: We check on which servers mod_php is running, with which MPM and from which package source.
- Patch: We update the PHP module, restart Apache completely and document the state.
- Secure the interim period: Where the update is blocked, we set the php.net measures as locked values in the server configuration.
- Switch over: As part of server hardening we migrate to PHP-FPM with separate pools, tested beforehand.
Frequently asked questions
Why is it called mod_php when the module is named php_module?
mod_php is the colloquial name for PHP as an Apache module. In the configuration it is loaded with LoadModule; the PHP manual gives LoadModule php_module modules/libphp.so as an example. Older versions used names such as php7_module or php5_module.
Why does mod_php need the prefork MPM?
According to the PHP manual, mod_php requires the prefork MPM unless PHP was built with Zend Thread Safety. Most distribution packages are built without thread safety. Prefork starts a separate process for every simultaneous connection, which needs more memory.
Do php_value lines in .htaccess also work with PHP-FPM?
No. php_value and php_flag in .htaccess are Apache directives of the PHP module and only work with mod_php. Under PHP-FPM, such settings belong in the pool or, for permitted values, in a .user.ini.
Do I have to abandon mod_php immediately?
The PHP update with a complete restart of Apache comes first. Switching to PHP-FPM makes sense afterwards but should be planned and tested. It does not close PHP2Shell, because PHP-FPM is affected as well.