This is a short documentation of a very strange unexpected behaviour I encountered in a current project.

I have two domains, pointing to the same htroot, where both are handled by a single TYPO3 installation. But from the outside, these are two separate web sites. The CMS has nothing to do with the strangness, at least in this case:

For both sites, I need the complete icon-gasm that is needed for modern "app" and "favicon"-ess:

android-icon-36x36.png
android-icon-48x48.png
android-icon-72x72.png
android-icon-96x96.png
android-icon-144x144.png
android-icon-192x192.png
apple-icon-57x57.png
apple-icon-60x60.png
apple-icon-72x72.png
apple-icon-76x76.png
apple-icon-114x114.png
apple-icon-120x120.png
apple-icon-144x144.png
apple-icon-152x152.png
apple-icon-180x180.png
apple-icon-precomposed.png
apple-icon.png
browserconfig.xml
favicon-16x16.png
favicon-32x32.png
favicon-96x96.png
favicon.ico
manifest.json
ms-icon-70x70.png
ms-icon-144x144.png
ms-icon-150x150.png
ms-icon-310x310.png

In a single-domain install, I'd throw the whole generated icons, browserconfig.xml and manifest.json into the web root. Let god the browser sort'em out.

Now, with a "shared" web root, this obviously doesn't work, since both Domain A and Domain B would show the same set of icons.

So I decided to let god the server sort'em out by resorting to a rewrite in the .htaccess file.

Something like

»If the domain is "domain.a", then rewrite the request to, for example "/favicon.ico", to "/assets/domainA/favicon.ico", and do so accordingly with "domain.b" to "/assets/domainB/favicon.ico"«

in .htaccess this would work like this:

rewriteCond %{HTTP_HOST} ^domain\.a$
rewriteRule ^favicon\.ico$ /assets/domainA/favicon.ico [L]
 
rewriteCond %{HTTP_HOST} ^domain\.b$
rewriteRule ^favicon\.ico$ /assets/domainB/favicon.ico [L]

This works.
Now, since there are a lot of icon files, writing a rewriteRule for each of them is rather tedious. So after checking with the files, I arrived at only two rewriteRules, one for the "text" files (browserconfig.xml and manifest.json)

RewriteRule ^(browserconfig\.xml|manifest\.json)$ /assets/domainA/$1 [L]

and a second one for all the icon files like "apple-icon-precomposed.png", "android-icon-16x16.png", and "ms-icon-40x40.png" and so on:

RewriteRule ^(favicon|android\-icon|apple\-icon|ms\-icon)(\-\d+|\-precomposed)?(x\d+)?\.(png|ico)$ /assets/domainA/$1$2$3.$4 [L]

So I put those two rewriteRules after the respective rewriteCond, like this:

rewriteCond %{HTTP_HOST} ^domain\.a$
  RewriteRule ^(browserconfig\.xml|manifest\.json)$ /assets/domainA/$1 [L]
  RewriteRule ^(favicon|android\-icon|apple\-icon|ms\-icon)(\-\d+|\-precomposed)?(x\d+)?\.(png|ico)$ /assets/domainA/$1$2$3.$4 [L]
 
rewriteCond %{HTTP_HOST} ^domain\.b$
  RewriteRule ^(browserconfig\.xml|manifest\.json)$ /assets/domainB/$1 [L]
  RewriteRule ^(favicon|android\-icon|apple\-icon|ms\-icon)(\-\d+|\-precomposed)?(x\d+)?\.(png|ico)$ /assets/domainB/$1$2$3.$4 [L]

I felt very clever and tested this - but to my surprise this didn't work as expected.
No matter the Domain, always the first condition/rewrite would be applied. If I checked for domain.a first, then requests coming from domain.b would also be rewritten to "/assets/domainA/...". If I checked for domain.b first, then always "/assets/domainB/..." woud be used.

I tested for quite a while, not really knowing what could be the problem (which by the way is the default mode of operation when working in web dev land).
Of course initially I thought that something with my regular expression was wrong, and after a while I reduced everything down to a more or less static rewrite. Didn't work.

As it turns out (or seems so according to my testing), it seems that I cannot use two rewriteRules "under" one rewriteCond. After I changed my code to:

rewriteCond %{HTTP_HOST} ^domain\.a$
  RewriteRule ^(browserconfig\.xml|manifest\.json)$ /assets/domainA/$1 [L]
rewriteCond %{HTTP_HOST} ^domain\.a$
  RewriteRule ^(favicon|android\-icon|apple\-icon|ms\-icon)(\-\d+|\-precomposed)?(x\d+)?\.(png|ico)$ /assets/domainA/$1$2$3.$4 [L]
 
rewriteCond %{HTTP_HOST} ^domain\.b$
  RewriteRule ^(browserconfig\.xml|manifest\.json)$ /assets/domainB/$1 [L]
rewriteCond %{HTTP_HOST} ^domain\.b$
  RewriteRule ^(favicon|android\-icon|apple\-icon|ms\-icon)(\-\d+|\-precomposed)?(x\d+)?\.(png|ico)$ /assets/domainB/$1$2$3.$4 [L]

it works as expected. But, to be honest, I don't get why this is so.

I know that the rewriteRule is the first thing that gets "checked", and only then Apache "looks" if a rewriteCond is there, and only if the rewriteCond evaluates as "true", the actual redirect happens. But somehow my own mental model around this was always the other way round, as it is written in the code, so rewriteCond, then rewriteRule "inside" that condition.

It would be very cool if someone with a better understanding of this voodoo could give me a hint, how this is supposed to work when I have a "group" of rewriteRules, which all share the same rewriteCondition…?

Cheers. :-)