1

I have just switched hosting providers and stumbled across a limitation that bugs me. Previously I had the following mapping between domains and files on the webserver:

example.com        → /web/example.com/www
www.example.com    → /web/example.com/www
matomo.example.com → /web/example.com/matomo

This lets me have different sites and also makes it possible to have a .htaccess just for the www and “naked” domains.

My new hosting provider forces me to have example.com → /web/. I have sent them an email about it, but I fear that they won't change their ways because of me.

The subdomains are free to be placed, but now I have the awkward situation that I can access matomo.example.com at example.com/example.com/matomo, which will confuse it since the hostname does not match.

Is there something that I can do with .htaccess and mod_rewrite such that the .htaccess only applies to the www part and also that I have independent subdirectories?

  • Let me guess: cPanel? cPanel has a horrible configuration schema that is unsecure. If so, I address this in parts here and there. Let me know. Cheers!! – closetnoc Jul 30 '18 at 23:06
  • @closetnoc: From the URL I infer that it is called “cobalt”. Did you forget to include some links in your comment. – Martin Ueding Jul 31 '18 at 10:17
  • When I get back I will see what might be helpful. Cheers!! – closetnoc Jul 31 '18 at 13:21
  • "The subdomains are free to be placed" - although, but the looks, they are not free to be placed anywhere? "example.com/example.com/matomo" - is the repetition of example.com intentional? – MrWhite Jul 31 '18 at 21:36
  • An aside: under cPanel you wouldn't expect to have this problem as you are usually free to point your subdomains anywhere... either outside of the main domains document root (as in the original example) or as subdirectories off the main domain's document root (as in the second example by the looks), and any level of sub-subdirectories if you wish (nesting subdomains if you want). Although cPanel defaults to subdomains pointing to subdirectories off the main domain - so this is what most users seem to go for. @closetnoc – MrWhite Jul 31 '18 at 22:29
2

but now I have the awkward situation that I can access matomo.example.com at example.com/example.com/matomo, which will confuse it since the hostname does not match.

In .htaccess you can check the hostname and redirect to the subdomain if the site has been erroneously accessed via the subdirectory on the main domain.

For example, in the .htaccess file located in the document root of the subdomain (which I assume is at example.com/example.com/matomo/.htaccess) you can do something like the following near the top of the file using mod_rewrite:

RewriteEngine On

RewriteCond %{HTTP_HOST} !=matomo.example.com
RewriteRule ^ https://matomo.example.com%{REQUEST_URI} [R=301,L]

This has the added benefit that it canonicalises any malformed request that contains a mixed-case hostname or a FQDN with a trailing dot.

OR, you can do something similar in the parent .htaccess file that affects all subdomains (accessed via the subdirectory) - but that would be dependent on whether the subdomain already has its own .htaccess file that uses mod_rewrite (the subdomain's mod_rewrite directives will override the parent directives by default).

Is there something that I can do with .htaccess and mod_rewrite such that the .htaccess only applies to the www part and also that I have independent subdirectories?

.htaccess files work along the filesystem path. The .htaccess file in the parent directory will naturally control the entire directory tree from the parent down through all subdirectories, so it is "tricky" to have true independence (without access to the server config).

However, different Apache modules behave differently in terms of how the directives are inherited. With mod_rewrite, providing the inheritance model has not been changed in the server-config, then simply enabling the rewrite engine (ie. RewriteEngine On) in the subdirectory's .htaccess file is sufficient to completely override any mod_rewrite directives in any parent .htaccess file. But directives from other modules cannot be overridden so easily (provision would need to be made in the parent .htaccess file).

Workaround

Instead of serving your main-site from the document root of the main domain, you could move your main-site to a subdirectory (effectively mimicking your original setup) and rewrite all requests for the domain apex or www subdomain to this subdirectory.

The document root of your main domain would then have minimal files, perhaps just a simple .htaccess file that rewrites all requests. For example, assuming all your main-site files are in a /mainsite subdirectory then you could do something like the following:

RewriteEngine On
RewriteCond %{HTTP_HOST} ^(www\.)?example\.com [NC]
RewriteRule !^mainsite/ /mainsite%{REQUEST_URI} [L]

UPDATE: Unless you have additional .htaccess files (that contain mod_rewrite directives) in the subsite's subdirectories then the above is sufficient to prevent the subsites from being accessed by their respective subdirectories off the main domain, since (as you mentioned in comments) the request is internally rewritten to the /mainsite subdirectory - which will probably result in a 404.

However, if the subsite does use its own .htaccess file with its own mod_rewrite directives then - by default - these will completely override the above directives in the document root, so the erroneous request for the subdirectory will not be rewritten to the mainsite. In this case, either implement the redirect as mentioned in the first part of this answer, OR if you are using Apache 2.4+ then you can enable mod_rewrite inheritance in the parent .htaccess file so that the parent mod_rewrite directives are processed first. You can do this by adding the RewriteOptions InheritDownBefore directive to the .htaccess file in the document root. This then becomes (with additional comments):

RewriteEngine On

# Apache 2.4+ Execute these directives BEFORE child configs
RewriteOptions InheritDownBefore

# Rewrite all requests for the main domain to a subdirectory
RewriteCond %{HTTP_HOST} ^(www\.)?example\.com [NC]
RewriteRule !^mainsite/ /mainsite%{REQUEST_URI} [L]
  • I have tried the last variant, but I only get an error 500. And it seems that I cannot look at the error log where such errors are logged. Before I dig into the rewrite engine: Will that cause a redirect to example.com/mainsite/index.html or will the user still see example.com/index.html? – Martin Ueding Aug 1 '18 at 15:12
  • 1
    Sorry, there was a typo... the last directive should be a RewriteRule, not a RewriteCond! (Now updated.) (Although that itself wouldn't have caused a 500 error - other directives could have.) The "last code block" isn't necessarily a variant, it would still need to be used together with the directives in the first part of my answer (to prevent the subdirectory being accessible). That last code block triggers an internal rewrite (not an external redirect) from example.com/<something> to example.com/mainsite/<something>. The user only sees example.com/<something>. – MrWhite Aug 1 '18 at 15:42
  • 1
    Thanks, now it works fine from the subdirectory! I do not think that I need the additional guards against accessing a file via the subdirectory now as such queries are now internally redirected into the www subdirectory. – Martin Ueding Aug 1 '18 at 16:29
  • 1
    "...such queries are now internally redirected into the www subdirectory" - True. However, that is currently dependent on the other subsite (in a subdirectory) not having its own .htaccess file that uses mod_rewrite. If it does, then such queries will not be internally redirected. I've updated my answer. – MrWhite Aug 1 '18 at 18:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.