Htaccess to manage multiple domains on server

I keep putting off this problem and it’s been several years now, so I need to fix it. I am now being hosted on a VPS and have the main domain and several other domains as sub-folders. The organization is thus:

Each one of those domains should appear to be stand-alone domains, with no reference to the main domain (unless it IS the main domain). In other words, if someone types in their browser “[noparse]www.maindomain.net/number2domain[/noparse]” OR “[noparse]http://number2domain.maindomain.net[/noparse]” they should get ONLY “[noparse]http://number2domain.org[/noparse]”. If they happen to type in “[noparse]www.maindomain.net[/noparse]” they should get ONLY [noparse]http://maindomain.net[/noparse].

I have tried a number of ways in htaccess and today I found the tutorial frequently linked to and it has helped some, but I still have issues I hope someone can help with. Here is the contents of htaccess in maindomain.net:


Options +FollowSymLinks
RewriteEngine on

RewriteCond %{HTTP_HOST} !^maindomain\\.net$ [NC]
RewriteRule .? http://maindomain.net%{REQUEST_URI} [R=301,L]

This is the contents of htaccess in number1domain.com:


Options +FollowSymLinks
RewriteEngine on

RewriteCond %{HTTP_HOST} !^www\\.number1domain\\.com$ [NC]
RewriteRule .? http://www.number1domain.com%{REQUEST_URI} [R=301,L]

And this is the contents of htaccess in number2domain.org:


Options +FollowSymLinks
RewriteEngine on

RewriteCond %{HTTP_HOST} !^number2domain\\.org$ [NC]
RewriteRule .? http://number2domain.org%{REQUEST_URI} [R=301,L]

I actually have about 10 domains and they are all set up the same way. Yes, I did run the tests and the server is set up properly. But I am making some kind of mistake as described below.

Using number2domain.org as an example, this causes all calls to number2domain.maindomain.net to be redirected to [noparse]http://number2domain.org[/noparse], which is good. But the problem remains that calls to [noparse]www.maindomain.net/number2domain[/noparse] get redirected to [B][noparse]http://number2domain.org/number2domain[/noparse][/B], which doesn’t exist and causes a 404.

Any help from those who understand htaccess and mod_rewrite much better than I would be appreciated. I appreciate very much the efforts that went into that tutorial, but apparently, I am missing something - maybe parking on a dead brain cell.

Thanks,

Jim

Jim,

You’ve gotten off to a good start but don’t yet realize what the {REQUEST_URI} variable is: It is everything after the / separating the domain from the path/to/file (Apache 2.x). Therefore, the calls to the maindomain/subdomain contain subdomain as the {REQUEST_URI} so you must write code to remove that and only capture the path/to/file after the subdomain.

Okay, basically, you’re using the maindomain and allowing the subdomains to be called from the maindomain. DON’T! The subdomains should be redirecting to their own subDIRECTORY which can then strip the subdomain from the path with something like:

RewriteEngine on
RewriteCond %{HTTP_HOST} !^subdomain$ [NC]
RewriteRule ^subdomain/(.*)$ http://subdomain/$1 [R=301,L]

