Apache mod_fcgid and PHP on Windows

I’ve run PHP on Windows in every way imaginable. I’ve run it through IIS and Apache. I’ve run it as SAPI, CGI, FastCGI. Heck, I’ve run it from the command line to automate tasks (during my pre-Python days). But I hadn’t tried mod_fcgid until recently. Setting it up isn’t terribly straight forward and most of the online tutorials I found were for various flavor of Linux, so I thought I’d go over how to do it here.

Everybody that has worked with PHP for a while knows that using it inline with your web server will, at random points, eat your web server. This has been true across PHP versions forever. There are always legends of people that have just the right release with just the right libraries and just the right modules loaded that it just works and if you’re one of those people (a) I hate you and (b) for pete’s sake DON’T TOUCH ANYTHING. From my personal experience, trying to pinpoint and fix the problem will turn your life into a furious ball of nothing.

Dilbert.com

So most people end up with a CGI or FastCGI solution.

mod_fcgid is a FastCGI solution, that being basically CGI with the ability to persist a process or processes and manage them from the server. That gives you the performance benefits of ISAPI (or pretty close) with the process isolation of CGI. mod_fcgid is binary compatible with FastCGI, but offers improved control over process spawning. It also runs well on multi-threaded Apache and lets you fairly easily run different PHP versions and configurations on the same Apache instance. Plus, running PHP under Apache with mod_fastcgi has proven problematic in practice.

Assuming you already have Apache 2.x up and running, we’re going to grab a couple of things. First, you’ll want to grab the Non Thread Safe release of PHP. This will massively increase performance of PHP, as the PHP process doesn’t have twiddle its thumbs waiting on thread synchronization. The next thing you’ll need to grab is mod_fcgid, which you’ll dump into your Apache modules folder. We’ll assume you dumped the PHP folder at C:\php, so change your paths appropriately.

Next, you’ll need to load the mod_fcgid module in your Apache httpd.conf file.

LoadModule fcgid_module modules/mod_fcgid.so

Now for the hard bit - configuring mod_fcgid. There are all kinds of mod_fcgid settings you can read about on the doc site, but these should cover most of your needs.

<IfModule mod_fcgid.c>
AddHandler fcgid-script .fcgi .php
# Where to look for the php.ini file?
FcgidInitialEnv PHPRC        "c:/php"
# Set PHP_FCGI_MAX_REQUESTS to greater than or equal to FcgidMaxRequestsPerProcess
# to prevent php-cgi process from exiting before all requests completed
FcgidInitialEnv PHP_FCGI_MAX_REQUESTS      1000
# Maximum requests a process should handle before it is terminated
FcgidMaxRequestsPerProcess       1000
# Maximum number of PHP processes
FcgidMaxProcesses             15
# Number of seconds of idle time before a php-cgi process is terminated
FcgidIOTimeout             120
FcgidIdleTimeout                120
#Path to php-cgi
FcgidWrapper "c:/php/php-cgi.exe" .php
# Define the MIME-Type for ".php" files
AddType application/x-httpd-php .php
</IfModule>

Note the two hard paths to PHP - change those as needed. Last, we’ll need to tell Apache to include ExecCGI in its options for a particular directory. Supposing your document root is C:\www, you’d have something like this:

<Directory "C:/www">
Options Indexes FollowSymLinks ExecCGI
Order allow,deny
Allow from all
AllowOverride All
</Directory>

Now php files in your document root and subsequent directories will be served by mod_fcgid. Restart Apache, make a test php file (<?php phpinfo(); ?>), and give it a whirl. You should see a php-cgi.exe process started that mod_fcgid is managing.

It’s tricky to set up the first time, but mod_fcgid is the best way to run PHP on Apache I’ve found.