1

I have one application with is server over a number of domains (each customizes the appearance of the application.

In addition, there is a common domain which has multiple subdomains to display the same data as above.

So - www.apples.com appears the same as apples.efruit.co.uk

and - www.bananas.co.uk appears the same as bananas.efruit.co.uk

etc

Now, I have a wildcard ssl for the efruit.co.uk domain so I want to use the htaccess file to force all efruit.co.uk requests to use https (if not already doing so).

All other domains will not have an ssl so they will need to use http to avoid browser warnings - again from the htaccess file.

I would also like to use the htaccess file so that if someone types www.apples.efruit.co.uk it rewrites as apples.efruit.co.uk (over https as above). However, www. is fine if it's not an efruit.co.uk domain.

Finally, I then have the standard and well documented rewrite rule for codeigniter to make the url prettier.

Here's what I have so far.

Options +FollowSymlinks
RewriteEngine On

RewriteCond %{REQUEST_URI} !(health_check\.php)$
RewriteCond %{HTTP_HOST} ^(.*)\.efruit\.co\.uk
RewriteCond %{HTTP:X-Forwarded-Proto} =http
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]

RewriteCond %{HTTP_HOST} !^(.*)\.efruit\.co\.uk
RewriteCond %{HTTP:X-Forwarded-Proto} =https
RewriteRule (.*) http://%{HTTP_HOST}%{REQUEST_URI} [R,L]

RewriteCond %{HTTP_HOST} ^www\.([^\.]*)\.efruit\.co\.uk$
RewriteRule (.*) https://%1.efruit.co.uk$1 [R,L]

# block hidden directories
RewriteRule "(^|/)\." - [F]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ ./index.php/$1 [L,QSA]

The only bit that seems to work though is forcing efruit.co.uk domains to be served over https.

Tom
  • 133
  • 6
  • What's the reasoning behind the `health_check.php` URL? (Why is this check only on the first rule block?) – MrWhite Mar 01 '18 at 23:19
  • Should `efruits.co.uk` and/or `www.efruits.co.uk` be accessible? Which is canonical? (I've not specifically addressed this in my answer as yet.) – MrWhite Mar 01 '18 at 23:47
  • @MrWhite - see my comment to your answer for these points. – Tom Mar 02 '18 at 08:43

1 Answers1

1

You seem to be behind an SSL proxy(?), hence the use of the X-Forwarded-Proto request header, instead of the HTTPS server variable.

RewriteCond %{REQUEST_URI} !(health_check\.php)$
RewriteCond %{HTTP_HOST} ^(.*)\.efruit\.co\.uk
RewriteCond %{HTTP:X-Forwarded-Proto} =http
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]

Whilst you state this bit "works" ("forcing efruit.co.uk domains to be served over https"), this won't redirect the main bare domain and it will also maintain the www subdomain, if present on the request - you should strip this first to avoid a secondary redirect. So, a change in the order of these directives is required.

You also don't need a capturing group (ie. a parenthesised subpattern) unless you are intending to use this as a backreference - which you don't appear to be.

All other domains will not have an ssl so they will need to use http to avoid browser warnings - again from the htaccess file.

You can't issue an HTTPS to HTTP redirect from .htaccess in order to avoid the browser warning on these other domains - which seems to be what you are suggesting. Because the invalid SSL cert browser warning occurs before .htaccess is executed. The SSL handshake occurs at the very start of the request.

RewriteCond %{HTTP_HOST} !^(.*)\.efruit\.co\.uk
RewriteCond %{HTTP:X-Forwarded-Proto} =https
RewriteRule (.*) http://%{HTTP_HOST}%{REQUEST_URI} [R,L]

So, the above won't actually be executed from a browser, unless the user accepts the SSL cert warning (which they shouldn't).

RewriteCond %{HTTP_HOST} ^www\.([^\.]*)\.efruit\.co\.uk$
RewriteRule (.*) https://%1.efruit.co.uk$1 [R,L]

In .htaccess this would result in an invalid redirect, for anything but the document root, because the $1 backreference does not have a slash prefix. Even for the document root you should really include a trailing slash on the substitution (although the browser will implicitly fix this). Also, curious why you used the REQUEST_URI server variable in the first two rules, but used a backreference here?

Try something like the following instead:

# Prevent any fruther processing when requesting "health_check.php"
# CHECK: Absence of start of string anchor?
RewriteRule health_check\.php$ - [L]

# Remove www sub-subdomain (and redirect to HTTPS)
RewriteCond %{HTTP_HOST} ^www\.([^.]+)\.efruit\.co\.uk [NC]
RewriteRule .* https://%1.efruit.co.uk%{REQUEST_URI} [R,L]

# HTTP to HTTPS redirect for the "efruit.co.uk" domain (and subdomains)
RewriteCond %{HTTP:X-Forwarded-Proto} =http
RewriteCond %{HTTP_HOST} ^([^.]+\.)?efruit\.co\.uk [NC]
RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [R,L]

# HTTPS to HTTP redirect for none "efruit.co.uk" domains
# Note that the user will still have to click through any browser security warnings
RewriteCond %{HTTP_HOST} !(^|\.)efruit\.co\.uk
RewriteCond %{HTTP:X-Forwarded-Proto} =https
RewriteRule .* http://%{HTTP_HOST}%{REQUEST_URI} [R,L]

Other notes:

  • No need to backslash escape a literal dot when used inside a character class.
  • I've removed the $ end of string anchor on the host check in order to catch FQDN that include a trailing dot.
  • You'll probably want to change these permanent (301) redirects once you have confirmed they are working OK. ie. change R to R=301.
MrWhite
  • 11,643
  • 4
  • 25
  • 40
  • Thanks for this. I should probably have mentioned that the www. subdomain is pointing to a completely separate server so that's not going to be an issue with any of this. - Also the health_check.php is hit by the load balancer and must be over http to return a 200 response. – Tom Mar 02 '18 at 08:42
  • What about the domain apex ie. `efruits.co.uk`? I've updated my answer to redirect `efruits.co.uk` to HTTPS if requested. I've also added back the code to redirect non-`efruits.co.uk` domains back to HTTP - note, however, that this will not avoid any browser security warning. – MrWhite Mar 04 '18 at 02:33