Forum Moderators: phranque

Message Too Old, No Replies

Trouble settings up multiple rewrites

         

smithaa02

7:54 pm on May 18, 2007 (gmt 0)

10+ Year Member



Here is basically my situation:

I have one site with multiple aliases.

I want each alias to redirect to its special subdirectory.

I want all aliases to add the www subdomain if it isn't already present.

If an alias is already on a subdirectory or file, there is no need to redirect it.

So to start, I add the www subdomain to the main domain and this works fine:

RewriteEngine On
RewriteCond %{HTTP_HOST} ^maindomain\.com [nc]
RewriteRule (.*) [maindomain.com...] [R=301,L]

Then I add the www to my first alias and this seems to work fine:

RewriteCond %{HTTP_HOST} ^alias1\.com [nc]
RewriteRule (.*) [alias1.com...] [R=301,L]

I then setup a redirect for the alias to go to its home directory and this is where I get into trouble:

RewriteCond %{HTTP_HOST} www\.alias1\.com [nc]
RewriteRule (.*) [alias1.com...] [R=301,L]

I get an error that states:

Firefox has detected that the server is redirecting the request for this address in a way that will never complete. (although the URL at the top redirect correctly).

Any idea of what could cause this?

g1smd

9:02 pm on May 18, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



You must avoid a redirection chain.

Wherever you start you need to get to the final destination in just one move.

You also need to do the most specific redirects first.

jdMorgan

9:07 pm on May 18, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



There's nothing in your code to stop recursion, which is why that's happening.

Also, I think you'll be happier using an internal rewrite, as opposed to an external redirect, for the second step. This avoids 'exposing' your alias subdirectory URLs to visitors and search engines.

Let's simplify the www-prefix into a single rule, and make up for it with a bit of complication in the second rule: :)


RewriteEngine On
#
# Externally redirect to prefix www subdomain if missing
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule (.*) http://www.%{HTTP_HOST}/$1 [R=301,L]
#
# Internally rewrite alias domains to subdirectories, but only if not previously done
RewriteCond %{ENV:RewriteDone} !^True$ [NC]
RewriteCond %{HTTP_HOST} !^www\.maindomain\.com [NC]
RewriteCond %{HTTP_HOST} ^www\.([^.]+)\.com [NC]
RewriteRule (.*) /alias1homedir/$1 [E=RewriteDone:True,L]

The second rules tests an environment variable to assure that it only executes once. It won't match initially, because it will be undefined and return a value of "(none)". So the rule will be invoked. But the rule then sets the value to "True" and therefore disables itself for the next pass. The name of this variable is arbitrary; Call it whatever you like as long as it doesn't conflict with any pre-existing server variable names.

Details: The [L] flag stops mod_rewrite processing only for the current pass through .htaccess. However, mod_rewrite will be re-invoked if any URL rewrites are performed, in order for the newly-rewritten URL to be checked for further rewrites or for any access restrictions that may now apply. Therefore, mod_rewrite code in .htaccess behaves as if it were recursive, and you must take explicit steps to stop potential loops.

Jim

[edited by: jdMorgan at 9:09 pm (utc) on May 18, 2007]

smithaa02

9:33 pm on May 18, 2007 (gmt 0)

10+ Year Member



jdMorgan,

The first part to add 'www' to all domains worked perfectly.

However, when I added in the second part, I got a 'Internal Server Error' page whenever I tried to use any of the aliases. Am I missing something?

Also how would I set this up for multiple aliases? I have 4 aliases total, 2 go to one directory and the other 2 go to another directory. Is there a way to implement this with your solution?

jdMorgan

9:59 pm on May 18, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Sorry, forgot to finish coding-in the multiple aliases:

