Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

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?

share|improve this question
add comment

4 Answers

up vote 5 down vote accepted

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]
share|improve this answer
    
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 Jun 11 '09 at 16:04
    
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 Jun 11 '09 at 16:45
    
Oh that's right - your method will work in both .htaccess and VirtualHost. That makes it better IMO :) –  davekaro Jun 11 '09 at 16:50
2  
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. –  Kenny Rasschaert Jan 16 '11 at 22:44
add comment

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>

share|improve this answer
    
Nice. I like the RedirectMatch approach. I will probably go with this since it really is a redirect that I want to accomplish. –  davekaro Jun 11 '09 at 16:10
add comment

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.

share|improve this answer
add comment

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

RewriteCond %{THE_REQUEST} //
RewriteRule ^(.*)$ http://domain.com [R=301,L]
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.