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?

ide
  • 211
  • 2
  • 5

6 Answers6

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>
dmuir
  • 311
  • 4
  • 5
  • 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 `VirtualDocumentRoot`s, and the rewriting trick never worked for me. – mcdado Oct 20 '17 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 '17 at 22:15
  • FYI I wrote this up in a blog post: http://mcdado.com/post/166619749589/apache-and-php-fpm-via-homebrew – mcdado Oct 20 '17 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 '20 at 09: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

Oliver
  • 21
  • 2
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>
Alin Razvan
  • 111
  • 1
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 :-(

misterich
  • 41
  • 5
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.

NickSoft
  • 248
  • 6
  • 22