Setting up PHP with FastCGI on Windows using Apache

I've recently been updating a few Windows machines to PHP 8.2, and decided that as I was doing the update I'd move from mod_php to using FastCGI instead.

I've recently been updating a few Windows machines to PHP 8.2, and decided that as I was doing the update I'd move from mod_php to using FastCGI instead.

On a Linux server I would tend to use PHP-FPM, which unfortunately isn't available for Windows. Instead, I ended up opting for mod_fcgid.

The Apache Haus distribution doesn't ship with mod_fcgid included by default though, and you have to install it as an extra step which I thought was worth documenting for future reference.

Install PHP

I use Chocolatey to manage packages, so installing PHP is as easy as:

choco install php

The manual installation process is pretty simple too though:

  • Download the current either x86 or x64 (depending on your OS) "Non Thread Safe" distribution from PHP for Windows.
  • Extract the downloaded ZIP to somewhere on your filesystem. Chocolatey installs to C:\tools\php82 by default, and the rest of this post will assume the same path.
  • Add C:\tools\php82 as an entry in your PATH environment variable.

Copy the php.ini-development or php.ini-production file to php.ini and make any required changes.

Check that PHP is working by checking its version:

php -v

You should expect some output such as:

PHP 8.2.0 (cli) (built: Dec  6 2022 15:25:41) (NTS Visual C++ 2019 x64)
Copyright (c) The PHP Group
Zend Engine v4.2.0, Copyright (c) Zend Technologies

Install Apache

Again, using Chocolatey this step is easy:

choco install apache-httpd --params '/port:80 /installLocation:C:\Apache24'

This will install Apache as a service and will install to the directory C:\Apache24.

Manual installation is similarly easy:

  • Download the current Apache release from Apache Haus, making sure that if you chose an x64 version of PHP that you also choose an x64 version of Apache.
  • Extract the downloaded folder to C:\Apache24.
  • Add C:\Apache24\Apache24\bin as an entry in your PATH environment variable.

Run the following command to install Apache as a service:

C:\Apache24\Apache24\bin\httpd.exe -k install -n Apache

Make any required changes to C:\Apache24\Apache24\conf\httpd.conf to configure the server, such as setting the document root, enabling modules, etc.

Check the syntax of the server configuration file:

httpd -t

You should expect some output such as:

Syntax OK

Install mod_fcgid

We have to install mod_fcgid manually, as it is not included when installed either through Chocolatey or manually.

  • Head to the Apache Haus downloads page.
  • Scroll down to the heading "Modules for Apache 2.4.x VS17" (assuming you installed the version of Apache compiled with VS17).
  • Download the "Mod FCGID ... for Apache 2.4.x" module, making sure that if you chose an x64 version of Apache that you also choose an x64 version of mod_fcgid.
  • Open the downloaded ZIP file, which should contain the following items (and several others that we're not interested in):
    • conf
    • mod_fcgid.so
  • Copy these items as follows within C:\Apache24\Apache24:
    • Copy the content of conf into conf
    • Copy mod_fcgid.so to modules\mod_fcgid.so

Now that we have the module installed, we need to load and configure it:

  • Open conf\httpd.conf in a text editor.
  • Open conf\extra\httpd-fcid.conf in a text editor.
  • Restart the Apache service.

Replace the content of the file with the following:

<IfModule fcgid_module>
	FcgidInitialEnv PHPRC "C:\\tools\\php82"
	FcgidInitialEnv PATH "C:\\tools\\php82;C:\\WINDOWS\\system32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem;"
	FcgidInitialEnv SystemRoot "C:\\Windows"
	FcgidInitialEnv SystemDrive "C:"
	FcgidInitialEnv TEMP "C:\\WINDOWS\\TEMP"
	FcgidInitialEnv TMP "C:\\WINDOWS\\TEMP"
	FcgidInitialEnv windir "C:\\WINDOWS"

	FcgidIOTimeout 40
	FcgidConnectTimeout 10
	FcgidMaxProcesses 8
	FcgidOutputBufferSize 64
	ProcessLifeTime 240
	FcgidMaxRequestsPerProcess 0
	FcgidInitialEnv PHP_FCGI_MAX_REQUESTS 0
	FcgidInitialEnv PHP_FCGI_CHILDREN 0
	FcgidProcessLifeTime 3600
	FcgidMinProcessesPerClass 0

	<Files ~ "\.php$">
		Options ExecCGI SymLinksIfOwnerMatch
		AddHandler fcgid-script .php
		FcgidWrapper "C:/tools/php82/php-cgi.exe" .php
	</Files>
</IfModule>

Add or uncomment the following to the end of the file (or put it next to the other Include directives):

LoadModule fcgid_module modules/mod_fcgid.so
Include conf/extra/httpd-fcgid.conf

Closing Thoughts

Immediately after switching to mod_fcgid, there was a perceivable performance improvement. This is most likely due to mod_php requiring a thread safe version of PHP which will include locks.

The actual upgrade to PHP 8.2 from 8.1 itself also went pretty smoothly, with no breakage to existing code - which is always nice!