Forum Moderators: phranque
I've been struggling with a rewrite issue for a few days now and I'm stumped, hope I can get some help here.
My work wants to use wildcard DNS so that we can have people sign up for an automatically generated site. Their domain would be something like subdomain.example.com. Now I have a redirect working which grabs the subdomain and delivers the index page with the domain appended in the query string. This value would then later be used in a database to get their specific information. The issue I'm having is with the CSS and JS files. The template were using tries to find the CSS / JS files on the sub domain, obviously they dont exist so I'm just getting an un-styled page.
I've been trying to find a way to use .htaccess to redirect the requests for CSS / JS file to the root domain (example.com). Here is the current rule I've been trying (with no success)
########## Begin - Repoint CSS / JS Requests
#RewriteCond %{HTTP_HOST} ^([^.]+)\.example\.
#RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /templates/([^/]+)/(css¦js)/([^.]+)\.(css¦js) [NC]
RewriteRule ^(.*)$ http://example.com/templates/%1/%2/%3.%4 [L]
########## End - Repoint CSS / JS Requests
The first two conditions I have commented. I found this approach on a forum and attempted to adapt it for my use here.
Thanks for any help
Jim
Does anyone have any suggestions of what I can do?
If the css and js files are in or below root, and all subdomains are mapped to /www/ as their DocumentRoot, then this should work, and the subdomain in the requested hostname is irrelevant.
So look at the filepaths to which the server is trying to resolve these css and js URLs, as shown in the server error log. It's usually immediately obvious what the problem is.
Jim
########## Begin - Repoint CSS / JS Requests
RewriteCond %{HTTP_HOST} ^([^.]+)\.example\.
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /([^.]+)/(.*)\.(css¦js¦png¦jpg¦flv¦swf¦gif¦xml) [NC]
RewriteRule ^(.*)$ /home/blue/public_html/%1/%2.%3 [S=1]# SPECIAL rule for files that don't fit into the genic rule above
RewriteCond %{HTTP_HOST} ^([^.]+)\.example\.
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /demo\.css [NC]
RewriteRule ^(.*)$ /home/blue/public_html/demo.css
########## End - Repoint CSS / JS Requests
and it seems to be working. I'm a bit annoyed that I had to have a special rewrite just for this one CSS that isn't with the rest of its buddies in this template, but oh well (I'm a bit of a perfectionist like that). Images are all coming in or so it seems. I'll be going over the site a bit more in details to see if there are any issues or anything broken.
Also, correct me if I'm wrong here, but the [S=1] on the first rewrite rule should cause it to ignore the next rewrite block (the one for the demo.css), correct? I just started working with .htaccess about 4 hours ago and so far I like it, bit complex off the bat, but very useful.
Also, don't use ".*" unless that's really what you want: Everything, anything, or nothing. This is a maximally-greedy and promiscuous pattern. And really, really try to avoid ever using more than one ".*" subpattern in a pattern -- It forces many, many, many "back-off-and-retry" matching attempts.
I doubt that you need "[S=1]" here, as [L] is the most appropriate end-flag in almost all circumstances.
Get in the habit of ending all rules with [L] for the sake of efficiency, and always order your rules with your external redirects first, in order from most-specific patterns and conditions to least-specific, followed by your internal rewrites, again in order from most-specific patterns and conditions to least-specific. This may save you untold hours of grief by avoiding unexpected rewrite behavior and exposure of internal filepaths as URLs.
Note that parentheses can be nested: Count left parentheses to resolve back-references.
Distilling all of that, your rules will look like this:
# Rewrite demo.css to subdirectory
RewriteCond %{HTTP_HOST} ^[^.]+\.example\.com
RewriteRule ^demo\.css$ /home/blue/public_html/demo.css [L]
#
# Rewrite CSS, JS, media, and XML requests to subdirectory
RewriteCond %{HTTP_HOST} ^[^.]+\.example\.com
RewriteRule ^([^/]+/[^.]+\.(css¦js¦png¦jpg¦flv¦swf¦gif¦xml))$ /home/blue/public_html/$1 [L]
Jim
I gave those patterns a try and they didn't work. The reason for the .* sub pattern (I'm not new to Regex, not a pro, but not new) is because some of the files are something.somethingelse.extension so doing something like [^.]+ wouldn't catch those particular items. If you know of a better way to match these I'd be all... well eyes I guess, it is a forum ;-)
I do wonder if you can clear something up for me, I've not been able to really tell what the first portion of a RewriteRule statement is matching the regex against. For instance you're using the patterns as the regex in the RewriteRule statement and only using a RewriteCond to ensure that the requset is coming from a sub domain. Now this approach makes sense to me as less conditions means less work for the server and faster load times, so I'll try to implement it with my working pattern, but I've never used the regex in the RewriteRule section is actually matching against. Can you shed some light on that for me?
Thanks for explaining the orders for rewrites to occur. I hadn't thought that far into my .htaccess yet, was still focused on getting a good solution for my issue.
The RewriteRule pattern in .htaccess or within a <Directory> container in a server config file matches against the localized URL-path.
Starting with a URL of "http://example.com.:80/dir/subir/x.y.php#anchor?name=value", the URL-path is "/dir/subir/x.y.php" -- Note that the protocol, hostname, port number, URL-fragment identifier, and query string are not part of the URL-path.
The localized URL-path depends on the directory specified in the <Directory> container, or on the location of the .htaccess file with this code in it. For example, if the .htaccess file is located in your Web root directory (where your robots.txt and 'home page' would also normally be located), then the local URL-path for the URL cited above would be "dir/subir/x.y.php".
If the .htaccess file is in /dir, then the localized URL-path would be "subir/x.y.php", and if it is located in /dir/subdir, then just "x.y.php". So the RewriteRule pattern needs to change depending on the code location, but in no case starts with a slash.
On the other hand, when RewriteCond looks at REQUEST_URI, it's looking at the full URL-path, as is RewriteRule when located in a server config file, but *not* within any <Directory> container.
Clear as mud?
Jim
If I'm understanding you correct, assuming I have my .htaccess in the /www/ folder for the domain (servers path is /home/blue/www/...) and I'm say trying to rewrite all .htm files to .php I'd do...
RewriteRule ([^.]+)\.htm $1.php
RewriteRule ([^/]+)+/([^.]+)\.html $1/$2.php
I've got this going on, which works for subodmain.example.com/administrator pointing back to example.com/administrator; the rest however eludes me.
########## Begin - Administration redirect
RewriteCond %{HTTP_HOST} ^([^.]+)\.example\.
RewriteCond %{REQUEST_URI} /administrator
RewriteRule ^administrator/(.*)$ http://example.com/administrator/$1 [R,L]
########## End - Administration redirect
This does not address the /admin section of my question from eathier a sub domain or the root domain.
If I'm understanding you correct, assuming I have my .htaccess in the /www/ folder for the domain (servers path is /home/blue/www/...) and I'm say trying to rewrite all .htm files to .php I'd do...RewriteRule ([^.]+)\.htm $1.php
That would obviously only work for files that are also in the root directory, if I were to say have a file in a sub directory...
In fact it would 'harder' to make this *not* work for subdirectories, because you'd have to exclude slashes as well as periods. And because 'directory names' in the URL could contain periods followed by "htm", this rule is deficient in several respects (mostly due to lack of anchoring).
Your second rule:
RewriteRule ([^/]+)+/([^.]+)\.html $1/$2.php
That's better, but could be improved a bit, especially for security:
# Rewrite any .html page URL in any directory to /page-dir/page-name.php
RewriteRule ^(([^/]+/)*[^.]+)\.html$ /$1.php [L]
...or for only root-directory page requests:
# Rewrite any .html page URL requests in root to /page-name.php
RewriteRule ^([^/.]+)\.html$ /$1.php [L]
As for this code...
########## Begin - Administration redirect
RewriteCond %{HTTP_HOST} ^([^.]+)\.example\.
RewriteCond %{REQUEST_URI} /administrator
RewriteRule ^admin/(.*)$ http://example.com/administrator/$1 [R,L]
########## End - Administration redirect
# Redirect subdomain.example.com and example.com /admin/<whatever> requests
# to example.com/administrator/<whatever>
RewriteCond %{HTTP_HOST} ^([^.]+\.)?example\.com
RewriteRule ^administrator/(.*)$ http://example.com/administrator/$1 [R=301,L]
# Redirect subdomain.example.com and example.com /admin/<whatever> or /admin
# requests to example.com/administrator<whatever>
RewriteCond %{HTTP_HOST} ^([^.]+\.)?example\.com
RewriteRule ^admin(/.*)?$ http://example.com/administrator$1 [R=301,L]
Jim
Also, I do include the .com, the owners of the company I work for are a bit paranoid, hence why I change the domain to .example and leave out the .net/.com etc, they think it'll make it harder for someone "evil" to find it.
Can you suggest any reference I can go over to broaden my horizons? I'm probably going to end up writing a few .htaccess files for some of our older sites and I'd prefer to not have to bug you guys all the time ;-)
Yes the RewriteRule is conditional, based on its pattern matching the requested URL-path. And RewriteRule does not check anything about *files* -- It looks at URL-paths only (big difference, there).
No, the pattern in the rule is matched only with the URL-path. For the client-requested URL "http://www.example.com/dir/index.php#named-anchor?name=value", only "dir/index.php" will be tested by the RewriteRule pattern -- if any other parts need to be tested, use a RewriteCond examining the appropriate server or request variable.
For more information, see the Apache mod_rewrite documentation and the Apache URL Rewriting Guide as a start.
Jim