This should not be loopy despite the (.*) because you’re changing domains (a subdomain is technically a different domain) so this will remove the subdomain from the {REQUEST_URI}. Be sure to replace my subdomain with your real “addon” domains properly escaped (i.e., the dot characters need the \'s).

BTW, I’d redirect all the subdomains before stripping the subdomain (including www) from the maindomain which you’ve shown before other code. ORDER MATTERS so redirect any subdomain call via maindomain before doing this.

Gee, you [ noparse ]'d your links, too! I’m impressed! :tup:

Regards,

DK

I moved your last sentence to comment on first because it made me feel good I did something right. :wink: Actually, I’ve been a forum staffer on various sites since 1993, so I was just doing what needs to be done to keep things uncluttered. 'Course, I clutter it all up again by talking too much sometimes.

You’ve gotten off to a good start but don’t yet realize what the {REQUEST_URI} variable is: It is everything after the / separating the domain from the path/to/file (Apache 2.x). Therefore, the calls to the maindomain/subdomain contain subdomain as the {REQUEST_URI} so you must write code to remove that and only capture the path/to/file after the subdomain.

Okay, basically, you’re using the maindomain and allowing the subdomains to be called from the maindomain. DON’T! The subdomains should be redirecting to their own subDIRECTORY which can then strip the subdomain from the path with something like:

RewriteEngine on
RewriteCond %{HTTP_HOST} !^subdomain$ [NC]
RewriteRule ^subdomain/(.*)$ http://subdomain/$1 [R=301,L]

This should not be loopy despite the (.*) because you’re changing domains (a subdomain is technically a different domain) so this will remove the subdomain from the {REQUEST_URI}. Be sure to replace my subdomain with your real “addon” domains properly escaped (i.e., the dot characters need the \'s).

BTW, I’d redirect all the subdomains before stripping the subdomain (including www) from the maindomain which you’ve shown before other code. ORDER MATTERS so redirect any subdomain call via maindomain before doing this.

I’m pretty much lost here. Although I understand some of what you are trying to explain, I’m not sure I “get it.” I think the main problem is not knowing what the maindomain htaccess file gets, as opposed to the domain folders. I’m guessing there may not be any harm in posting my actual htaccess files.

Here is the htaccess file in my server’s public_html folder (enterprisejm.net):


Options +FollowSymLinks
RewriteEngine on

RewriteCond %{HTTP_HOST} !^enterprisejm\\.net$ [NC]
RewriteRule .? http://enterprisejm.net%{REQUEST_URI} [R=301,L]

RewriteCond %{HTTP_HOST} ^1foot.enterprisejm.net$ [OR]
RewriteCond %{HTTP_HOST} ^www.enterprisejm.net/1foot$
RewriteRule ^(.*)$ http://1footinthegrave.com/$1 [R=301,L]

RewriteCond %{HTTP_HOST} ^linomaster.enterprisejm.net$ [OR]
RewriteCond %{HTTP_HOST} ^www.enterprisejm.net/linomaster$
RewriteRule ^(.*)$ http://www.linomaster.com/$1 [R=301,L]

# more of the same for each domain

This is the htaccess in the public_html/1foot folder:


Options +FollowSymLinks
RewriteEngine On

RewriteCond %{HTTP_HOST} !^1footinthegrave\\.com$ [NC]
RewriteRule ^(.*)$ http://1footinthegrave.com/$1 [R=301,L]

# BEGIN WordPress
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# END WordPress

And here’s the public_html/linomaster folder:


Options +FollowSymLinks
RewriteEngine on

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

# BEGIN WordPress
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# END WordPress

I’m plenty confused about the (.*) atom because of what you said in your tut and now what you said here in this thread. What you see in the root domain that redirects all the folders to domains is something I had in an old file. I plugged it in just today and it does what I want it to. But that may be just on the surface. I might have some loop thing goin’ on that I don’t know about - from what you said in your tut and confuses me still.

I tried to decipher what you said above and re-wrote the htaccess files in all the domain folders to what you see above. But then, there’s that pesky (.*) again. :frowning:

Got a headache, no hair left to pull…

Jim

Hi Jim!

Okay, I guessed at that but it was still a very nice thing to see (the [ noparse ] wrapper). Not many are aware of that so maybe more will pick-up on this (as well as the [ code ] wrapper which many still won’t use).

There shouldn’t be any harm in posting your domain but I’ll alter those in case one of the mods wants you to go incognito.

There are a number of tasks you need to handle which depend on the request being made:

  1. Strip www from maindomain.net.

  2. Redirect subdomain.maindomain.net to subdomain.com (retain the path/to/file? Yes, that would be kinder to your clients’ visitors).

  3. Handle CMS redirections within the subdomains.

If you handle task #1 first (the way you were doing it), you’ll be stripping the subdomain information and will not be able to redirect to any subdomain.com.

Of course, you could match www\.maindomain\.net [NC] and redirect that to maindomain.net but you had chosen to strip them all. Pedantically, I addressed your code’s introduced problem.

Task 3 should be handled within each subdomain’s ({DOCUMENT_ROOT}) directory so that won’t be handled by maindomain.net’s .htaccess.

Therefore:

[COLOR="#808080"]Options +FollowSymLinks[/COLOR]
# You shouldn't need this as it should be in the server's conf file.
RewriteEngine on

RewriteCond %{HTTP_HOST} ^1foot[SIZE=4]\\[/SIZE].enterprisejm[SIZE=4]\\[/SIZE].net$ [N[SIZE=4]C,[/SIZE]OR]
RewriteCond %{HTTP_HOST} [COLOR="#808080"]^www.[/COLOR]enterprisejm[SIZE=4]\\[/SIZE].net/1foot$
RewriteRule ^(1foot/)?([a-z.]*)$ http://1footinthegrave.com/$2 [R=301,L]

[indent]1. Don't forget to escape your dot characters to match just a dot character.
2. Don't forget that the domain name is NOT case sensitive but your regex matches are
    ... unless you use the No Case flag.
3. IF the 1foot subdirectory was requested, you do NOT want (.*) to match that,
   too because it would be loopy. Using an optional 1foot/ should resolve that problem.
4. You are correct, I was being lazy (and wanted to capture everything in the {REQUEST_URI})
   but it's a lot safer to correctly identify that you only want lowercase letters and dot characters
   (you may want to add a / within the [...] brackets if your requests go deeper into the file structure)
   and the * is correct as there may not have been a directory or file requested.[/indent]

RewriteCond %{HTTP_HOST} ^linomaster.enterprisejm.net$ [OR]
RewriteCond %{HTTP_HOST} ^www.enterprisejm.net/linomaster$
RewriteRule ^(.*)$ http://www.linomaster.com/$1 [R=301,L]

[indent]Ditto all the above comments on this block.[/indent]

# more of the same for each domain

RewriteCond %{HTTP_HOST} !^enterprisejm\\.net$ [NC]
RewriteRule .? http://enterprisejm.net%{REQUEST_URI} [R=301,L]

[indent]Right! NOW it's time to strip any remaining subdomain from maindomain.net! Of course, all that should be left at this point is the www subdomain (or subdomains which don't exist).[/indent]

This is the htaccess in the public_html/1foot folder:


[COLOR="#808080"]Options +FollowSymLinks[/COLOR]
RewriteEngine On

RewriteCond %{HTTP_HOST} !^1footinthegrave\\.com$ [NC]
# You escaped this one AND used the No Case Flag! What happened above?
RewriteRule ^(.*)$ http://1footinthegrave.com/$1 [R=301,L]
# You duplicated the {REQUEST_URI} variable with $1. Why bother?

# BEGIN WordPress
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .[SIZE=4]?[/SIZE] /index.php [L]
# The WP people will catch on some day but you can account for the domain-only
# request with the ?. Yeah, yeah, the DirectoryIndex should give index.php anyway
# but ... what if you've used default.php or default.asp instead?
# END WordPress

Ditto for the rest of your Addon Domains (cPanel’s name for domains which are also subdomains of the maindomain within your account).

I hope I addressed the difference between the (.) and ([a-z./]+) above. The real disadvantage to the (.) is that newbies to regex will use it as a crutch to match whatever they want to match without recognizing the potential for loopy code. When someone comes here complaining that their code doesn’t work (or loops), I look first for the (.*) everytime! Using specific characters or lists, e.g., (first|second|third), is a better way as the variable MUST match not any ridiculous string of letters but EXACTLY first OR second OR third. It makes for a good security check, too!

I hope that cleared away some of the confusion I introduced (with apologies, too).

Regards,

DK

Hmmm, I think I’m beginning to understand a bit more, but I have a few more questions. It’s almost 3am here now though and it might be those questions will answer themselves if I get some sleep first. Or maybe not. I sure do appreciate your patience with me though. As many years as I have been working online, you’d think I’d know this stuff by now.

So many IT disciplines, so little time. :wink:

Talk atcha tamorrow.

Jim

Jim,

Ain’t that the truth!

See you tomorrow … just don’t wake me up early!

Regards,

DK

Hi David,

Sorry I didn’t reply back about this htaccess dilemma. I get all caught up in various projects - the last couple days it’s been a dresser I’m trying to get repurposed before the weather turns bad. And because I have to suck o2 with the help of a machine, I don’t always have the stamina to do all of the other little things in life most people take for granted. A few things get put off and some just don’t get done.

So, another day with this problem sitting on the shelf staring me in the face. I’ll try to organize my time better tomorrow (Saturday) so I can sit down with this htaccess code. Don’t worry about me waking you too early. My alarm doesn’t usually go off until 10am at the earliest. And I’m pretty slow to get rolling.

Thanks,

Jim

Jim,

Me, too (10AM) but I’m 16 clock hours ahead of you (you’re US/EDT, aren’t you?) so that’s my 2AM and I’ve just going to sleep.

No worries, too many years of hanging about here answering the odd questions and I’m not always available on a daily basis (although I try).

Regards,

DK

Pacific time zone. I live in the real Northern California. :wink:

For several years now, all new domains I create are www-less, but a few I’ve had for a long time do use www. My main domain is sans www. I’m not sure of the consequences of switching the older ones to www-less, so I’ve left them with.

  1. Redirect subdomain.maindomain.net to subdomain.com (retain the path/to/file? Yes, that would be kinder to your clients’ visitors).

And at the same time, redirect maindomain.net/subdomain/ to subdomain.com, right? This seems to be that part that has caused me the most trouble (until I discovered from your tut that it wasn’t my only trouble).

  1. Handle CMS redirections within the subdomains.

More than just the CMS’ (Content Management System for those who don’t recognize the acronym). Other website scripts and software should have their redirects and rewrites in the subdomain folder and sometimes in the subdomain’s subfolders.

Options +FollowSymLinks # You shouldn’t need this as it should be in the server’s conf file.

I was a little confused by this and am glad I can remove that from all my htaccess files.

  1. Don’t forget to escape your dot characters to match just a dot character.

Another bit of confusion: I understand why it’s important to escape the dot characters, but notice they are not escaped in the RewriteRule. So, only in the RewriteCond they get escaped?

  1. Don’t forget that the domain name is NOT case sensitive but your regex matches are … unless you use the No Case flag.

Regex is like a whole ‘nother language to me and I have never been able to figure it out. But when it’s spelled out, or I have examples, I can deal with it. In the case of case on websites, I don’t use anything but lower case, numbers, dashes and underscores. But I do have to contend with members of the forums I manage who upload files with spaces and a few odd characters once in a while. Ya just cain’t teach these kids NUTHIN’!

  1. IF the 1foot subdirectory was requested, you do NOT want (.*) to match that, too because it would be loopy. Using an optional 1foot/ should resolve that problem.

I’m pretty clear on this, but I got confused when I saw you use (.*) elsewhere.

  1. You are correct, I was being lazy (and wanted to capture everything in the {REQUEST_URI}) but it’s a lot safer to correctly identify that you only want lowercase letters and dot characters (you may want to add a / within the […] brackets if your requests go deeper into the file structure) and the * is correct as there may not have been a directory or file requested.

Bold part: You mean like [a-z./]? I’m a little confused about that.

RewriteCond %{HTTP_HOST} !^enterprisejm\\.net$ [NC]
RewriteRule .? http://enterprisejm.net%{REQUEST_URI} [R=301,L]

[indent]Right! NOW it's time to strip any remaining subdomain from maindomain.net! Of course, all that should be left at this point is the www subdomain (or subdomains which don't exist).[/indent]

