1

I have quite a large site that consists of some regular web pages in the root and a lot of Joomla sites in folders.

So it looks a little like this:

- index.php (root)
- about.php (root)
- product.php (root)
/joomlasite1
/joomlasite2
/joomlasite3

I asked my web host to help put a redirect in the .htaccess to force https and www. But when they did this every Joomla site redirected to the root so I had to remove it.

This is the rule they put in:

RewriteEngine on
RewriteCond %{HTTPS} !=on [NC]
RewriteRule ^(.*)$ https://www.example.com/$1 [R=301,L]

Can someone suggest the best way to do this? Am I going to have to put a redirect in the root and also one in every Joomla site folder?

  • Are those Joomla sites on different domains? What code got put in that wasn't working? – Stephen Ostermiller Mar 22 '18 at 21:37
  • @StephenOstermiller they are all on the same domain. So mydomain.co.uk is the root and the Joomla sites are in mydomain.co.uk/joomlasite1 for example. I foolishly didn't save the code that the host put in but I will update the question with it if I find it. – caffeinehigh Mar 22 '18 at 21:46
  • If these are all on the same domain then what exactly do you want to force to HTTPS and what should stay on HTTP? You would normally expect to force HTTPS across the entire domain. – MrWhite Mar 22 '18 at 22:33
  • @MrWhite Sorry I should have been clearer. I want to force everything to www. and HTTPS. So the root site and all joomla sites that are in folders. – caffeinehigh Mar 22 '18 at 23:04
  • 1
    @MrWhite I have updated the original question with the rule they put in. Yes there are additional .htaccess in the /joomlasite subdirectories. – caffeinehigh Mar 23 '18 at 11:52
2

What you describe just sounds like a standard HTTP to HTTPS (and non-www to www) redirect, so it's not clear why the webhost's directives failed in the way you suggest.

However, since you would expect each /joomlasite to have its own .htaccess file that also contains mod_rewrite directives then this could well complicate matters. Although, if anything, you would expect these subdirectories to not redirect at all. (See below.)

To redirect HTTP to HTTPS and non-www to www then try the following near the top of the .htaccess file in the root of your site:

RewriteEngine On

RewriteCond %{HTTPS} !on [OR]
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^ https://www.example.com%{REQUEST_URI} [R=302,L]

Make sure you clear your browser cache before testing.

This also assumes the SSL cert is installed on your server and you are not using an SSL front-end proxy to manage your SSL.

Note that this is a 302 temporary redirect. Only change it to a 301 permanent redirect when you are sure it's working OK. 301s are cached hard by the browser, so can make testing problematic.


UPDATE: If you wanted a more generic solution that doesn't involve hardcoding the domain then you can do something like the following instead:

RewriteCond %{HTTPS} !on [OR]
RewriteCond %{HTTP_HOST} !^www\.
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)\.?$ [NC]
RewriteRule ^ https://www.%1%{REQUEST_URI} [R=302,L]

This is very similar to the above, except with an additional RewriteCond directive, which is required in order to capture the domain apex from the Host header.

A generic solution isn't necessarily the "best solution". (Although it might be.) In the infinite world of varying server configs, hardcoding the domain name is often going to be the most reliable solution.


However, this may not do anything for the subdirectories that contain their own .htaccess files (if these files also contain mod_rewrite directives). If this is the case then you will either need to repeat the above directives in each subdirectory's .htaccess file, or enable mod_rewrite inheritance by either placing the following directive in each subdirectory's .htaccess file:

RewriteOptions InheritBefore

Or, on Apache 2.4.8+, you can instead include the following directive in just the root .htaccess file:

RewriteOptions InheritDownBefore

But whether the mod_rewrite inheritance is successful without modifying existing directives is dependent on what other directives you have in the parent .htaccess file.

mod_rewrite inheritance is not trivial. Directives are literally copied in-place. So, if you have per-directory directives that are dependent on the relative file-path then these can break. (This is primarily why I have used REQUEST_URI in the directive above, rather than capturing the URL-path from the RewriteRule pattern.) So, the easiest solution - without knowing more about your system - may be to simply copy the redirect directives (above) into each sub .htaccess file.


UPDATE:

This is the rule they put in:

RewriteEngine on
RewriteCond %{HTTPS} !=on [NC]
RewriteRule ^(.*)$ https://www.example.com/$1 [R=301,L]

If these directives were used in the .htaccess file in the document root of your site and mod_rewrite inheritance was also enabled (as described above), then this would indeed exhibit the behaviour you were seeing, ie. everything in /joomlasite is redirected to the root. eg. http://www.example.com/joomlasite/foo would get redirected to https://www.example.com/foo in the root - the /joomlasite directory is effectively "lost".

This is because the inherited directives are copied in-place (as mentioned above). If these directives are run in the context of the .htaccess file in the /joomlasite subdirectory then the URL-path captured by the RewriteRule pattern (and later used in the $1 backreference) would be foo, not joomlasite/foo, because the directory-prefix (of where the .htaccess file is located) is first removed from the URL-path. This then results in a substitution of the form https://www.example.com/foo.

However, the directives I posted earlier, that use REQUEST_URI instead of $1, get around this issue since REQUEST_URI always contains the full URL-path of the request.

  • 1
    I've updated my answer explaining why this might have failed with the original code the webhost provided (which has since been added to the question). Have you tried my code suggestion? This should be exempt from this unwanted behaviour. This also canonicalises the www part of the URL, which the webhost's code did not (unless this was implemented as another rule?). – MrWhite Mar 23 '18 at 14:05
  • Yes I tried your suggestion thanks! However it gave me a redirect loop. Presuming this is some sort of server configuration issue that stopped it working. The one in my answer below however does work. However I am unclear why this works. – caffeinehigh Apr 8 '18 at 19:58
  • 1
    OMG! I've just noticed a typo in my answer/code (now corrected). The first RewriteRule should have read RewriteCond! Ooops, sorry! (The second RewriteRule would have indeed resulted in an unconditional redirect loop!) – MrWhite Apr 9 '18 at 16:45
  • I've updated my answer to include a generic solution that doesn't require a hardcoded domain. – MrWhite Apr 9 '18 at 23:45
0

Thank you for the thorough explanation @MrWhite. I have one question. When I tried to implement your code I got an infinite redirect loop. I looked at alternatives and this one below worked. Just curious why the two would differ? Is there some sort of server config that would cause it?

RewriteEngine On


# Redirect HTTP with www to HTTPS with www
RewriteCond %{HTTPS} off
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [R=302,L]
# Redirect HTTP without www to HTTPS with www
RewriteCond %{HTTPS} off
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule .* https://www.%{HTTP_HOST}%{REQUEST_URI} [R=302,L]
# Redirect HTTPS without www to HTTPS with www
RewriteCond %{HTTPS} on
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule .* https://www.%{HTTP_HOST}%{REQUEST_URI} [R=302,L]
  • If you excuse the typo that I had in my code suggestion/answer (now corrected!) then this is actually exactly the same (just more convoluted). In fact, the code you posted here isn't strictly correct as you shouldn't be using the NC flag on the negated CondPatterns (ie. !^www\. [NC]), only on the first rule block - although that makes no difference to the outcome for normal requests. – MrWhite Apr 9 '18 at 16:50
  • Thank you! I'm going to give your solution a try again as it is simpler than the alternative I found here. Is there any advantage / disadvantage of writing the domain in against using HTTP_HOST for the RewriteRule? – caffeinehigh Apr 9 '18 at 21:52
  • 1
    The HTTP_HOST server variable contains the value of the Host HTTP request header, ie. whatever hostname the user has used on the request (eg. www or non-www). Hardcoding the domain and using HTTP_HOST are not necessarily the same thing. In the code example in my answer, you will need to hardcode the domain, otherwise you will get a redirect loop when specifiying the bare domain. With the enormous variety of server configs, hardcoding the domain is always going to be the most reliable. However, I'll update my answer to include a generic solution that doesn't require a hardcoded domain. – MrWhite Apr 9 '18 at 23:26

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.