Configure Apache to run PHP with Minimal Memory Bloat

Apache Web Server is great! It’s a time-test proven web server with tons of extension. It’s free and open source, runs on all major operation systems, and has a great developer and user community. But if you have ever tired running Apache and PHP on a Linux server with limited memory (RAM

The Problem: In short, Apache’s child processes are eating all the RAM on your tiny server. Apache 2 comes installed by default with the Prefork Multi-Process Module (MPM). Under this operating model, each HTTP request is handled by a single Apache process one at a time. This is a completely single-threaded model. For throughput reasons, Apache forks off multiple child processes that hang out waiting for incoming requests.

Solution: switch to Apache’s Worker MPM. The Worker MPM is a hybrid model that can use multiple threads per process. The memory cost of creating a new thread is a lot less than creating a new process, so, in theory, Worker MPM can achieve the same throughput as Prefork, but use much less memory. The downside is that the worker threads share the same process space, which depending on the code being run, may introduce all sorts of nasty problems like access violations or deadlocks.

PHP is not thread-safe! Even though PHP clames to be thread safe since 5.2, it seems this is still not the case. As a result, switching to the Worker MPM may cause strange crashes and/or unpredictable deadlocks. The recommended solution is to use FastCGI as the interface between Apache and PHP. FastCGI will create its own single-thread process for PHP to run in.

There are lots of posts that describe how to configure Apache + Worker + PHP, but I found this one to be the best. Some of the following is taken directly from Steven’s Blog:

install:

sudo apt-get install apache2-mpm-worker libapache2-mod_fcgi php5-cgi

create php-wraper script: /usr/local/bin/php-wrapper

#!/bin/sh # Set desired PHPFCGI* environment variables. # Example: # PHP FastCGI processes exit after 500 requests by default. PHPFCGIMAXREQUESTS=1000 export PHPFCGIMAXREQUESTS # DO NOT SET PHPFCGICHILDREN! # Replace with the path to your FastCGI-enabled PHP executable exec /usr/bin/php-cgi

create FastCGI configuration: /etc/apache2/conf.d/php-fcgid.conf

FcgidInitialEnv PHPRC=/etc/php5/cgi FcgidInitialEnv PHPFCGIMAX_REQUESTS 1000 # FcgidMaxRequestsPerProcess should be AddHandler fcgid-script .php Options +ExecCGI FcgidWrapper /usr/local/bin/php-wrapper .php # Customize the next two directives for your requirements. Order allow,deny Allow from all

This configuration will fork off a max of 3 php processes. Also, you can tweek the Apache worker settings in /etc/apache2/apache2.conf in the section. The ServerLimit variable controls the max number of child Apache processes to fork. Have fun.

P.S. Here is a good blog post discussing why it is best to let mod-fcgi manage the PHP child processes, and not PHP itself. In short, you don’t need two child process managers, and mod-fcgi does a great job.

Paul Soucy

Read more posts by this author.