Viewed   142 times

Summary: Apache 2.4's mod_proxy does not seem to be passing the Authorization headers to PHP-FPM. Is there any way to fix this?

Long version: I am running a server with Apache 2.4 and PHP-FPM. I am using APC for both opcode caching and user caching. As recommended by the Internet, I am using Apache 2.4's mod_proxy_fcgi to proxy the requests to FPM, like this:

ProxyPassMatch ^/(.*.php)$ fcgi://127.0.0.1:9000/foo/bar/$1

The setup works fine, except one thing: APC's bundled apc.php, used to monitor the status of APC does not allow me to log in (required for looking at user cache entries). When I click "User cache entries" to see the user cache, it asks me to log in, clicking on the login button displays the usual HTTP login form, but entering the correct login and password yields no success. This function is working perfectly when running with mod_php instead of mod_proxy + php-fpm.

After some googling I found that other people had the same issue and figured out that it was because Apache was not passing the Authorization HTTP headers to the external FastCgi process. Unfortunately I only found a fix for mod_fastcgi, which looked like this:

FastCgiExternalServer /usr/lib/cgi-bin/php5-fcgi -host 127.0.0.1:9000 -pass-header Authorization

Is there an equivalent setting or some workaround which would also work with mod_proxy_fcgi?

 Answers

2

Various Apache modules will strip the Authorization header, usually for "security reasons". They all have different obscure settings you can tweak to overrule this behaviour, but you'll need to determine exactly which module is to blame.

You can work around this issue by passing the header directly to PHP via the env:

SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1

See also Zend Server Windows - Authorization header is not passed to PHP script

In some scenarios, even this won't work directly and you must also change your PHP code to access $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] rather than $_SERVER['HTTP_AUTHORIZATION']. See When setting environment variables in Apache RewriteRule directives, what causes the variable name to be prefixed with "REDIRECT_"?

Monday, November 14, 2022
49

At last I found a way to make it work. First I tried Dave Cheney suggestion, so I installed an other certificate for the apache server redirected to Tomcat non SSL port (so the proxy was redirecting to http://localhost:8080/). Unfortunately it did not fully work as in the web browser the https was transformed to http immediately upon connection. So I reverted to using https://localhost:8443/ and the final touch to make it work was to add again SSLProxyEngine.

Here is the resulting VirtualHost configuration:

<VirtualHost 1.2.3.4:443>
    ServerName host.domain.org

    <Proxy *>
        Order deny,allow
        Allow from all
    </Proxy>

    SSLEngine on
    SSLProxyEngine On
    SSLCertificateFile /etc/apache2/ssl/certificate.crt
    SSLCertificateKeyFile /etc/apache2/ssl/certificate.key

    ProxyRequests Off
    ProxyPreserveHost On
    ProxyPass / https://localhost:8443/
    ProxyPassReverse / https://localhost:8443/
</VirtualHost>
Friday, October 21, 2022
 
19

The trick is that you need to rename the action and alias too so they are not 'redefinitions', so for my 'www' pool, my vhost config looks like this:

<IfModule mod_fastcgi.c>
    <FilesMatch .php$>
        SetHandler php-script
    </FilesMatch>
    Action php-script /php5-www.fcgi virtual
    Alias /php5-www.fcgi /var/fastcgi/php5-www.fcgi
    FastCGIExternalServer /var/fastcgi/php5-www.fcgi -socket /var/run/php5-fpm-www.sock
    <Directory "/var/fastcgi">
        Order allow,deny
        <Files "php5-www.fcgi">
            Order deny,allow
            Deny from all
            Allow from env=REDIRECT_STATUS
        </Files>
    </Directory>
</IfModule>

And for SSL on the same pool:

<IfModule mod_fastcgi.c>
    <FilesMatch .php$>
        SetHandler php-script
    </FilesMatch>
    Action php-script /php5-www-ssl.fcgi virtual
    Alias /php5-www-ssl.fcgi /var/fastcgi/php5-www-ssl.fcgi
    FastCGIExternalServer /var/fastcgi/php5-www-ssl.fcgi -socket /var/run/php5-fpm-www.sock
    <Directory "/var/fastcgi">
        Order allow,deny
        <Files "php5-www-ssl.fcgi">
            Order deny,allow
            Deny from all
            Allow from env=REDIRECT_STATUS
        </Files>
    </Directory>
</IfModule>

So they're using different names, but pointing at the same socket.

Tuesday, December 20, 2022
 
4

This can be achieved by using mod_proxy_html which is capable of rewriting links. Generally this would not be a problem if your webpage would be using relative paths.

With the module installed you can use a configuration similar to this one

LoadModule proxy_module      modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule headers_module    modules/mod_headers.so
LoadFile   /usr/lib/libxml2.so
LoadModule proxy_html_module modules/mod_proxy_html.so
LoadModule xml2enc_module modules/mod_xml2enc.so

# Disable Proxy Requests since this is not a forward proxy
ProxyRequests off


ProxyPass /mypath/ http://www.example1.com/
ProxyHTMLURLMap http://www.example1.com /mypath

<Location /mypath/>
        ProxyPassReverse /
        ProxyHTMLEnable On
        ProxyHTMLURLMap  /      /mypath/

        # You cannot rewrite gzip compressed streams
        RequestHeader    unset  Accept-Encoding
</Location>

You can read up more about mod_proxy_html here and here

Sunday, August 21, 2022
 
39

Looks like the only way is to add the env vars manually.

I modified the code a bit

#!/usr/bin/php
<?php
$confFile = '/etc/nginx/fastcgi_params';

// Update the fpm configuration to make the environment variables available
// NOTE: ONLY in the CLI will $_SERVER have environment variables in it.
$content = file_get_contents($confFile);
$line = false;
foreach ($_SERVER as $name => $val) {
    if (strstr($name, 'SYMFONY') !== false) {
        $line = "fastcgi_param {$name} {$val};n";
        # Either Add or Reset the variable
        if (strstr($content, $name) !== false) {
            $content = preg_replace('/fastcgi_param[st]+'.$name.'][st]+.*?n/', $line, $content);
            echo "MODIFIED {$name}n";
        } else {
            $content .= "n{$line}";
            echo "ADDED    {$name}n";
        }
    }
}
if ($line) {
    file_put_contents($confFile, $content);
}
Wednesday, August 3, 2022
 
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :