Apache 2.4 + PHP-FPM + ProxyPassMatch

Solution 1:

After hours of searching and reading Apache documentation I've come up with a solution that allows to use the pool, and also allow the Rewrite directive in .htaccess to work even when the url contains .php files.

<VirtualHost ...>

 ...

 # This is to forward all PHP to php-fpm.
 <FilesMatch \.php$>
   SetHandler "proxy:unix:/path/to/socket.sock|fcgi://unique-domain-name-string/"
 </FilesMatch>

 # Set some proxy properties (the string "unique-domain-name-string" should match
 # the one set in the FilesMatch directive.
 <Proxy fcgi://unique-domain-name-string>
   ProxySet connectiontimeout=5 timeout=240
 </Proxy>

 # If the php file doesn't exist, disable the proxy handler.
 # This will allow .htaccess rewrite rules to work and 
 # the client will see the default 404 page of Apache
 RewriteCond %{REQUEST_FILENAME} \.php$
 RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} !-f
 RewriteRule (.*) - [H=text/html]

</VirtualHost>

As per Apache documentation, the SetHandler proxy parameter requires Apache HTTP Server 2.4.10.

I hope that this solution will help you too.

Solution 2:

I ran into this problem yesterday as well – Apache 2.4 moved out of Debian/experimental into Debian/unstable forcing me to deal with this new stuff; not on our production servers of course ;).

After reading what feels like millions of sites, Apache docs, bug reports and debugging output in the error log I finally got it to work. No, there's no support for FPM with sockets, yet. The default Debian config has been using sockets for some time now, so Debian users will have to change that too.

Here's what works for a CakePHP site and PHPMyAdmin (the latter needs some config if you're using the Debian packages though), so I can confirm that mod_rewrite still works as expected to do fancy URL rewriting.

Notice DirectoryIndex index.php, which might be the reason none of your configs worked for "folders" (at least that's what didn't work here).

I still get File not found. for directories, but only if there's no index file it can parse. Would love to get rid of that too, but it's not that critical as for now.


<VirtualHost *:80>
    ServerName site.localhost

    DocumentRoot /your/site/webroot
    <Directory />
            Options FollowSymlinks
            DirectoryIndex index.php
            AllowOverride All
            Require all granted
    </Directory>

    <LocationMatch "^(.*\.php)$">
            ProxyPass fcgi://127.0.0.1:9000/your/site/webroot
    </LocationMatch>

    LogLevel debug
    ErrorLog /your/site/logs/error.log
    CustomLog /your/site/logs/access.log combined
</VirtualHost>

The above vhost works perfectly well with an .htaccess in the root like this:

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(.*)$ index.php [QSA,L]
</IfModule>

I don't quite get what you mean by URL rewriting inside a subdirectory though (I'm only rewriting to the root's index.php).


(Oh, and you'll have to make sure Xdebug doesn't conflict with FPM on your system, out of the box they want to use the same ports.)


Solution 3:

All you need to do is to set:

 ProxyErrorOverride on

And do not forget to set the customer page by:

ErrorDocument 404 /path/to/error_page_file    

Solution 4:

This is what I've got. It seems to work OK. I put Drupal in a subdirectory and its rewrites work, directory indexes work, and PATH_INFO works.

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} ^/((.*\.php)(/.*)?)$
RewriteCond %2 -f
RewriteRule . fcgi://127.0.0.1:9000/%1 [L,P]
RewriteOptions Inherit

I've tried to do something like this without rewrites ("If" and such), but I couldn't get anything to work.

EDIT: Note that if you were to implement this as a shared hosting provider, this could be a security issue. It would allow users to pass PHP scripts to an arbitrary fcgi proxy. If you had a seperate pool for every user, that would allow for elevation of privilege attacks.


Solution 5:

Yet another solution (requires Apache >= 2.4.10) - Inside the vhost:

# define worker
<Proxy "unix:/var/run/php5-fpm-wp.bbox.nuxwin.com.sock|fcgi://domain.tld" retry=0>
    ProxySet connectiontimeout=5 timeout=7200
</Proxy>

<If "%{REQUEST_FILENAME} =~ /\.php$/ && -f %{REQUEST_FILENAME}">
    SetEnvIfNoCase ^Authorization$ "(.+)" HTTP_AUTHORIZATION=$1
    SetHandler proxy:fcgi://domain.tld
</If>

So here, the fcgi handler for PHP will be set only if the file exists and if its name matches with PHP file extension.

BTW: For those which would have idea to set the ProxyErrorOverride to On, be aware that this is really a bad idea. Usage of this directive is not without causing any issue. For instance, any PHP application sending HTTP code such as 503 would lead to unexpected result. Default error handler would be involved in any cases and for PHP applications that provide API, that is really a bad behavior.