3

I have a virtual host on Apache 2.4.25 with PHP-FPM 7.1.4 connected via mod_proxy_fcgi as follows:

<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /srv/www/example.com

    <Directory /srv/www/example.com>
        AllowOverride All
        Require all granted
    </Directory>

    SetEnvIfNoCase ^Authorization$ "(.+)" HTTP_AUTHORIZATION=$1
    <FilesMatch ".+\.ph(p[3457]?|t|tml)$">
        SetHandler "proxy:unix:/run/php/example.sock|fcgi://localhost"
    </FilesMatch>
</VirtualHost>

Most of the applications work flawlessly with this setup, but there is one application which uses PATH_INFO to to extract the request. The application has something like this in its .htaccess:

RewriteEngine On

RewriteCond $1 ^index\.php
RewriteRule ^(.*)$ - [PT,L]

RewriteRule ^(.*)$ index.php/$1 [PT,L]

Simply put, everything what's not index.php should be passed to it as a path. Visiting URL http://example.com/index.php/test works and shows [PATH_INFO] => /test as expected, but visiting http://example.com/test dies with

AH01071: Got error 'Primary script unknown\n'

Setting LogLevel trace6 for both mod_rewrite and mod_proxy_fcgi shows that the redirection is done properly and the proper paths are also passed to PHP-FPM.

Traces for /index.php/test:

[Sat Apr 29 09:40:41.156316 2017] [rewrite:trace3] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141400a0/initial] [perdir /srv/www/example.com/] add path info postfix: /srv/www/example.com/index.php -> /srv/www/example.com/index.php/test
[Sat Apr 29 09:40:41.156334 2017] [rewrite:trace3] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141400a0/initial] [perdir /srv/www/example.com/] strip per-dir prefix: /srv/www/example.com/index.php/test -> index.php/test
[Sat Apr 29 09:40:41.156348 2017] [rewrite:trace3] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141400a0/initial] [perdir /srv/www/example.com/] applying pattern '^(.*)$' to uri 'index.php/test'
[Sat Apr 29 09:40:41.156352 2017] [rewrite:trace4] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141400a0/initial] [perdir /srv/www/example.com/] RewriteCond: input='index.php/test' pattern='^index\\.php' => matched
[Sat Apr 29 09:40:41.156355 2017] [rewrite:trace2] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141400a0/initial] [perdir /srv/www/example.com/] forcing '/srv/www/example.com/index.php' to get passed through to next API URI-to-filename handler
[Sat Apr 29 09:40:41.156358 2017] [rewrite:trace1] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141400a0/initial] [perdir /srv/www/example.com/] initial URL equal rewritten URL: /srv/www/example.com/index.php [IGNORING REWRITE]
[Sat Apr 29 09:40:41.156368 2017] [proxy_fcgi:debug] [pid 3014:tid 140574363391744] mod_proxy_fcgi.c(913): [client xx.xx.xx.xx:32622] AH01076: url: fcgi://localhost/srv/www/example.com/index.php proxyname: (null) proxyport: 0
[Sat Apr 29 09:40:41.156371 2017] [proxy_fcgi:debug] [pid 3014:tid 140574363391744] mod_proxy_fcgi.c(920): [client xx.xx.xx.xx:32622] AH01078: serving URL fcgi://localhost/srv/www/example.com/index.php
[Sat Apr 29 09:40:41.156510 2017] [rewrite:trace3] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda1413e0a0/subreq] [perdir /srv/www/example.com/] strip per-dir prefix: /srv/www/example.com/test -> test
[Sat Apr 29 09:40:41.156519 2017] [rewrite:trace3] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda1413e0a0/subreq] [perdir /srv/www/example.com/] applying pattern '^(.*)$' to uri 'test'
[Sat Apr 29 09:40:41.156535 2017] [rewrite:trace4] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda1413e0a0/subreq] [perdir /srv/www/example.com/] RewriteCond: input='test' pattern='^index\\.php' => not-matched
[Sat Apr 29 09:40:41.156538 2017] [rewrite:trace3] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda1413e0a0/subreq] [perdir /srv/www/example.com/] strip per-dir prefix: /srv/www/example.com/test -> test
[Sat Apr 29 09:40:41.156541 2017] [rewrite:trace3] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda1413e0a0/subreq] [perdir /srv/www/example.com/] applying pattern '^(.*)$' to uri 'test'
[Sat Apr 29 09:40:41.156563 2017] [rewrite:trace2] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda1413e0a0/subreq] [perdir /srv/www/example.com/] rewrite 'test' -> 'index.php/test'
[Sat Apr 29 09:40:41.156567 2017] [rewrite:trace3] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda1413e0a0/subreq] [perdir /srv/www/example.com/] add per-dir prefix: index.php/test -> /srv/www/example.com/index.php/test
[Sat Apr 29 09:40:41.156571 2017] [rewrite:trace2] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda1413e0a0/subreq] [perdir /srv/www/example.com/] forcing '/srv/www/example.com/index.php/test' to get passed through to next API URI-to-filename handler
[Sat Apr 29 09:40:41.156575 2017] [rewrite:trace2] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda1413e0a0/subreq] [perdir /srv/www/example.com/] strip document_root prefix: /srv/www/example.com/index.php/test -> /index.php/test
[Sat Apr 29 09:40:41.156579 2017] [rewrite:trace1] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda1413e0a0/subreq] [perdir /srv/www/example.com/] internal redirect with /index.php/test [INTERNAL REDIRECT]
[Sat Apr 29 09:40:41.158640 2017] [proxy_fcgi:trace4] [pid 3014:tid 140574363391744] util_script.c(571): [client xx.xx.xx.xx:32622] Headers from script 'index.php':
[Sat Apr 29 09:40:41.158661 2017] [proxy_fcgi:trace4] [pid 3014:tid 140574363391744] util_script.c(572): [client xx.xx.xx.xx:32622]   Content-type: text/html; charset=UTF-8

