Use nested directives in .htaccess in Apache 2.4

.htaccessapache-2.4configurationredirect

I am trying to simulate the permalink structure of a previous version of my site using Redirect and RedirectMatch rules in my .htaccess file.

I have different rules that I would to apply to different paths from my old site. Some directories have no analogue and I want them to redirect to a single location. Some directories contain many items (thousands) at varying locations and I want them to redirect smartly to their correct new locations in the new site.

It seems that I could guard and group related items with a basic regex test on <If> to prevent all the contained grouped redirects from being tested if they would never match. In this method, the resulting configuration looks logical and coherent and can be easily auto-generated:

<If "%{REQUEST_URI} =~ m#^/categories/software/.*#">
    # These rules aren't considered if the request wasn't for a subpath of categories/software.

    <If "%{REQUEST_URI} =~ m#^/categories/software/store/.*#">
        # All old store pages now invalid, go to main store.    
        RedirectMatch 301 .* /software-store/
    </If>

    # Regexes for each category of software to group them logically.
    # And so that 1,000s of redirects don't get considered on each page load.
    <If "%{REQUEST_URI} =~ m#^/categories/software/item/.*#">
        # Loads and loads of redirect lines for pages with arbitrary rules to product pages.
        Redirect 301 "/categories/software/item/foo" /software-store/games/foo
        Redirect 301 "/categories/software/item/bar" /software-store/productivity/bar
        Redirect 301 "/categories/software/item/baz" /software-store/misc/baz
        # ...
    </If>
    <If "%{REQUEST_URI} =~ m#^/categories/software/dlc/.*#">
        # Loads and loads of redirect lines. It could also be grouped into subdirectories of dlc/ and so on.
        # ...
    </If>
</If>
# ...

For a huge catalogue, a few guarding regexes can prevent thousands of useless tests.

I'm using Apache 2.4, where the <If> directive is available, but the above directives aren't having the effect I expect. The interior <If>s are being ignored completely.

If I remove the enclosing <If> and just have the innermost <If>s present the rules work, so I don't believe that my syntax or my Redirect rules are at fault.

I suspect that the problem is that I can't nest <If>s, although this seems like a very common thing to want to do. I can't see any reference to nesting, allowed or otherwise, in the documentation.
http://httpd.apache.org/docs/2.4/mod/core.html#if

Can I nest <If> directives? And if so/if not so, can you point me to the section of the documentation that says why.

Best Answer

Updated Answer:

As of Apache 2.4.26 nested <If> directives are allowed.

The change log has the following change noted:

Evaluate nested If/ElseIf/Else configuration blocks. [Luca Toscano, Jacob Champion]


Original answer:

An <If> directive cannot be nested inside another <If> directive but can be nested inside other sections like <Directory>, <Location>, <Files> and <IfModule>.

The Apache 2.4 Documentation for the If Directive has the following notice:

Not a scripting language

The name of this directive is very familiar to programmers and admins but it should not be confused with its counterpart in scripting languages. For example, the current implementation does not contemplate the possibility of having a <If> section inside another one (the inner <If> will be ignored).

No reason is given for why they chose not to allow nested <If> directives.

The only other information about nesting provided in the documentation indicates each section type differs on whether or not it can be nested:

Nesting of sections

Some section types can be nested inside other section types. On the one hand, <Files> can be used inside <Directory>. On the other hand, <If> can be used inside <Directory>, <Location>, and <Files> sections (but not inside another <If>). The regex counterparts of the named section behave identically.