So that part goes at the end of the maindomain htaccess file and is correct as written?

This is the htaccess in the public_html/1foot folder:


[COLOR="#808080"]Options +FollowSymLinks[/COLOR]
RewriteEngine On

RewriteCond %{HTTP_HOST} !^1footinthegrave\\.com$ [NC]
# You escaped this one AND used the No Case Flag! What happened above?
RewriteRule ^(.*)$ http://1footinthegrave.com/$1 [R=301,L]
# You duplicated the {REQUEST_URI} variable with $1. Why bother?

I’m sure I wrote that before I moved to my current server and picked up the code from someone who I thought knew what they were doing. I recently found out otherwise, which is partly why I went in search of better information. But he did have part of it right, apparently. :slight_smile:

You question about why I duplicated the {REQUEST_URI} variable with $1 leaves me scratching my head again. I don’t know why. My thought now is maybe I should leave {REQUEST_URI} and $1 out, as in:


RewriteEngine On

RewriteCond %{HTTP_HOST} !^1footinthegrave\\.com$ [NC]
RewriteRule ^(.*)$ http://1footinthegrave.com/ [R=301,L]

But that causes all my browsers to say it can’t find 1foot/enterprisejm.net when my hope was it would redirect to 1footinthegrave.com.

I hope that cleared away some of the confusion I introduced (with apologies, too).