Traces for /test:

[Sat Apr 29 09:45:01.600510 2017] [rewrite:trace3] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141b40a0/initial] [perdir /srv/www/example.com/] strip per-dir prefix: /srv/www/example.com/test -> test
[Sat Apr 29 09:45:01.600527 2017] [rewrite:trace3] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141b40a0/initial] [perdir /srv/www/example.com/] applying pattern '^(.*)$' to uri 'test'
[Sat Apr 29 09:45:01.600533 2017] [rewrite:trace4] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141b40a0/initial] [perdir /srv/www/example.com/] RewriteCond: input='test' pattern='^index\\.php' => not-matched
[Sat Apr 29 09:45:01.600535 2017] [rewrite:trace3] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141b40a0/initial] [perdir /srv/www/example.com/] strip per-dir prefix: /srv/www/example.com/test -> test
[Sat Apr 29 09:45:01.600537 2017] [rewrite:trace3] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141b40a0/initial] [perdir /srv/www/example.com/] applying pattern '^(.*)$' to uri 'test'
[Sat Apr 29 09:45:01.600540 2017] [rewrite:trace2] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141b40a0/initial] [perdir /srv/www/example.com/] rewrite 'test' -> 'index.php/test'
[Sat Apr 29 09:45:01.600550 2017] [rewrite:trace3] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141b40a0/initial] [perdir /srv/www/example.com/] add per-dir prefix: index.php/test -> /srv/www/example.com/index.php/test
[Sat Apr 29 09:45:01.600553 2017] [rewrite:trace2] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141b40a0/initial] [perdir /srv/www/example.com/] forcing '/srv/www/example.com/index.php/test' to get passed through to next API URI-to-filename handler
[Sat Apr 29 09:45:01.600556 2017] [rewrite:trace2] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141b40a0/initial] [perdir /srv/www/example.com/] strip document_root prefix: /srv/www/example.com/index.php/test -> /index.php/test
[Sat Apr 29 09:45:01.600560 2017] [rewrite:trace1] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141b40a0/initial] [perdir /srv/www/example.com/] internal redirect with /index.php/test [INTERNAL REDIRECT]
[Sat Apr 29 09:45:01.600621 2017] [rewrite:trace3] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a1a78/initial/redir#1] [perdir /srv/www/example.com/] add path info postfix: /srv/www/example.com/index.php -> /srv/www/example.com/index.php/test
[Sat Apr 29 09:45:01.600626 2017] [rewrite:trace3] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a1a78/initial/redir#1] [perdir /srv/www/example.com/] strip per-dir prefix: /srv/www/example.com/index.php/test -> index.php/test
[Sat Apr 29 09:45:01.600628 2017] [rewrite:trace3] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a1a78/initial/redir#1] [perdir /srv/www/example.com/] applying pattern '^(.*)$' to uri 'index.php/test'
[Sat Apr 29 09:45:01.600643 2017] [rewrite:trace4] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a1a78/initial/redir#1] [perdir /srv/www/example.com/] RewriteCond: input='index.php/test' pattern='^index\\.php' => matched
[Sat Apr 29 09:45:01.600646 2017] [rewrite:trace2] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a1a78/initial/redir#1] [perdir /srv/www/example.com/] forcing '/srv/www/example.com/index.php' to get passed through to next API URI-to-filename handler
[Sat Apr 29 09:45:01.600648 2017] [rewrite:trace1] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a1a78/initial/redir#1] [perdir /srv/www/example.com/] initial URL equal rewritten URL: /srv/www/example.com/index.php [IGNORING REWRITE]
[Sat Apr 29 09:45:01.600664 2017] [proxy_fcgi:debug] [pid 3013:tid 140574514460416] mod_proxy_fcgi.c(913): [client xx.xx.xx.xx:32639] AH01076: url: fcgi://localhost/srv/www/example.com/index.php proxyname: (null) proxyport: 0
[Sat Apr 29 09:45:01.600666 2017] [proxy_fcgi:debug] [pid 3013:tid 140574514460416] mod_proxy_fcgi.c(920): [client xx.xx.xx.xx:32639] AH01078: serving URL fcgi://localhost/srv/www/example.com/index.php
[Sat Apr 29 09:45:01.600790 2017] [rewrite:trace3] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a30a0/subreq] [perdir /srv/www/example.com/] strip per-dir prefix: /srv/www/example.com/test -> test
[Sat Apr 29 09:45:01.600795 2017] [rewrite:trace3] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a30a0/subreq] [perdir /srv/www/example.com/] applying pattern '^(.*)$' to uri 'test'
[Sat Apr 29 09:45:01.600799 2017] [rewrite:trace4] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a30a0/subreq] [perdir /srv/www/example.com/] RewriteCond: input='test' pattern='^index\\.php' => not-matched
[Sat Apr 29 09:45:01.600801 2017] [rewrite:trace3] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a30a0/subreq] [perdir /srv/www/example.com/] strip per-dir prefix: /srv/www/example.com/test -> test
[Sat Apr 29 09:45:01.600803 2017] [rewrite:trace3] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a30a0/subreq] [perdir /srv/www/example.com/] applying pattern '^(.*)$' to uri 'test'
[Sat Apr 29 09:45:01.600805 2017] [rewrite:trace2] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a30a0/subreq] [perdir /srv/www/example.com/] rewrite 'test' -> 'index.php/test'
[Sat Apr 29 09:45:01.600807 2017] [rewrite:trace3] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a30a0/subreq] [perdir /srv/www/example.com/] add per-dir prefix: index.php/test -> /srv/www/example.com/index.php/test
[Sat Apr 29 09:45:01.600810 2017] [rewrite:trace2] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a30a0/subreq] [perdir /srv/www/example.com/] forcing '/srv/www/example.com/index.php/test' to get passed through to next API URI-to-filename handler
[Sat Apr 29 09:45:01.600813 2017] [rewrite:trace2] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a30a0/subreq] [perdir /srv/www/example.com/] strip document_root prefix: /srv/www/example.com/index.php/test -> /index.php/test
[Sat Apr 29 09:45:01.600815 2017] [rewrite:trace1] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a30a0/subreq] [perdir /srv/www/example.com/] internal redirect with /index.php/test [INTERNAL REDIRECT]
[Sat Apr 29 09:45:01.602797 2017] [proxy_fcgi:error] [pid 3013:tid 140574514460416] [client xx.xx.xx.xx:32639] AH01071: Got error 'Primary script unknown\n'
[Sat Apr 29 09:45:01.602833 2017] [proxy_fcgi:trace4] [pid 3013:tid 140574514460416] util_script.c(571): [client xx.xx.xx.xx:32639] Headers from script 'index.php':
[Sat Apr 29 09:45:01.602839 2017] [proxy_fcgi:trace4] [pid 3013:tid 140574514460416] util_script.c(572): [client xx.xx.xx.xx:32639]   Status: 404 Not Found
[Sat Apr 29 09:45:01.602842 2017] [proxy_fcgi:trace4] [pid 3013:tid 140574514460416] util_script.c(572): [client xx.xx.xx.xx:32639]   Content-type: text/html; charset=UTF-8

How to get the Apache to properly rewrite the URLs and pass the PATH_INFO at the same time?

Note: This question might seem to be similar as Apache 2.4 + PHP-FPM + ProxyPassMatch but in my case I'm already using SetHandler. The problem is with the PATH_INFO part, which the answers there don't seem to solve.

Disassembler
  • 246
  • 2
  • 7
  • 1
    I might be working on a similar issue (WordPress) at https://bz.apache.org/bugzilla/show_bug.cgi?id=51517#c22 The solution w/ 2.4.26 seems to unintuitively be `ProxyFCGIBackendType GENERIC`. Digging for further details. – lkraav Jun 20 '17 at 15:08

1 Answers1

5

After few days of struggle, I have captured and examined CGI headers sent between Apache and PHP-FPM and tested the same also with different versions of said components. It turns out that different versions of Apache set SCRIPT_FILENAME variable differently which is unaccounted for in PHP-FPM.
Apache 2.4.18 (default in Ubuntu 16.04 which I use) populates the variable as follows:

SCRIPT_FILENAME proxy:fcgi://localhost/srv/www/index.php

Whereas Apache 2.4.25 sets:

SCRIPT_FILENAME /srv/www/index.php

Apache documentation of mod_proxy_fcgi mentions a directive ProxyFCGIBackendType available since Apache 2.4.26 (not released yet as of 2017-05-02), which defaults to "FPM". There is a following note in the description:

One example of values that change based on the setting of this directive is SCRIPT_FILENAME. When using mod_proxy_fcgi historically, SCRIPT_FILENAME was prefixed with the string "proxy:fcgi://". This variable is what some generic FastCGI applications would read as their script input, but PHP-FPM would strip the prefix then remember it was talking to Apache. In 2.4.21 through 2.4.25, this prefix was automatically stripped by the server, breaking the ability of PHP-FPM to detect and interoperate with Apache in some scenarios.

Seems I have coincidentally found "some scenario". Answer to my own question is then: Do not use Apache 2.4.21 through 2.4.25 as they contain a bug. Use either lower version or wait for newer where the bug is fixed.

Disassembler
  • 246
  • 2
  • 7