Apache 2.4: ProxyPass (For PHP) Taking Precedence Over Files/FilesMatch In Htaccess

Mattias Geniar, Sunday, August 2, 2015

I got to scratch my head on this one for a while. If you're writing a PHP-FPM config for Apache 2.4, don't use the ProxyPassMatch directive to pass PHP requests to your FPM daemon.

This will cause you headaches:

# don't
<IfModule mod_proxy.c>
  ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/
</IfModule>

You will much rather want to use a FilesMatch block and refer those requests to a SetHandler that passes everything to PHP.

# do this instead
# Use SetHandler on Apache 2.4 to pass requests to PHP-PFM
<FilesMatch \.php$>
  SetHandler "proxy:fcgi://127.0.0.1:9000"
</FilesMatch>

Why is this? Because the ProxyPassMatch directives are evaluated first, before the FilesMatch configuration is being run.

That means if you use ProxyPassMatch, you can't deny/allow access to PHP files and can't manipulate your PHP requests in any way anymore.

So for passing PHP requests to an FPM daemon, you'd want to use FilesMatch + SetHandler, not ProxyPassMatch.



Hi! My name is Mattias Geniar. I'm a Support Manager at Nucleus Hosting in Belgium, a general web geek, public speaker and podcaster. Currently working on DNS Spy. Follow me on Twitter as @mattiasgeniar.

I respect your privacy and you won't get spam. Ever.
Just a weekly newsletter about Linux and open source.

SysCast podcast

In the SysCast podcast I talk about Linux & open source projects, interview sysadmins or developers and discuss web-related technologies. A show by and for geeks!

cron.weekly newsletter

A weekly newsletter - delivered every Sunday - for Linux sysadmins and open source users. It helps keeps you informed about open source projects, Linux guides & tutorials and the latest news.

Share this post

Did you like this post? Will you help me share it on social media? Thanks!

Comments

Fre Friday, August 7, 2015 at 20:58 (permalink)

Interesting.

However, this is causing huge problems on my system. After some time, I get this in php-fpm log:
WARNING: [pool www] server reached pm.max_children setting (25), consider raising it

This never occurred when using ProxyPassMatch instead, and now only started happening when I changed my system to use SetHandler.

I also tried adding

but it’s not helping either.

Reply


    Mattias Geniar Friday, August 7, 2015 at 22:06 (permalink)

    That’s probably unrelated, entirely. Are you sure there aren’t any “hanging” processes? Something in your code/CMS that changed, that can cause longer timeouts?

    Reply


      Fre Saturday, August 8, 2015 at 23:00 (permalink)

      No, it’s definitely caused by this change. I monitor my server with Icinga, and so I know that everything was working perfectly before this change, and about 2 hours after this change, I got this error for the first time, and about 3 more times during the next 24 hours. I reverted to ProxyPassMatch, and since then this did not happen a single time. No other change was made to the server in that period.

      My server is running different virtualhosts, and I’m also using Alias a lot. So for every virtualhost and for every Alias, I am using a ProxyPassMatch line. I replaced every single ProxyPassMatch line, by a FilesMatch block defining the SetHandler inside a Directory block.

      On https://httpd.apache.org/docs/2.4/mod/mod_proxy_fcgi.html they recommend to explicity declare a worker with enablereuse=on max=10 options, but this did not seem to help. On http://rustyroy.blogspot.be/2015/07/php-as-fastcgi-connection-timing-out.html, the same problem is discussed, and there the solution was to remove these options. But as that was the original configuration (like in your blog post here), this does not seem to be the solution for me.

      I am wondering whether with ProxyPassMatch, maybe it always uses the same worker, while it creates separate workers for every SetHandler instance (of which I have many), and hence exceeding the maximum number of connections to php-fpm (cfr “worker sharing” on https://httpd.apache.org/docs/2.4/mod/mod_proxy.html)?

      Reply


        Mattias Geniar Sunday, August 9, 2015 at 08:32 (permalink)

        I am wondering whether with ProxyPassMatch, maybe it always uses the same worker, while it creates separate workers for every SetHandler instance (of which I have many), and hence exceeding the maximum number of connections to php-fpm?

        Both should work the same: every request that’s passed to PHP-FPM will go to the PHP-FPM master, he’ll decide which worker should be used. Apache cannot influence which worker gets the request, because it’s just sent to a single socket/port, where the FPM master handles everything.

        As for the SetHandler config: is your regex perhaps handling more requests now? Maybe you’re sending more requests to PHP-FPM than you were with the ProxyPassMatch config?

        A FilesMatch behaves differently than ProxyPassMatch, you may be accidentally sending more hits to your backend. Can you figure out what the FPM processes are doing with strace?

        Reply


    Martin Balint Tuesday, November 24, 2015 at 01:51 (permalink)

    I used to have same issue and resolved it with
    pm = ondemand
    pm.max_children = 10

    Reply


Leho Kraav @lkraav Saturday, August 8, 2015 at 16:28 (permalink)

Dude, you nailed it. I followed the Gentoo guide on http://z-issue.com/wp/apache-2-4-the-event-mpm-php-via-mod_proxy_fcgi-and-php-fpm-with-vhosts/ and he recommended the same thing. But https://wiki.apache.org/httpd/PHP-FPM recommends the seemingly simpler ProxyPassMatch, so I tried that first.

Using ProxyPassMatch meant that Alias wouldn’t work, RewriteRules were ignored etc etc. Well… now I know.

Reply


    Mattias Geniar Saturday, August 8, 2015 at 20:29 (permalink)

    But https://wiki.apache.org/httpd/PHP-FPM recommends the seemingly simpler ProxyPassMatch, so I tried that first.

    Because it seemed simpler, I went for the ProxyPassMatch first as well. Spent the next couple of hours debugging like a mad man why it wouldn’t work properly.

    What looks simple can end up costing you a lot of time. :-)

    Reply