# Internally rewrite alias domains to subdirectories, but only if not previously done
RewriteCond %{ENV:RewriteDone} !^True$ [NC]
RewriteCond %{HTTP_HOST} !^www\.maindomain\.com [NC]
RewriteCond %{HTTP_HOST} ^www\.([^.]+)\.com [NC]
RewriteCond %{DOCUMENT_ROOT}/%1dir -d
RewriteRule (.*) /[b]%1dir[/b]/$1 [E=RewriteDone:True,L]

Here the alias-domain-directory names are <alias-domain> + "dir". So www.example.com/index.html would reside in /exampledir/index.html.

The fourth (newly-added) RewriteCond is optional. It makes sure the subdirectory exists before rewriting to it.

As to your server error, I'm using this same code on a live server, so look at your server error log. It will help you find the problem -- or if you can't find the problem, it will help us find it if you post the info here.

Jim

[edited by: jdMorgan at 3:03 pm (utc) on May 20, 2007]

smithaa02

2:06 pm on May 21, 2007 (gmt 0)

10+ Year Member



Here is what I found in my error log:

------------------------------------------------------
[Mon May 21 09:02:03 2007] [error] [client ip.ip.ip.ip] mod_security: Access denied with code 403. Pattern match "!(^$¦^application/x-www-form-urlencoded$¦^multipart/form-data)" at HEADER("Content-Type") [msg "Only accept request encodings we know how to handle. group 1009"] [hostname "maindomain.com"] [uri "/instmsg/aliases/mail"]
[Mon May 21 09:02:04 2007] [error] [client ip.ip.ip.ip] mod_security: Access denied with code 403. Pattern match "!(^$¦^application/x-www-form-urlencoded$¦^multipart/form-data)" at HEADER("Content-Type") [msg "Only accept request encodings we know how to handle. group 1009"] [hostname "www.maindomain.com"] [uri "/403.shtml"]
------------------------------------------------------

It looks like mod_security is making a mess of things then?

jdMorgan

2:43 pm on May 21, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Possibly... But that is a 403-Forbidden response warning shown in the error log snippet, and not a 500-Server Error.

