Configuring Apache with FastCGI PHP-FPM for a Slim Application

Configuring Apache

I used Apache 2.4, which had mod_proxy_fcgi. Older versions lacked that module. To enable it:

sudo a2enmod proxy_fcgi

The regular documentation for the module used the ProxyPassMatch directive to map PHP files to the FastCGI server, like this (from the docs):

ProxyPassMatch "^/(.*\.php(/.*)?)$" "unix:/var/run/php5-fpm.sock|fcgi://localhost/var/www/"

I made a rule that was like this:

ProxyPassMatch "^/legacy-sitemap/api(/.*)$" "unix:/var/run/php5-fpm.sock|fcgi://localhost/www/riceball.com/public/legacy-sitemap/api$1"

I messed with that (and other directives) for a couple of hours, not making much headway, but finally figured out that I had an .htaccess file with this rule, which was enabling my URLs to work:

# Cause Slim routes to work without a visible index.php
RewriteEngine On
RewriteRule ^(.+)$ index.php/$1 [L,END]

This tells Apache to take URLs like this:

http://example.com/path/to/api/rest/of/the/url/

And turn them into URLs like this:

http://example.com/path/to/api/index.php/rest/of/the/url/

This causes index.php to execute, with the PHP_SELF environment variable set to /rest/of/the/url/.

The Slim framework uses PHP_SELF to match the routes.

The problem was that PHP-FPM wasn’t reading the .htaccess file, so the URLs never got modified.

The following didn’t work – with comments explaining why:

# File not found - the url on the left is tacked onto the url on the right.
ProxyPass /legacy-sitemap/api "unix:/var/run/php/php7.2-fpm.sock|fcgi://localhost/www/riceball.com/public/"

# This didn't seem to honor the unix domain socket.  It's probably a bug.  I got this error:
# [Wed Apr 04 15:12:49.090746 2018] [proxy_fcgi:error] [pid 32725] [client 127.0.0.1:45434] AH01079: failed to make connection to backend: localhost
ProxyPassMatch ^/legacy-sitemap/api(.*)$ "unix:/var/run/php/php7.2-fpm.sock|fcgi://localhost/www/riceball.com/public/legacy-sitemap/api/index.php/$1"

However, this did work:

RewriteRule ^/legacy-sitemap/api(.*)$ "unix:/var/run/php/php7.2-fpm.sock|fcgi://localhost:9000/www/riceball.com/public/legacy-sitemap/api/index.php/$1"

But that still didn’t work within the frontend application. The problem was that the Authorization header wasn’t being forwarded to the FastCGI server.

The correction was to pass it as an environment variable.

RewriteRule ^/legacy-sitemap/api(.*)$ "unix:/var/run/php/php7.2-fpm.sock|fcgi://localhost:9000/www/riceball.com/public/legacy-sitemap/api/index.php/$1" [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},P]

Unix Domain Sockets

Starting with Apache 2.4.10, support was added for Unix domain sockets. These are sockets that are mounted in the file system. They are faster than TCP/IP sockets, because they don’t incur the overhead of networking. They also require a little less configuration, because there are no hosts or ports to configure. Instead, you need to manage the owner and group permissions, just like Unix files.

When using the socket at unix:/var/run/php/php7.20-fpm.sock, the fcgi:’s machine name and socket number are ignored.

Next up: Benchmarks.

Leave a Reply