Ssl – mod_rewrite redirects for site root and subdirectory from HTTP to SSL

apache-2.2directorymod-rewritessl

Ok, so I have two sites within the same webroot — the main site (in the root) and an unrelated bunch of files in a subdirectory. We would like both of these sites to force rendering under SSL.

At the moment, the relevant chunks of my httpd.conf read as follows:

<Directory "/var/www/html">
    <IfModule mod_rewrite.c>
        RewriteEngine on

        <IfModule mod_ssl.c>
            RewriteCond %{HTTPS} !=on
            RewriteRule ^subdir(.*)$ https://%{HTTP_HOST}/subdir$1 [R=301,L]

            RewriteCond %{HTTPS} !=on
            RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
        </IfModule>
    </IfModule>
</Directory>

<Directory "/var/www/html/subdir">
    <IfModule mod_rewrite.c>
        RewriteEngine on

        <IfModule mod_ssl.c>
            RewriteCond %{HTTPS} !=on
            RewriteRule ^subdir(.*)$ https://%{HTTP_HOST}/subdir$1 [R=301,L]

            RewriteCond %{HTTPS} !=on
            RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
        </IfModule>
    </IfModule>
</Directory>

but if a user browses directly to http://www.domain.com/subdir, they get redirected to the site root (https://www.domain.com/), discarding the rest of the request path. This is the case even if I remove the whole <IfModule mod_rewrite.c> section from the subdirectory's <Directory> section and is also the case if I remove the first RewriteCond/RewriteRule pair in each config section (which we only added to try to fix this problem).

I can't see why the first rule (in either <Directory> section) isn't taking effect first, so that the user is immediately redirected to https://www.domain.com/subdir (with SSL and subdir) before mod_rewrite even gets to the second rule (in either section).

I presume I'm doing something obviously wrong (not least because Apache configuration is not my core skillset), but I just can't see it. Looking at the mod_rewrite docs and the docs on How configuration sections are merged doesn't seem to answer my question either, unless I'm reading them wrong, so I'm at a complete loss.

Can anyone see the (probably obvious) mistake I'm making?

Best Answer

Is the intent with the second RewriteRule under the subdir to send the user to the root, dropping the subdir path?

The context of the string passed to your source regex is dependent on the <Directory> context - so a request to /subdir/something.html will give the /var/www/html rules a string of subdir/something.html to match against, while the rules within /var/www/html/subdir will be matching against something.html.

You can use RewriteBase to override the context, so the config can be fixed to work as intended in one of two ways; using a RewriteBase:

<Directory "/var/www/html/subdir">
  <IfModule mod_rewrite.c>
    RewriteEngine on
    RewriteBase /
    # ... etc etc, no other changes needed

..or, by changing the destination URL to take the context into account (first rule will never match, as subdir isn't in the string):

<Directory "/var/www/html/subdir">
  <IfModule mod_rewrite.c>
    RewriteEngine on
    <IfModule mod_ssl.c>
      RewriteCond %{HTTPS} !=on
      RewriteRule ^(.*)$ https://%{HTTP_HOST}/subdir/$1 [R=301,L]
    </IfModule>
  </IfModule>
</Directory>