ROlf Tuesday, August 25, 2015 at 05:06 (permalink)

Thanks Mattias.

I have the same problem of course, but I am using Apache V2.4.7 (Ubuntu 14.10 LTS).
The SetHandler solution requires Apache V2.4.10 http://httpd.apache.org/docs/2.4/mod/mod_proxy.html#handler

What Apache version are you using?


Rolf.

Reply


    Mattias Geniar Tuesday, August 25, 2015 at 12:43 (permalink)

    Ah, that’s a tricky part of the configuration: sockets are only allowed as of version 2.4.10, but TCP/IP ports are always allowed.

    If you had a php-fpm config that relied on sockets, that won’t work. Modify your PHP-FPM listen ports first:

    listen = 127.0.0.1:9001

    And let apache connect to the TCP/IP port, not the socket:

    SetHandler "proxy:fcgi://127.0.0.1:9001"

    For socket support, you’ll need Apache 2.4.10 or higher, which isn’t in the default repositories for Ubuntu or CentOS, unfortunately.

    Reply


      ROlf Tuesday, August 25, 2015 at 13:06 (permalink)

      Ok, I’m already using the PHP5-FPM TCP/IP (FastCGI) setup; I will try to implement it today using SetHandler.

      #OLD:

      ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/var/apache-www-17401/$1 retry=10
      

      #NEW

      SetHandler "proxy:fcgi://127.0.0.1:9000/"
      

      Reply


ROlf Tuesday, August 25, 2015 at 19:22 (permalink)

I have not implemented the change because moving the access rules and anti-hacking rules from Apache to Varnish VCL was easier and had less impact on the current Apache configs.

Reply


Daryl Monday, August 31, 2015 at 00:19 (permalink)

I’m using Apache 2.4.10 with PHP-FPM and mod_proxy_fcgi. Although I can successfully use ProxyPassMatch for all php files under my web root (including /phpmyadmin) using this:

ProxyPassMatch ^/(.*\.php(/.*)?)$ unix:/var/run/php5-fpm.sock|fcgi://127.0.0.1:9000/website/public

I found that I would consistently get this error in my Apache log:

[proxy_fcgi:error] AH01071: Got error 'Primary script unknown\n'

The only way to stop it was to use this instead:

SetHandler "proxy:unix:/var/run/php5-fpm.sock|fcgi://localhost/"

The only problem now is that the FilesMatch/SetHandler directives don’t work for my /phpmyadmin install. I have created a soft-link to phpmyadmin in my webroot, but that doesn’t seem to work now as only raw code is rendered on the page. Any ideas about this Mattias?

Reply


    Mattias Geniar Monday, August 31, 2015 at 16:28 (permalink)

    What other FilesMatch configurations did you have for phpMyAdmin? The above, as you described it, should work just fine as it routes all .PHP files to the proxy FastCGI setup.

      <FilesMatch \.php$>
        SetHandler "proxy:fcgi://127.0.0.1:9000"
      </FilesMatch>
    

    Reply


      Daryl Tuesday, September 1, 2015 at 23:59 (permalink)

      Hello Mattias.
      I ended up having to include a separate directive within my virtualhost for phpmyadmin:

      SetHandler “proxy:unix:/var/run/php5-fpm.sock|fcgi://localhost/”

      This could have also been achieved by editing /etc/apache2/conf-available/phpmyadmin.conf.

      Reply


Alfred Ayache Monday, July 4, 2016 at 19:54 (permalink)

Hi Mattias:

Wondering if there’s any way to use PHP-FPM and override some of the php.ini directives in .htaccess using php_value.

Specifically I’m thinking of:

upload_max_filesize
post_max_size
max_execution_time
max_input_time

Thanks.

Reply


askapache Friday, August 19, 2016 at 18:11 (permalink)

This was exacly what happened to me. I banged my keyboard against this for a good solid couple days, reading through the apache source code for proxy and fpm modules. Finally I found out you can use SetHandler and that solved all of my problems. Thanks for posting

Reply


crstin Friday, December 16, 2016 at 15:06 (permalink)

Thank you so much! That solved a lot of my php problems.

Reply


Leave a Reply

Your email address will not be published. Required fields are marked *