Mod_rewrite on Debian Stretch breaks php7.0-fpm with AH01071: Got error ‘Primary script unknown\n’

apache-2.4debian-stretchmod-rewritephp-fpm

We've just built a new Debian 9.8 server to replace our 8.11 server in order to test and upgrade to php7. We've installed apache2, php7.0-fpm and brought over out existing virtual host config, which has this in it:

<Directory "${virtualhost_path}/public_html">
    Require all granted
    AllowOverride None
    Options FollowSymLinks

    <IfModule mod_rewrite.c>
        RewriteEngine On

        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule ^/?(.*)$ /index.php/$1 [L]
    </IfModule>
</Directory>

Here is the (stock, standard) php-fpm conf:

$ cat /etc/apache2/conf-enabled/php7.0-fpm.conf 

# Redirect to local php-fpm if mod_php is not available
<IfModule !mod_php7.c>
<IfModule proxy_fcgi_module>
    # Enable http authorization headers
    <IfModule setenvif_module>
    SetEnvIfNoCase ^Authorization$ "(.+)" HTTP_AUTHORIZATION=$1
    </IfModule>

    <FilesMatch ".+\.ph(p[3457]?|t|tml)$">
        SetHandler "proxy:unix:/run/php/php7.0-fpm.sock|fcgi://localhost"
    </FilesMatch>
    <FilesMatch ".+\.phps$">
        # Deny access to raw php sources by default
        # To re-enable it's recommended to enable access to the files
        # only in specific virtual host or directory
        Require all denied
    </FilesMatch>
    # Deny access to files without filename (e.g. '.php')
    <FilesMatch "^\.ph(p[3457]?|t|tml|ps)$">
        Require all denied
    </FilesMatch>
</IfModule>
</IfModule>

However, the rewriting does not seem to be working correctly. When we make this request, we get this result (in the browser, we just see "File Not Found"):

$ curl -I https://hostname/services/login

HTTP/1.1 404 Not Found
Date: Fri, 29 Mar 2019 02:32:01 GMT
Server: Apache/2.4.25 (Debian)
Content-Type: text/html; charset=UTF-8

And we see this in the log:

[hostname/sid#7f0e8fd47d30][rid#7f0e8fc3f0a0/initial] [perdir /home/jay/online/public_html/] add path info postfix: /home/jay/online/public_html/services -> /home/jay/online/public_html/services/login
[hostname/sid#7f0e8fd47d30][rid#7f0e8fc3f0a0/initial] [perdir /home/jay/online/public_html/] strip per-dir prefix: /home/jay/online/public_html/services/login -> services/login
[hostname/sid#7f0e8fd47d30][rid#7f0e8fc3f0a0/initial] [perdir /home/jay/online/public_html/] applying pattern '^/?(.*)$' to uri 'services/login'
[hostname/sid#7f0e8fd47d30][rid#7f0e8fc3f0a0/initial] [perdir /home/jay/online/public_html/] rewrite 'services/login' -> '/index.php/services/login'
[hostname/sid#7f0e8fd47d30][rid#7f0e8fc3f0a0/initial] [perdir /home/jay/online/public_html/] trying to replace context docroot /home/jay/online/public_html with context prefix 
[hostname/sid#7f0e8fd47d30][rid#7f0e8fc3f0a0/initial] [perdir /home/jay/online/public_html/] internal redirect with /index.php/services/login [INTERNAL REDIRECT]
[hostname/sid#7f0e8fd47d30][rid#7f0e8fc3dc00/initial/redir#1] [perdir /home/jay/online/public_html/] add path info postfix: /home/jay/online/public_html/index.php -> /home/jay/online/public_html/index.php/services/login
[hostname/sid#7f0e8fd47d30][rid#7f0e8fc3dc00/initial/redir#1] [perdir /home/jay/online/public_html/] strip per-dir prefix: /home/jay/online/public_html/index.php/services/login -> index.php/services/login
[hostname/sid#7f0e8fd47d30][rid#7f0e8fc3dc00/initial/redir#1] [perdir /home/jay/online/public_html/] applying pattern '^/?(.*)$' to uri 'index.php/services/login'
[hostname/sid#7f0e8fd47d30][rid#7f0e8fc3dc00/initial/redir#1] [perdir /home/jay/online/public_html/] pass through /home/jay/online/public_html/index.php
[hostname/sid#7f0e8fd47d30][rid#7f0e8830a0a0/subreq] [perdir /home/jay/online/public_html/] add path info postfix: /home/jay/online/public_html/services -> /home/jay/online/public_html/services/login
[hostname/sid#7f0e8fd47d30][rid#7f0e8830a0a0/subreq] [perdir /home/jay/online/public_html/] strip per-dir prefix: /home/jay/online/public_html/services/login -> services/login
[hostname/sid#7f0e8fd47d30][rid#7f0e8830a0a0/subreq] [perdir /home/jay/online/public_html/] applying pattern '^/?(.*)$' to uri 'services/login'
[hostname/sid#7f0e8fd47d30][rid#7f0e8830a0a0/subreq] [perdir /home/jay/online/public_html/] rewrite 'services/login' -> '/index.php/services/login'
[hostname/sid#7f0e8fd47d30][rid#7f0e8830a0a0/subreq] [perdir /home/jay/online/public_html/] trying to replace context docroot /home/jay/online/public_html with context prefix 
[hostname/sid#7f0e8fd47d30][rid#7f0e8830a0a0/subreq] [perdir /home/jay/online/public_html/] internal redirect with /index.php/services/login [INTERNAL REDIRECT]
AH01071: Got error 'Primary script unknown\n'

It appears to be rewriting everything correctly according to the log, but it doesn't seem to be serving index.php as expected along with the correct PATH_INFO. If we manually include index.php in the URL, it serves the correct file:

$ curl -I https://hostname/index.php/services/login

HTTP/1.1 200 OK
Date: Fri, 29 Mar 2019 02:35:13 GMT
Server: Apache/2.4.25 (Debian)
Content-Type: text/html; charset=UTF-8

But, the whole point of this configuration is to avoid having index.php in the URL.

Is there some change in apache for FPM between Debian 8 and 9 that is causing this? Is there any workaround?

Best Answer

This is a problem in Apache from 2.4.21 - 2.4.25 (inclusive), as described by Disassembler in the answer at https://serverfault.com/a/847750

See also the mod_proxy_fcgi docs

Stretch appears to be stuck on Apache 2.4.25, and the relevant patch has not yet been backported - I assume that it never will be.

Beyond compiling your own Apache for Stretch, the best solution would appear to be to either to upgrade to Buster or to use PHP via the Apache module instead of FPM.