1

What is the meaning, purpose and semantics of the fcgi:// URI after the pipe symbol within the SetHandler directive?

From my understanding of the docs, everything after the scheme part fcgi:// of the URI is has no particular meaning to Apache, but is only used as an opaque, unique identifier to distinguish between different reverse proxies.

This is my current configuration which only uses fcgi://localhost/ and which works as expected.

# Using (?:pattern) instead of (pattern) is a small optimization that
# avoid capturing the matching pattern (as $1) which isn't used here
<FilesMatch ".+\.ph(?:ar|p|tml)$">
    # The following "If" avoids unnecessary "Primary Script Unknown" errors from
    # PHP FPM, if an attacker tries fishing typical PHP scripts (such as "wp-login.php")
    # as we only call PHP FPM for actually existing files.
    <If "-f %{SCRIPT_FILENAME}">
        # The URL after the pipe and "fcgi" can be anything unique.
        # It has no particular meaning, but serves as a opaque, unique identifier and
        # match the <Proxy> definition below.
        SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost/"
    </If>
</FilesMatch>

# The URL of the proxy is arbitrary, but must match the URL which is used by the
# "SetHandler" directive above.
# This creates an explicit worker (see https://httpd.apache.org/docs/2.4/mod/mod_proxy.html#workers)
# to handle requests which are relayed to the PHP FPM and allows to explicitly
# set connection options.
<Proxy "fcgi://localhost">
    ProxySet flushpackets=auto flushwait=10 timeout=1200
</Proxy>

As I need to configure another FCGI reverse proxy, I changed the URI to fcgi://localhost/php/ in both places, i.e.

...
# The URL after the pipe and "fcgi" can be anything unique.
# It has no particular meaning, but must match the <Proxy> definition below.
# We use "localhost/php" here as a telling name to make explicit that this
# proxy is our local PHP FPM.
SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost/php/"
...
<Proxy "fcgi://localhost/php">
...

This resulted in the error

[proxy_fcgi:error] cloud.mhnnet.de: AH01071: Got error 'Primary script unknown'

for previously working scripts.

Obviously, the URI after the pipe symbol is not irrelevant. Where am I erring? How does the URI-part work?


Here are some extracts from the docs:

From Apache 2.4 Doc, Module mod_proxy_fcgi, Examples (highlighting by me):

The following example passes the request URI as a filesystem path for the PHP-FPM daemon to run. In this case, PHP-FPM is listening on a unix domain socket (UDS). Requires 2.4.9 or later. With this syntax, the hostname and optional port following fcgi:// are ignored.

ProxyPassMatch "^/(.*\.php(/.*)?)$" "unix:/var/run/php5-fpm.sock|fcgi://localhost/var/www/"

[...]

<FilesMatch "\.php$">
  # Note: The only part that varies is /path/to/app.sock
  SetHandler  "proxy:unix:/path/to/app.sock|fcgi://localhost/"
</FilesMatch>

# Define a matching worker.
# The part that is matched to the SetHandler is the part that
# follows the pipe. If you need to distinguish, "localhost; can
# be anything unique.
<Proxy "fcgi://localhost/" enablereuse=on max=10>
</Proxy>

From Apache 2.4 Doc, Module mod_proxy, Access via Handler (highlighting by me):

You can also force a request to be handled as a reverse-proxy request, by creating a suitable handler pass-through. The example configuration below will pass all requests for PHP scripts to the specified FastCGI server using reverse proxy:

<FilesMatch "\.php$">
  # Unix sockets require 2.4.7 or later
  SetHandler  "proxy:unix:/path/to/app.sock|fcgi://localhost/"
</FilesMatch>

From Apache 2.4 Doc, Module mod_proxy, ProxyPassDirective (highlighting by me):

In 2.4.7 and later, support for using a Unix Domain Socket is available by using a target which prepends unix:/path/lis.sock|. For example, to proxy HTTP and target the UDS at /home/www.socket, you would use unix:/home/www.socket|http://localhost/whatever/.

1 Answer 1

0

As the documentation says

The following example passes the request URI as a filesystem path for the PHP-FPM daemon to run. In this case, PHP-FPM is listening on a unix domain socket (UDS). Requires 2.4.9 or later. With this syntax, the hostname and optional port following fcgi:// are ignored.

Only the hostname and port are ignored, not a potential path component!

Hence, the following config works as expected

<FilesMatch ".+\.ph(?:ar|p|tml)$">
    <If "-f %{SCRIPT_FILENAME}">
        SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://php/"
    </If>
</FilesMatch>

<Proxy "fcgi://php/">
    ProxySet flushpackets=auto flushwait=10 timeout=1200
</Proxy>

This example configuration uses fcgi://php/ instead of the typical fcgi://localhost/. Apache maps the handler to the proxy definition based on the arbitrary imaginary domain "php".

Hence, the documentation which says

In 2.4.7 and later, support for using a Unix Domain Socket is available by using a target which prepends unix:/path/lis.sock|. For example, to proxy HTTP and target the UDS at /home/www.socket, you would use unix:/home/www.socket|http://localhost/whatever/.

is nuts. The example should be unix:/home/www.socket|http://whatever/, i.e. the hostname can be "whatever", but not a path component.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .