9

I am using the following code to direct all www requests to non-www URLs:

RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.example\.org$ [NC]
RewriteRule ^(.*)$ http://example.com/$1 [R=301,L]

This works great inside an .htaccess file in the root of my website.
For example,
www.example.com -> example.com/
www.example.com/ -> example.com/
www.example.com/other_page -> example.com/other_page

However, if I move this same code into my VirtualHost configuration, the rewritten URLs contain a double trailing slash.
www.example.com -> example.com//
www.example.com/ -> example.com//
www.example.com/other_page -> example.com//other_page

I fixed it by removing the slash from the rewrite rule:

RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.example\.org$ [NC]
RewriteRule ^(.*)$ http://example.com$1 [R=301,L]

But I can't understand the reason for this. Anyone know why?

4 Answers 4

10

As I understand it, in .htaccess files, the string that mod_rewrite processes in your rule is relative to the directory the .htaccess file is in, so it will not have a / at the start.

In the VirtualHost entry, the string it processes is absolute to the root of the server, and so includes the /.

It makes for subtle differences in how mod_rewrite works.

Here is someone with a similar problem, and solution:

http://forum.modrewrite.com/viewtopic.php?p=56322&sid=77f72967f59200b5b5de174440234c3a

This should work in both cases, assuming I remember my escaping correctly:

RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.example\.org$ [NC]
RewriteRule ^\/?(.*?)$ http://example.com/$1 [R=301,L]
4
  • Thanks! Now I understand why, at least. However, is this better for some reason than just removing the / before the $1 like I show in my original question?
    – davekaro
    Commented Jun 11, 2009 at 16:04
  • 1
    No better or worse, it is just a block that you can swap between .htaccess of VirtualHost without having to edit it each time to handle context differences. If your way works for you, stick with it! :)
    – Neobyte
    Commented Jun 11, 2009 at 16:45
  • Oh that's right - your method will work in both .htaccess and VirtualHost. That makes it better IMO :)
    – davekaro
    Commented Jun 11, 2009 at 16:50
  • 4
    I had the exact same problem as @davekaro and tried your solution. The last line didn't work for me. RewriteRule ^/?(.*)$ http://example.com/$1 [R=301,L] did the trick. Commented Jan 16, 2011 at 22:44
2

It is happening because you are capturing an initial slash with (.*) and then applying another slash before it in the new location /$1. It didn't happen before because mod_rewrite behaves slightly differently when operating in a per-directory context as opposed to a per-server context.

You could avoid this by optionally pre-empting the slash. Additionally you can use RedirectMatch in an empty VirtualHost with your surplus domains, which creates a bit less processing and can look cleaner.

<VirtualHost *>
ServerName example.com
ServerAlias other.example.com
..
RedirectMatch permanent ^/?(.*) http://example.com/$1
</VirtualHost>

1
  • Nice. I like the RedirectMatch approach. I will probably go with this since it really is a redirect that I want to accomplish.
    – davekaro
    Commented Jun 11, 2009 at 16:10
1

I'm including this post for completeness.

The Apache documentation explains why this behaviour occurs very well and is the reason that the 'RewriteBase' directive exists.

Simply including the 'RewriteBase' directive in your .htaccess file should achieve your desired result.

Example:

RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} ^www\.example\.org$ [NC]
RewriteRule ^(.*)$ http://example.com/$1 [R=301,L]

From the Apache 2.2 mod_rewrite documentation:

The RewriteBase directive explicitly sets the base URL for per-directory rewrites.

My rule of thumb is to almost always use 'RewriteBase' in .htaccess files, and not to use it in the Apache config.

0

I had no time to handle this issue so just rewrite // to / :)

RewriteCond %{THE_REQUEST} //
RewriteRule ^(.*)$ http://domain.com [R=301,L]

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .