Search code examples
apachesubdomainvirtualhostdocument-root

Apache VirtualHosts: two subdomain configurations possible?


At present, I have the following VirtualHost configuration set up on my Apache 2.4 server (running EasyPHP):

## Local domain access
<VirtualHost 127.0.0.1>
    UseCanonicalName Off
    ServerAlias *.local *.*.local
    VirtualDocumentRoot "D:/var/www/%-2/public_html"
    <Directory "D:/var/www/*/public_html">
        Require all granted
        Options Includes Indexes FollowSymLinks
        AllowOverride All
    </Directory>
</VirtualHost>

Essentially, this maps {domain}.local and {sub}.{domain}.local to the {domain}s document root - the reason it's done this way is due to the fact that I primarily develop with Laravel, and make good use of subdomain routing.

However, there are certain situations whereby I need to have the subdomain-request point to another directory in the domain's document-root parent, thus calling up a different application with its own document root.

With the above VirtualHost configuration, requesting test.example.local will serve up the document root at D:\var\www\example\public_html.

What additions or changes can I make to this configuration to allow the above example to serve D:\var\www\example\test\public_html instead, but only if the test directory exists?


Solution

  • Right, so I figured that I shouldn't make things complicated (elephant/mosquito metaphor), but should still comply with the DRY principal so that I don't have a huge mess of exceptions in my virtual host configuration file - at the end of the day, this gets quite exhausting, and difficult to maintain.

    As such, I've opted to use Apache's mod_macro module - this needs to be explicitly enabled.

    The result is this:

    # Macro LocalSub
    # For specific *.*.local subdomains that require their own DIRECTORY_ROOT
    <Macro LocalSub $sub $domain>
        <VirtualHost 127.0.0.1>
            ServerName $sub.$domain.local
            DocumentRoot "D:/var/www/$domain/$sub/public_html"
            <Directory "D:/var/www/$domain/$sub/public_html">
                Require all granted
                Options Includes Indexes FollowSymLinks
                AllowOverride All
            </Directory>
        </VirtualHost>
    </Macro>
    
    # Specific subdomain Macro usage
    Use LocalSub assets example
    Use LocalSub images01 mydomain
    Use LocalSub images02 mydomain
    
    # Fallback to *.local and *.*.local (points to the same DOCUMENT_ROOT)
    <VirtualHost 127.0.0.1>
        UseCanonicalName Off
        ServerAlias *.local *.*.local
        VirtualDocumentRoot "D:/var/www/%-2/public_html"
        <Directory "D:/var/www/*/public_html">
            Require all granted
            Options Includes Indexes FollowSymLinks
            AllowOverride All
        </Directory>
    </VirtualHost>
    

    This is better than the mod_rewrite approach in the VirtualHost context as this method allows the DOCUMENT_ROOT to be set correctly.

    At the end of the day, trying to get Apache to automate everything for me, and thus bending to my very specific wills, is not the way to go - so a little manual overriding does the trick, whilst keeping everything DRY.

    This could be taken a step further by also 'macrofying' <Directory>:

    # Macro Directory
    # Default Directory configuration on a per-vhost basis
    <Macro Directory $dir>
        <Directory "D:/var/www/$dir/public_html">
            Require all granted
            Options Includes Indexes FollowSymLinks
            AllowOverride All
        </Directory>
    </Macro>
    
    # Macro LocalSub
    # For specific *.*.local subdomains that require their own DIRECTORY_ROOT
    <Macro LocalSub $sub $domain>
        <VirtualHost 127.0.0.1>
            ServerName $sub.$domain.local
            DocumentRoot "D:/var/www/$domain/$sub/public_html"
            Use Directory $domain/$sub
        </VirtualHost>
    </Macro>
    
    # Specific subdomain Macro usage
    Use LocalSub assets example
    Use LocalSub images01 mydomain
    Use LocalSub images02 mydomain
    
    # Fallback to *.local and *.*.local (points to the same DOCUMENT_ROOT)
    <VirtualHost 127.0.0.1>
        UseCanonicalName Off
        ServerAlias *.local *.*.local
        VirtualDocumentRoot "D:/var/www/%-2/public_html"
        Use Directory *
    </VirtualHost>