mod_rewrite - generic www redirect

Hello,
I’m trying to configure apache modrewrite so that it would redirect non-www redirects to www subdomain (if there’s no file request)

<IfModule mod_rewrite.c>
  RewriteEngine On

  # uncomment the following line, if you are having trouble
  # getting no_script_name to work
  RewriteBase /

  ###### BEGIN special handling for the media module's cached scaled images
  # If it exists, just deliver it
  RewriteCond %{REQUEST_URI} ^/uploads/media_items/.+$
  RewriteCond %{REQUEST_FILENAME} -f
  RewriteRule .* - [L]
  # If it doesn't exist, render it via the front end controller
  RewriteCond %{REQUEST_URI} ^/uploads/media_items/.+$
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^(.*)$ index.php [QSA,L]
  ###### END special handling for the media module's cached scaled images

  # we skip all files with .something
  RewriteCond %{REQUEST_URI} \\..+$
  RewriteCond %{REQUEST_URI} !\\.html$
  RewriteRule .* - [L]

  # we check if the .html version is here (caching)
  RewriteRule ^$ index.html [QSA]
  RewriteRule ^([^.]+)$ $1.html [QSA]
  RewriteCond %{REQUEST_FILENAME} !-f


[COLOR="Red"]  # redirect to www
  # non empty HTTP_HOST in the request
  RewriteCond %{HTTP_HOST} !^$ [NC]
  # does not start with 'www'
  RewriteCond %{HTTP_HOST} !^www\\. [NC]
  # saves the value of HTTP_HOST in %1
  RewriteCond %{HTTP_HOST} ^(.*)$ [NC]
  # redirects using the saved URI (in RewriteRule) and saved hostname (in the last RewriteCond)
  RewriteRule ^(.*)$ "http://www.%1/$1" [L,R=301][/COLOR]


  # no, so we redirect to our front web controller
  RewriteRule ^(.*)$ index.php [QSA,L]
</IfModule>

The problem is that non-www request will get .html extension at the end of the url. How can I fix that // why is that happening?

I added the red colored part, the rest of the .htaccess was defined before.

Thanks for help


# redirect to www
# non empty HTTP_HOST in the request
RewriteCond %{HTTP_HOST} !^$ [NC]

Drop that, it doesn’t make sense.


# saves the value of HTTP_HOST in %1
RewriteCond %{HTTP_HOST} ^(.*)$ [NC]

You don’t need to save this, you can use %{HTTP_HOST} in the RewriteRule directly. Drop this part as well.


# redirects using the saved URI (in RewriteRule) and saved hostname (in the last RewriteCond)
RewriteRule ^(.*)$ "http://www.%1/$1" [L,R=301]

Why the double quotes? And why the use of (.*) ?


RewriteRule .? http://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Let me know how that works out :slight_smile:

Wow, thanks for this helpful info

The rewriting appears to work now but I’m experiencing some strange behavior.

If I go to domain.com from my mac it will redirect everything properly to www.domain.com (with the subpages), however if I go to domain.com on windows with FF or IE it will redirect me to www.domain.com/500.shtml and give error:

500 Server Error
A misconfiguration on the server caused a hiccup. Check the server logs, fix the problem, then try again. 

I make sure that the cache is cleared and I get the same error.

If I point my browser on a mac to the www.domain.com/500.shtml url I get the same message.

The headers appears to be okay

If I run the same .htaccess on my local environment, I get normal Not Found error - as expected.

Do you have any idea what is going on? I have no idea why is that happening.

Also, which position do you think it would be the most appropriate to put www redirect rule?
I put it before index.php execution, because it makes sense to me to first check for the cache / files. Does the position seem okay to you?

Thanks a lot for help

That’s weird. A server error should either fire or not, and should definitely not be dependent on the OS requesting the URL. Not really sure what’s going on there …

As for the rewrite to www, I always do that as the very first thing in the .htaccess (well, after any Options, RewriteEngine On, etc).

A few more pointers about your .htaccess (maybe it will solve things eh? :wink:

<IfModule mod_rewrite.c>

Do not use this. You’re asking Apache for every request if mod_rewrite is available. Check this once to see it works, and then remove the <IfModule>…</IfModule> that is burning CPU cycles for nothing.

RewriteBase /

You’re not using Alias or AliasMatch are you? If not, drop this.


###### BEGIN special handling for the media module's cached scaled images
# If it exists, just deliver it
RewriteCond %{REQUEST_URI} ^/uploads/media_items/.+$
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule .* - [L]

I would drop the .+$ at the end of the first Cond, it’s not needed. Also, I’d change .* in the Rule to .? (.* is evil)


# If it doesn't exist, render it via the front end controller
RewriteCond %{REQUEST_URI} ^/uploads/media_items/.+$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]
###### END special handling for the media module's cached scaled images

I would drop this part. You’re sending everything to the front controller at the end of this file anyway.


# we skip all files with .something
RewriteCond %{REQUEST_URI} \\..+$
RewriteCond %{REQUEST_URI} !\\.html$
RewriteRule .* - [L]

Why?


# we check if the .html version is here (caching)
RewriteRule ^$ index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]
RewriteCond %{REQUEST_FILENAME} !-f

I’m assuming the RewriteCond doesn’t belong here, but should go with the last block (i.e. the one that sends all unresolved requests to the front controller) ?


# no, so we redirect to our front web controller
RewriteRule ^(.*)$ index.php [QSA,L]

I would change that to:


RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]

It’s more efficient because it doesn’t create an unused backreference for nothing and it doesn’t send existing files to be handled by the front controller.

</IfModule>

See above