11

I am migrating my server to use mod_proxy_fcgi and php-fpm instead of mod_php. Apache is able to forward .php requests to the fcgi proxy and PHP executes correctly. I've got this working with:

ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/var/www/html/$1

Unfortunately, Apache forwards all .php requests to the proxy, even when the file doesn't exist. This causes a few problems. My ErrorDocument rule isn't invoked, and DirectoryIndex index.php index.html doesn't fall back to index.html.

I was able to fix these problems with mod_rewrite:

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

However, the Apache documentation does not recommend RewriteRule: "This is because this flag triggers the use of the default worker, which does not handle connection pooling."

Ideally, I think I'd either like to use ProxyPass in a FilesMatch block (currently unsupported), or define a new handler that proxies through fcgi and use it to handle .php requests, similar to what mod_php does.

Any suggestions for simulating a standard mod_php setup but actually proxying through fcgi?

6 Answers 6

8

One option is to install mod_proxy_handler: https://gist.github.com/progandy/6ed4eeea60f6277c3e39

Or you can wait for Apache 2.4.10, which should include the module.

Basically the module lets you do this:

#tcp
<FilesMatch \.php$>
SetHandler proxy:fcgi://localhost:9000
</FilesMatch>

#uds
<FilesMatch \.php$>
    SetHandler "proxy:unix:/path/to/socket.sock|fcgi://./"
</FilesMatch>
4
  • YAEEES! I lost an entire day to trial and error, what solved the issue for me was using the #tcp block above. Using ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/usr/local/var/www/$1 does not work with VirtualDocumentRoots, and the rewriting trick never worked for me.
    – mcdado
    Oct 20, 2017 at 22:14
  • 1
    Also, it's important to note that proxy:fcgi://localhost:9000 does not want the path after it. This was a big time misunderstanding for me.
    – mcdado
    Oct 20, 2017 at 22:15
  • FYI I wrote this up in a blog post: mcdado.com/post/166619749589/apache-and-php-fpm-via-homebrew
    – mcdado
    Oct 20, 2017 at 23:45
  • Make sure that php-fpm is listening using a socket instead of a TCP port as otherwise it won't work (displays the php code in the browser). The php-fpm listen config should look like listen = /var/run/php-fpm7.sock
    – 8ctopus
    Apr 19, 2020 at 9:01
2

Just for the record as a one liner:

AddHandler "proxy:unix:/path/to/socket.sock|fcgi://./" .php

You'll need a recent Apache 2.4 (RedHat back ported that to 2.4.6)

Oliver

1

I had same issue when file did not existed was showing "File not found." message , this fixed my issue and allowed me to setup a 404 page :

<VirtualHost *:80>

---------- content --------

DocumentRoot /home/user/public_html/domain.tld

#this disables php execution if you wish to show only html files
#ProxyPass /errors !

ProxyErrorOverride On
# /errors folder is located in public_html
ErrorDocument 404 /errors/404.php


</VirtualHost>
0

Ditto to the OP.

  • I also couldn't figure out how to get Apache VHOST config to route non-findable requests to a 404.
  • Similarly, I was also stymied by trying to figure out how to get extension-less URL's to map throuh ProxyPassMatch.
    • Sure... I could route everything through the php-fpm proxy, but that killed javascript and css files.

Theoretical Solution

My guess is that I'd have to write a custom 404.php processor -- and then route all requests through that appending the requested file(s) as a query string.

For example:

RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} !-s
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} !-l
RewriteRule ^.*$   fcgi://127.0.0.1:9000%{DOCUMENT_ROOT}/404.php?no_comprende=%{REQUEST_URI} [P]
...
ProxyPassMatch ^/(.*\.php(/.*)?)$    fcgi://127.0.0.1:9000%{DOCUMENT_ROOT}/$1
...

in theory -- and assuming that the order in which they are listed still applies as normal:

Any 404'd file would be caught before the ProxyPassMatch directive was reached

MY SOLUTION

  • php5-fpm (5.4.23)
  • Apache 2.4.2
  • Ubuntu 12.04 / 3.8.0-34 x86_64

To handle extension-less URLs with php-fpm I adapted the above to look for extension-less URL's as such in my VHOST config:

...
# Extensionless URL's
RewriteCond %{REQUEST_FILENAME} ^/((.*)(/.*)?)$
RewriteCond %{DOCUMENT_ROOT}/%2.php -f
RewriteRule !.*\.php$   fcgi://127.0.0.1:9000%{DOCUMENT_ROOT}/%1.php   [P]

# files w/ .php extensions
RewriteCond %{REQUEST_FILENAME} ^/((.*\.php)(/.*)?)$
RewriteCond %{DOCUMENT_ROOT}/%2 -f
RewriteRule . fcgi://127.0.0.1:9000%{DOCUMENT_ROOT}/%1 [P]
...

Not pretty, but it does get the job done :-(

0

I had precisely the same problem as ide and spent far longer trying to solve this than I had hoped. Since this is the only post or article I was able to find that helped me to adequately solve the issue, I wanted to add my solution to the mix.

My configuration:

  • Ubuntu 14.04
  • Apache 2.4.20
  • PHP-FPM 5.5.9-1ubuntu4.17 (fpm-fcgi) (built: May 19 2016 19:08:26)

I encountered a few additional challenges:

  1. My ErrorDocument handler is a PHP file.
  2. I have a bunch of RedirectPermanent directives in my document root's .htaccess file. These were not being honored because the requests were proxied to PHP-FPM before the redirect rules were evaluated.
  3. FilesMatch was insufficient for me because I use URL rewriting in similar ways to Wordpress. E.g. /mydir/mypath.html points to /mydir/script.php. I couldn't get it to match the rewritten URLs, though perhaps I overlooked somethig?
  4. I was able to get misterich's approach to work, but after reading Apache's performance warning, I decided to dig in further.

My solution is basically this:

  1. Intercept and redirect requests for non-existent directories and files and rewrite them to the error handler PHP file.
  2. Use another rewrite rule to route my rewritten error request to PHP-FPM.
  3. Route all other requests to PHP-FPM using ProxyPassMatch.

To solve the 301 redirects (#2), I'll simply leverage the error handler to issue redirects.

RewriteEngine On

RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteRule ^.*\.php$ /error.php?error=404&requestUri=$1

RewriteCond %{REQUEST_FILENAME} ^/(error.php)$
RewriteCond %{DOCUMENT_ROOT}/%1 -f
RewriteRule . fcgi://127.0.0.1:9000%{DOCUMENT_ROOT}/%1   [P]

# PHP-FPM
ProxyPassMatch ^/(.*\.php(/.*)?)$ "fcgi://127.0.0.1:9000/var/www/mysite.com"
0

I had the same issue that when there is no index.php apache does not fall back to index.html when using ProxyPassMatch.

What I did instead is I used (apache 2.4):

<FilesMatch "\.php$">
  SetHandler "proxy:unix:/usr/local/php73/var/run/mpelov-php-fpm.sock|fcgi://localhost/"
</FilesMatch>

I'm not sure if that'll work on apache 2.2 though.

The problem with that is that you cannot tell the path to the file. So http://example.com/file.php will be mapped to /file.php which is normally fine, but if php-fpm uses chroot it goes a bit complicated because for php the file is /file.php and if you have http://example.com/file.html then apache handles the request and the path is //file.html

So you can't use filematch with fpm+chroot.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.