3

I would like to use the value set by VirtualDocumentRoot in a RewriteRule.

The Apache documentation says:

The other thing to determine is the document root (configured with DocumentRoot and available to CGI scripts via the DOCUMENT_ROOT environment variable). In a normal configuration, this is used by the core module when mapping URIs to filenames, but when the server is configured to do dynamic virtual hosting, that job must be taken over by another module (either mod_vhost_alias or mod_rewrite), which has a different way of doing the mapping. Neither of these modules is responsible for setting the DOCUMENT_ROOT environment variable so if any CGIs or SSI documents make use of it, they will get a misleading value.

Refering to the documentation, it seems I won't be able to use %{DOCUMENT_ROOT} in RewriteRule. But after looking for alternative solutions, I found this ticket (title: DOCUMENT_ROOT environment variable set incorrectly with VirtualDocumentRoot) saying it has been “fixed in 2.4.1”.

I am using the latest (stable) version of Apache:

$ httpd -v
Server version: Apache/2.4.9 (Unix)
Server built:   Jun 18 2014 03:07:48

... but it doesn't seem to work for me. When testing, %{DOCUMENT_ROOT} has the default value set by DocumentRoot in httpd.conf. I would like %{DOCUMENT_ROOT} (or any other variable I could use) to be dynamically set by VirtualDocumentRoot.

Here is what I would like to use in httpd-vhosts.conf:

<VirtualHost *:8080>
    ServerName dev
    ServerAlias *.dev

    VirtualDocumentRoot "/usr/local/var/www/.dev/%-2+"

    RewriteRule ^/(.*\.php(/.*)?)$ "fcgi://127.0.0.1:9000%{DOCUMENT_ROOT}/$1" [P]
</VirtualHost>

Is there a solution?

4
  • Can you use %{SCRIPT_FILENAME} on the right hand side of the rewrite rule? If so, that could solve your problem.
    – John Auld
    Jun 22, 2014 at 9:45
  • SCRIPT_FILENAME has the value of the URL (e.g. "/index.php"), so it cannot be used as a path to the PHP script. Using SERVER_NAME can solve the problem but only if there is one single type of server aliases (*.dev in this case). If I want to add more server aliases (e.g. *.xip.io), SERVER_NAME cannot be used anymore.
    – Matworms
    Jun 23, 2014 at 2:36
  • OK. Can you test %{REQUEST_FILENAME}. The docs for mod_rewrite appear to say that this will give the full file path, so that should include the document root.
    – John Auld
    Jun 23, 2014 at 10:08
  • It doesn't work either but I have found a solution, it is not 100% perfect, but it is good enough for me.
    – Matworms
    Jun 23, 2014 at 11:47

4 Answers 4

2

I accomplished this using mod_proxy and mod_proxy_fcgi, noting the "Proxy via Handler" section: https://httpd.apache.org/docs/trunk/mod/mod_proxy_fcgi.html

I needed to be able to run both PHP 5.6 and PHP 7 on my local dev sites so I installed PHP-FPM for both PHP 5.6 and PHP 7 and setup my vhosts config as follows:

<Virtualhost *:80>
    VirtualDocumentRoot "/Volumes/CODE/projects/%1"
    ServerName sites.hack
    ServerAlias *.hack
    UseCanonicalName Off
    <FilesMatch "\.php$">
        Require all granted
        SetHandler proxy:fcgi://127.0.0.1:9056
    </FilesMatch>
</Virtualhost>

<Virtualhost *:80>
    VirtualDocumentRoot "/Volumes/CODE/projects/%1"
    ServerName php7.php
    Serveralias *.php
    UseCanonicalName off
    <FilesMatch "\.php$">
      Require all granted
      SetHandler proxy:fcgi://127.0.0.1:9070
    </FilesMatch>
</Virtualhost>

As the "Proxy via Handler" section explains:

When FastCGI is configured this way, the server can calculate the most accurate PATH_INFO.

With this configuration I can:

Visit a local dev site http://example.hack and it'll be pulled from the Document Root /Volumes/CODE/projects/example and be passed through to my PHP 5.6 PHP-FPM service SetHandler proxy:fcgi://127.0.0.1:9056.

Visit a local dev site http://example.php and it'll be pulled from the same Document Root /Volumes/CODE/projects/example but it'll be passed through to my PHP 7 PHP-FPM service SetHandler proxy:fcgi://127.0.0.1:9070

I haven't had any problems with this yet. It's simple and works.

1

After having looked in many directions with @John Auld (thanks for your time and help), I have finally found a solution. As I said in a previous comment, it is not 100% perfect but good enough for me.

For clarity's sake, here is what I wanted to have in httpd-vhosts.conf:

<VirtualHost *:8080>
    ServerName dev
    ServerAlias *.dev

    VirtualDocumentRoot "/usr/local/var/www/.dev/%-2+"

    RewriteRule ^/(.*\.php(/.*)?)$ "fcgi://127.0.0.1:9000%{DOCUMENT_ROOT}/$1" [P]
</VirtualHost>

And here is what I've come up with:

<VirtualHost *:8080>
    ServerName dev
    ServerAlias *.dev

    VirtualDocumentRoot "/usr/local/var/www/.dev/%-2/%-3"

    RewriteCond %{SERVER_NAME} (?:([^.]+)\.)?([^.]+)\.dev
    RewriteRule ^/(.*\.php(/.*)?)$ "fcgi://127.0.0.1:9000/usr/local/var/www/.dev/%2/${:%1|www}/$1" [P]
</VirtualHost>

I use RewriteCond to capture parts of %{SERVER_NAME} and reuse them in RewriteRule.

There are two capturing groups: subdomain (%1) and domain (%2). The subdomain is optional so I use the syntax ${map:value|default} to set a default value for the subdomain when empty.

VirtualDocumentRoot has its own default value when a part (%N.M) is not available. As said in the documentation:

If N or M is greater than the number of parts available a single underscore is interpolated.

That's why I had to use a little "trick" to make it work with an optional subdomain:

ln -sfv /path/to/the/project/www /path/to/the/project/_

If you think of a way to do it config only, leave a comment and I will edit my answer with your contribution.

0

The variable is not available in the apache configuration files.

Have a look at mod_macro, which allows the use of variables within the conf files.

http://httpd.apache.org/docs/current/mod/mod_macro.html

5
  • mod_macro indeed allows to define configurable <VirtualHost> blocks, but I don't see how to use it to resolve the DOCUMENT_ROOT problem. Could you provide an example?
    – Matworms
    Jun 21, 2014 at 11:04
  • You would need to use mod_macro instead of md_vhost_alias. However, are you sure that it is correct to pass the full path of the php script to the fcgi socket? If so, does that work with suexec? If all of the scripts run under the web server account the scripts of one user would have access to the content of another user.
    – John Auld
    Jun 21, 2014 at 13:15
  • Actually, I am looking for a zero-config setup for my dev environment, so I have no critical security concerns (and it may be out of the scope of my question). Is there a way to pass PHP scripts to the fcgi socket other than passing the full path of the scripts? What I am trying to get is a RewriteRule using some kind of directory name interpolation (VirtualDocumentRoot ".../%-2+"), as described in the documentation, and I don't see how mod_macro could help me to do that. That's why I asked you if you can provide some example.
    – Matworms
    Jun 21, 2014 at 17:43
  • Have a look at the following URL, fcgi line does not include the path of the php script. I presume that the AddType and Action directives instruct Apache to pass those details at run time, so no rewrite is needed. If you can avoid the rewrite, your mass hosting config is much easier. janoszen.com/2013/04/29/setting-up-apache-with-php-fpm
    – John Auld
    Jun 22, 2014 at 9:54
  • This blog post is about configuring PHP-FPM with mod_fastcgi and I am using mod_proxy_fcgi (bundled with Apache) but I don't think it makes much difference. I could use an Action directive, but Apache still needs to know where my scripts are located and I presume it is specified by the DocumentRoot directive in combination with the URL. I do need directory name interpolation because the host is part of the path to the scripts.
    – Matworms
    Jun 23, 2014 at 4:16
0

Following worked just fine for me for 2.4

UseCanonicalName Off
<VirtualHost *:80>
  ServerName auto.dev
  ServerAlias *.dev
  VirtualDocumentRoot /Users/yourusername/Sites/auto/%1/public

  <Directory ~ "/Users/yourusername/Sites/auto/.*/public">
    Options Indexes FollowSymlinks MultiViews
    AllowOverride All
    Order allow,deny
    Allow from all
  </Directory>
</VirtualHost>

Note that I am mapping to the public folder in root folder

You must log in to answer this question.

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