It also shows a 403-Forbidden error in response to an attempt to serve the custom 403-Forbidden error page -- In other words, the initial 403 caused a second 403, because a bug in the access-control code (I don't know where) caused the 403 page itself to be 'protected', so this causes a cascade of 403 errors. Now that might lead to a 500-Server Error; You'll be able to tell if you see more of these errors logged all in a row.

Try to correlate the error log with the access log by time stamps, and be sure that there were only those two 403 errors you posted from the error log. This information is important in identifying the problem.

Also look through all of your config and .htaccess files, and make sure that if there any mod_access, mod_alias, or mod_rewrite directives that forbid access, that they contain provisions so that access to the 403.shtml page are never forbidden under any circumstances -- By the way, I suggest the same exclusion for your robots.txt file (if you have one).

I'm not sure I'll be able to help with this problem much further, but with the additional information gathered as described above, you should at least be able to ask your host for help in a very specific way. Or maybe someone reading this thread has seen something like this and can help.

Jim

smithaa02

9:37 pm on May 21, 2007 (gmt 0)

10+ Year Member



I verified that mod_security is not the problem. Now when I test an alias, I get 2 identical errors in my error log right away and nothing else:

Request exceeded the limit of 20 internal redirects due to probable configuration error. Use 'LimitInternalRecursion' to increase the limit if necessary. Use 'LogLevel debug' to get a backtrace.

Now here is a possible culprit... I run a CMS called Drupal that requires the following directive at the end of the .htaccess file:

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

Could this, in addition to the code you provide me earlier, be causing the infinite recursion?

smithaa02

9:50 pm on May 21, 2007 (gmt 0)

10+ Year Member



I just moved the code you provide to the end of the .htaccess file (past Drupal's url rewriting) and that got rid of the infinite recursion.

Unfortinitly this has created a new problem, because I needed that Drupal rewrite section to go first because the URL I'm redirecting to uses a Drupal Alias. Basically how Drupal works is it rewrites everything to index.php?q=, so /example.html becomes index.php?q=example.html. And this seems to be my problem... Is there a way to ensure the drupal rewrite only runs once as well? Here it is again:

# Rewrite current-style URLs of the form 'index.php?q=x'.
RewriteCond %{REQUEST_FILENAME}!-f
RewriteCond %{REQUEST_FILENAME}!-d
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]

jdMorgan

9:50 pm on May 21, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



No, that code only rewrites if the requested URL-path does not exist as a file or directory; as long as index.php exists, it shouldn't loop.

Is there a filepath associated with that recursion error, in either the error log or the access log (correlated by timestamp)?

Jim

smithaa02

1:44 pm on May 22, 2007 (gmt 0)

10+ Year Member



Well I've actually gotten rid of that error by using index.php in my URL rewrites. So I have now:

RewriteCond %{ENV:RewriteDone}!^True$ [NC]
RewriteCond %{HTTP_HOST}!^www\.maindomain\.com [NC]
#RewriteCond %{HTTP_HOST} ^www\.([^.]+)\.com [NC]
RewriteCond %{HTTP_HOST} www\.alias1.com$ [NC]
#RewriteRule (.*) /alias1directory/alias1page.htm [E=RewriteDone:True,L]
RewriteRule (.*) index.php?q=/node/1/view [E=RewriteDone:True,L]

Drupal then kicks in their code as usual:

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

And this almost works correctly. No error messages, but whenever I type in www.alias1.com with any subdirectories or files (eg alias1.com/info.htm) it gets redirected when it should not be. Can I ensure that only a host with name of alias1.com with no subdirectories or files gets the rewrite treatment to the special splash page?

The second issue is that while the correct page is coming up, all the images are broken. Can I ensure that my rewrites won't affect my other included paths on my splash page (images, css, and javascript)?

jdMorgan

2:05 pm on May 22, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



You can add RewriteConds to the code to exclude your various conditions by using the "!" NOT operator on the pattern.

As to the broken images, again, you can exclude various filetypes using a RewriteCond checking %{REQUEST_URI} or %{REQUEST_FILENAME}. An alternative is to link to those included objects using server-relative links instead of page-relative links, that is, <img src="/images/logo"> instead of <img src="images/logo">. It helps to clarify this if you remember that it is the client (e.g. browser or robot) that resolves relative links, based upon the current page URL that it is using, generating the canonical URL for the object.

Jim

smithaa02

6:33 pm on May 22, 2007 (gmt 0)

10+ Year Member



It was a bit messy, but I finally got a solution. I added the following for each of my domain aliases and that seemed to do the trick:

RewriteCond %{ENV:RewriteDone1}!^True$ [NC]
RewriteCond %{HTTP_HOST}!^www\.maindomain\.com [NC]
RewriteCond %{HTTP_HOST} www\.alias1\.com$ [NC]
RewriteCond %{REQUEST_FILENAME}!sites [NC]
RewriteCond %{REQUEST_FILENAME}!css [NC]
RewriteCond %{REQUEST_FILENAME}!js [NC]
RewriteCond %{REQUEST_FILENAME}!\.htm [NC]
RewriteCond %{REQUEST_URI}!contact [NC]
RewriteCond %{REQUEST_URI}!index\.php [NC]
RewriteCond %{REQUEST_URI}!user [NC]
RewriteCond %{REQUEST_URI}!admin [NC]
RewriteCond %{REQUEST_URI}!files [NC]
RewriteRule (.*) index.php?q=/node/1/view [E=RewriteDone1:True,L]

I really appreciate all your help Jim.

jdMorgan

6:52 pm on May 22, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Remember, you can combine those using the local OR operator:

RewriteCond %{REQUEST_FILENAME} !\.(css¦js¦html?)$ [NC]

It shows in these forums as a broken pipe "¦" character, but you need to replace it with a solid pipe from your keyboard before trying to use it.

Note that "html?" matches either "htm" or "html" -- The question mark is a quantifier that makes the preceding character optional.

Jim