How to Install and Use mod_php in Apache

How to install and use mod_php in Apache

PHP and Apache have a long history together, and mod_php is the classic way to get them talking to each other. I’ve used it on plenty of smaller sites and legacy applications over the years — it’s dead simple to set up compared to alternatives like PHP-FPM, even if it’s not always my first choice for high-traffic production environments anymore. In this post, I’ll walk through installing and configuring mod_php, and I’ll also be honest with you about when I’d reach for something else instead.

What Is mod_php

mod_php is an Apache module that embeds the PHP interpreter directly inside Apache’s worker processes. When a request comes in for a .php file, Apache hands it off internally to the embedded PHP interpreter, which executes the script and returns the output — all within the same process, no separate service required.

This is different from PHP-FPM (FastCGI Process Manager), which runs PHP as a completely separate process pool that Apache (or Nginx) communicates with over a socket or TCP connection. mod_php is simpler to set up, but it ties PHP execution to Apache’s process model, which has real implications for performance and memory usage that I’ll get into.

Prerequisites

  • Apache installed and running (with the prefork MPM — this matters, more below)
  • Root or sudo access
  • Basic familiarity with PHP and Apache virtual hosts

Important: mod_php Requires the Prefork MPM

This is the detail that trips people up most often. mod_php is not thread-safe, so it only works with Apache’s prefork Multi-Processing Module, which handles each request in a separate process rather than a thread. If your Apache is running worker or event MPM (common on fresh installs), you’ll need to switch.

Check your current MPM:

apachectl -V | grep -i mpm

Switch to prefork on Debian/Ubuntu:

sudo a2dismod mpm_event mpm_worker
sudo a2enmod mpm_prefork
sudo systemctl restart apache2

On CentOS/RHEL, edit /etc/httpd/conf.modules.d/00-mpm.conf and comment/uncomment the relevant LoadModule lines to select mpm_prefork_module.

Step 1: Install PHP and mod_php

Debian/Ubuntu

sudo apt update
sudo apt install php libapache2-mod-php

This automatically enables the module and restarts Apache appropriately, but I always double check:

apachectl -M | grep php

CentOS/RHEL

sudo dnf install php php-cli
sudo systemctl restart httpd

On RHEL-based systems, the Apache PHP module typically loads automatically once the package is installed — confirm with:

apachectl -M | grep php

Step 2: Verify PHP Is Working

Create a test file in your document root:

sudo nano /var/www/html/info.php
<?php
phpinfo();
?>

Visit http://your-server-ip/info.php in a browser. If you see the PHP info page, everything’s wired up correctly.

Important: Delete this file once you’ve confirmed it works. phpinfo() exposes a lot of server configuration detail that shouldn’t be publicly accessible.

sudo rm /var/www/html/info.php

Step 3: Configure PHP Settings

The main PHP config file is php.ini, typically located at:

  • Debian/Ubuntu: /etc/php/8.x/apache2/php.ini
  • CentOS/RHEL: /etc/php.ini

Common settings I adjust right away:

memory_limit = 256M
upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 60
display_errors = Off
log_errors = On
error_log = /var/log/php/error.log

In production, display_errors should always be Off — you don’t want PHP stack traces visible to visitors. Errors should go to a log file instead, where you can review them without exposing internal details.

After editing php.ini, restart Apache to apply changes:

sudo systemctl restart apache2   # Debian/Ubuntu
sudo systemctl restart httpd     # CentOS/RHEL

Step 4: Per-Directory PHP Configuration

Sometimes I need different PHP settings for a specific site or directory — for instance, a larger upload limit just for an admin upload tool. I do this in the virtual host or a .htaccess file:

<Directory /var/www/example.com/uploads>
    php_value upload_max_filesize 128M
    php_value post_max_size 128M
</Directory>

Note: php_value/php_admin_value directives only work with mod_php — this is actually one of its conveniences over PHP-FPM, where per-directory PHP settings require separate pool configs.

Installing PHP Extensions

Most applications (WordPress, Laravel, etc.) need specific PHP extensions. Common ones:

# Debian/Ubuntu
sudo apt install php-mysql php-curl php-gd php-mbstring php-xml php-zip

# CentOS/RHEL
sudo dnf install php-mysqlnd php-curl php-gd php-mbstring php-xml php-zip

Restart Apache after installing any new extension:

sudo systemctl restart apache2   # Debian/Ubuntu
sudo systemctl restart httpd     # CentOS/RHEL

mod_php vs PHP-FPM: My Honest Take

I want to be upfront about this since it affects real decisions:

mod_php pros:

  • Simpler setup, fewer moving parts
  • Per-directory config via .htaccess works natively
  • Good enough for small sites, internal tools, and low-traffic projects

mod_php cons:

  • Requires the prefork MPM, which is heavier on memory (each Apache process embeds a full PHP interpreter)
  • Can’t take advantage of event/worker MPM’s better concurrency handling
  • Doesn’t scale as well under high concurrent load compared to PHP-FPM

For anything with meaningful traffic, I switch to PHP-FPM with Apache’s event MPM and mod_proxy_fcgi. But for smaller sites, dev environments, or legacy applications that assume mod_php-style behavior, it’s still a perfectly reasonable choice, and I won’t pretend otherwise.

Switching PHP Versions with mod_php

Because mod_php binds a single PHP version directly into Apache, switching versions on Debian/Ubuntu (where multiple PHP versions can be installed side by side) requires disabling one module and enabling another:

sudo a2dismod php8.1
sudo a2enmod php8.3
sudo systemctl restart apache2

Check which version is now actually active:

php -v
apachectl -M | grep php

This works fine for a single site that needs to move to a newer PHP version, but if you’re hosting multiple sites that each need a different PHP version simultaneously, mod_php genuinely can’t do that — only one version can be loaded into Apache at a time. That’s the scenario where I stop reaching for mod_php entirely and set up PHP-FPM instead, running a separate pool per version, each proxied through mod_proxy_fcgi to the appropriate socket per virtual host.

Real-World Use Cases

  • Small business websites with light traffic where simplicity matters more than raw performance.
  • Legacy PHP applications that were built assuming mod_php‘s behavior (e.g., certain .htaccess-based PHP config overrides).
  • Local development environments where ease of setup outweighs performance concerns.
  • Shared hosting-style setups where per-directory PHP configuration via .htaccess is genuinely useful.

Troubleshooting Tips

  • PHP files downloading instead of executing: Usually means mod_php isn’t loaded — check apachectl -M | grep php.
  • 500 Internal Server Error after enabling PHP: Check the Apache error log first; it’s almost always a specific PHP error or a permissions issue.
  • “AH00534: Configuration error: mod_php… requires prefork MPM”: You’re running event or worker MPM — switch to prefork as shown above.
  • Changes to php.ini not taking effect: Confirm you edited the Apache-specific php.ini (not the CLI one), and restart (not just reload) Apache.

Common Mistakes to Avoid

  1. Leaving phpinfo() accessible publicly — remove test files immediately after checking them.
  2. Running event/worker MPM with mod_php enabled, which simply won’t work.
  3. Leaving display_errors On in production, exposing internal paths and logic to visitors.
  4. Forgetting to restart Apache after installing new PHP extensions.
  5. Assuming mod_php will scale like PHP-FPM under heavy load — it won’t, due to the process-per-request model tied to Apache’s prefork workers.

Security Best Practices

  • Always set display_errors = Off and log_errors = On in production.
  • Disable dangerous PHP functions you don’t need, via disable_functions in php.ini (e.g., exec, shell_exec, passthru if unused).
  • Keep PHP updated — old PHP versions accumulate known vulnerabilities quickly.
  • Set expose_php = Off in php.ini to avoid leaking your PHP version in response headers.
  • Restrict file upload sizes and types appropriately for your application.

Performance Optimization

  • Enable OPcache — it’s bundled with PHP and dramatically speeds up execution by caching compiled bytecode:
opcache.enable=1
opcache.memory_consumption=128
opcache.max_accelerated_files=10000
opcache.revalidate_freq=2
  • Tune prefork MPM settings (MaxRequestWorkers, StartServers) to match your server’s available memory, since every worker embeds a full PHP interpreter.
  • For anything beyond low-to-moderate traffic, seriously consider migrating to PHP-FPM for better resource efficiency.

Frequently Asked Questions

Q: Do I need mod_php or can I just install PHP separately? A: For Apache to execute PHP files directly, you need either mod_php or a FastCGI setup like PHP-FPM with mod_proxy_fcgi. PHP alone isn’t enough.

Q: Why does mod_php require the prefork MPM? A: Because mod_php isn’t thread-safe — it needs each request handled in its own process, which is exactly what prefork provides.

Q: Is mod_php deprecated? A: Not deprecated, but increasingly less recommended for production due to performance and scalability limitations compared to PHP-FPM.

Q: Can I run multiple PHP versions with mod_php? A: It’s difficult — mod_php binds one PHP version directly into Apache. Running multiple versions simultaneously is much easier with PHP-FPM, where you can run separate pools per version.

Q: How do I check which PHP version is running? A: Run php -v from the CLI, or check phpinfo() output temporarily (then remove it).

Summary and Key Takeaways

mod_php is a straightforward way to get PHP running under Apache, especially for smaller projects. Here’s what to remember:

  • It requires the prefork MPM — check and switch if needed.
  • Install via your package manager, verify with a temporary phpinfo() file, then remove it.
  • Configure php.ini sensibly for production (errors off, logging on, reasonable limits).
  • For higher-traffic sites, PHP-FPM is generally the better long-term choice.
  • Enable OPcache regardless of which approach you use — it’s an easy, significant performance win.

It’s a solid, simple option — just go in with clear eyes about its scaling limitations.

References

Total
1
Shares

Leave a Reply

Previous Post
How to use mod_alias for URL redirection in Apache

How to Use mod_alias for URL Redirection in Apache

Next Post
How to enable mod_ssl for SSL/TLS support in Apache

How to Enable mod_ssl for SSL/TLS Support in Apache

Related Posts