Some of the info is clearer and some is still confusing, but you don’t have to apologize for that. I appreciate your long-standing efforts to teach so many of us the right way to do these things. I remember how I loved being the teacher of apprentices in my chosen profession before I had lung troubles. Most thought flooring was easy, but there are so many different variables, rules and conditions… pretty much like code, only with heavy lifting. I learned the most about being a teacher when some of my “lessons” confused the student. I miss it.

Jim

Hi Jim,

Whew! You wrote a tome!

NoCal, eh? I grew up in SoCal and worked in both LA and SD for quite a few years, too.

I prefer to use non-www’d domains but my cPanel enables the use of both (except with SSLs which I must force to www). IMHO, it makes no differrence EXCEPT to those who are not aware that the www isn’t needed (computer neophytes who merely recognize that www is for a website address).

There are two different tasks there: Redirecting the subdomain. and redirecting the /subdomain. Except for the few times when you’re sharing your maindomain’s SSL (and want to leave the subdomain’s scripts in the client’s directories, not yours), yes, you’ll want to do both. Sorry, I should have made that clear.

Yes, the Options directives should already be in the server’s configuration file (so it does not need repeating on every request). Test it, though, to be sure before removing all instances of the Options +FollowSymLinks code. It’s been so long now that I’ve actually forgotten the information I put in my signature’s tutorial about configuring Apache but, if you’re hosted, that’s all be done for you.

The dot character serves two purposes and, thus, must be handled according to its use. In regular expressions, they are metacharacters, i.e., represent ANY character, unless they are escaped (with the \). The exception to this is when the dot character is found within a character range definition (denoted by […] brackets) where it is simply the dot character. When you are using the dot character in creating a string to match (like adding .php to a {REQUEST_FILENAME}) in a RewriteCond OR in a RewriteRule’s redirection, it’s simply used as the dot character.

That seems like an awkward explanation so please ask if I’ve only caused more confusion.

There are some good “cheat sheets” out there on regex and I’ve attempted to explain much of it in my signature’s tutorial. Give it a try and ask questions if you need clarification. If an old jet jock can understand it, I’m sure you can, too.

ARGH! Spaces in filenames, er, links are displayed as %20 and, to me, that’s uglier than sin! I have to agree that “dem kidz” can’t be taught (good programming technique) but have faith that they’ll learn. Many have to learn it the hard way rather than take advantage of the bleeding we’ve done to learn this stuff but that’s their choice.

Ah! (.) is a very useful tool. Unfortunately, “dem kidz” don’t take the time to learn that EVERYTHING (or NOTHING) means exactly that! They get the match they want (because it will match EVERYTHING (or NOTHING)) including, more often than not, their redirection. Then they wonder why their code is looping. That kicked-off my series of Standard Rants! Back to (.), it’s great to capture an entire URI or specific portion of a URI but you do need to be sure that (1) the redirection isn’t loopy, (2) that any loop generated has a RewriteCond which will allow an exit from the loop and (3) that there are no security issues with the redirection (…/…/…/home/etc/pswords - okay substitute the correct name of the password file, I don’t have time to go look it up as I should).

Correct, the ([a-z./]+) will capture a path/to/file.ext and would suite your naming convention (and mine) better than (.*).

Without looking back into the depths of this message (from the Advanced reply page), yes, the code provided as just amended would do the trick for you.

I was being pedantic with the creation of $1 rather than simply .? and using the already available {REQUEST_URI} string. Six of one and half dozen of the other so it’s simply coding technique (and eliminating a ridiculously minor burden of asking Apache to duplicate a variable for you).

[COLOR="#808080"]
RewriteEngine on
RewriteCond %{HTTP_HOST} !^1footinthegrave\\.com$ [NC][/COLOR]

RewriteRule ^(.*)$ http://1footinthegrave.com/[COLOR="#0000FF"]$1[/COLOR] [R=301,L]

# is the same as

RewriteRule .? http://1footinthegrave.com%{REQUEST_URI} [R=301,L]

# which uses the already available {REQUEST_URI} string rather than creating and using $1

The gray part of the code will force any request made through that .htaccess file to be redirected to http://1footinthegrave.com (using the requested URI). It should NEVER redirect to 1foot/enterprisejm.net (in fact, if 1foot requests are delivered to this .htaccess, it will redirect that, too!).

Jim, they say that those who can, do, those who can’t, teach. I learned a LOT by being an instructor pilot (and instructors’ instructor pilot). Ditto my coming into the Apache forum years ago to ask a simple mod_rewrite question and becoming an expert by subbing for the expert while he went on vacation and being forced to answer questions members had that I’d never even considered. I did get a few things wrong over the years but attempted to correct them ASAP as I rethought and discovered new aspects of this fabulous tool.

Regards,

DK

I’m gonna keep this very short this time because I promised myself many years ago to never work on my birthday. I mostly failed at that because of greed or some other foolish reason. But I am nearly 3 years past my so-called expiration date and birthdays have extra special meaning to me now.

Anyway, I wanted to say thanks very much for being patient with me while I learned and made some mistakes. You are a real asset to SitePoint and to fledgling webmasters like me.

Best R’gards to you and yours,

Jim

Jim,

I hope you had a very happy birthday! :hbday: :Partier:

I know the feeling but with a 24 Dec birthday, I’ve NEVER worked on my birthday!

Thank you for the encouraging and kind words about my contributions here.

Regards,

DK