What follows is what I consider to be best practice for my personal sites and a guide for those who wish to do the same. Months ago I dropped the www.
prefix from my domain in part because I think it’s redundant and also because I wanted to experiment with how Google treated valid HTTP redirect codes. The experiment has been a great success. Google seems to fully respect 301 Permanent Redirects and the change has taken my previously split PageRank has been combined and now I am at 7. There are other factors that have contributed to this, of course, and people still continue to link to my site and posts with a www.
(or worse) in front of it, but overall it just feels so much cleaner to have one URI for one resource, all the time. I’m sure that’s the wrong way to say that, but the feeling is there nonetheless.
Now for the meat. What’s a good way to do this? Let’s look at our goals:
- No links should break.
- Visitors should be redirected using a permanent redirect, HTTP code 301, meaning that the address bar should update and intelligent user agents may change a stored URI
- It should be transparent to the user.
- It should also work for mistyped “sub domains” such as
ww.
orwwww.
(I still get hits from Carrie’s bad link)
So we need a little magic in DNS and in our web server. In my case these are Bind and Apache. I am writing about this because at some point the code I put in to catch any subdomain stopped working and while I reimplemented it I decided to write about what I was doing. This method also works with virtual hosts on shared IPs where my previous method did not.
In Bind you need to set up a wildcard entry to catch anything that a misguided user or bad typist might enter in front of your domain name. Just like when searching or using regular expressions you use an asterisk (or splat) to match any number of any characters the same thing applies in Bind. So at the end of my zone DB file (/var/named/photomatt.net.db
) I added the following line:
*.photomatt.net. 14400 IN A 64.246.62.114
Note the period after my domain. The IP is my shared IP address. That’s all you need, now restart bind. (For me /etc/init.d/named restart
.)
Now you need to set up Apache to respond to requests on any hostname under photomatt.net. Before I just used the convinence of having a dedicated IP for this site and having the redirect VirtualHost entry occur first in my httpd.conf
file. That works, but I have a better solution now. So we want to tell Apache to respond to any request on any subdomain (that does not already have an existing subdomain entry) and redirect it to photomatt.net. Here’s what I have:
<VirtualHost 64.246.62.114>
DocumentRoot /home/photomat/public_html
BytesLog domlogs/photomatt.net-bytes_log
ServerAlias *.photomatt.net
ServerName www.photomatt.net
CustomLog domlogs/photomatt.net combined
RedirectMatch 301 (.*) http://photomatt.net$1
</VirtualHost>
The two magic lines are the ServerAlias
directive which is self explanitory and the RedirectMatch
line which redirects all requests to photomatt.net in a permanent manner.
There is a catch though. The redirecting VirtualHost
entry must come after any valid subdomain VirtualHost
entries you may have, for example I have one for cvs.photomatt.net
and I had to move that entry up in the httpd.conf
because Apache just moves down that file and uses the first one it comes to that matches, so the wildcard should be last.
That is it, I’m open to comments and suggestions for improvement.
I’m glad I know a guy like you. Because I don’t understand a damn thing you just wrote and I’m glad there are people who do.
LOL
well as one who does understand what was written. I can appreciate Cody’s comment. I can’t really talk tech like this to my friends without them getting cross-eyed either.
Well hopefully someone appreciated it. Maybe I should tone down some of the posts.
No! Write whatever motivates you to write. Don’t go changin’.
Hey, I’m looking to do something just like this but with one critical difference. I do not want the address basr updated, because I need to look at the original request and respond intelligently in my application code to the subdomain requested. Is there a way to change the VirtualHost directive so it will behave how I want?
Thanks.
I want to do basically the same thing you are describing but with one critical difference. I don’t want to change the address in the address bar because I need to respond intelligently in my application based on the original subdomain requested. Basically, I don’t want to use it to capture mistyped subdomains but instead to maintain virtual subdomains without having to create individual virtual hosts and dns entries for each.
Do you know how I might do this?
Is this line correct? It did not work for me.
*.photomatt.net. 14400 IN A 64.246.62.114
This worked for me, i added it after all the other stuff in the zone file:
* A 123.45.67.89
Is that bad, or is there a reason for all the other stuff in the first line?
oops, i meant * IN A 123.45.67.89
DUH, i forgot the period after the domain. never mind
Georg: don’t feel bad, that’s a pretty common problem. Glad to hear it worked out for you.
Thanks. This helped deduce a solution to redirecting .net requests to .com. Searched forever til I found this. Nice work.
Hi Matt, great info on how to redirect http://www.domain.com to domain.com – but I’m not sure how to do it the other way — I want to have my websites do a 301 redirect from domain.com to http://www.domain.com (for some reason, I like that way better). Here’s the difficult part – I also use wildcard subdomains (handled by a CGI script to offer up the appropriate content) and don’t want those to be 301 redirected – just domain.com to http://www.domain.com. Any ideas? I’m taking a guess below with this example:RedirectMatch 301 http://domain.com(.*) http://www.domain.com$1Would that work? I’m always paranoid about messing around with server config files…Thanks!-Jake
Oops, let me try to put the example on its own line:
RedirectMatch 301 http://domain.com(.*) http://www.domain.com$1
…would that work for what I want to do in #12 above?
I was just trying to do the same thing…but it seems that I don’t have access to the httpd.conf on my shared hosting plan. Any idea what to do…?
It works! Exactly what I needed. – Thanks
I have been looking in to having wildcard domains on my site. But I have a question about this method. Will this actually change the URL in the browser? I need the URL in the addressbar to stay on the wildcard subdomain. What I would like it for the 404 page to be displayed on the screen but the URL in the address bar to remain on the ‘incorrect’ subdomain.
Thanks,
James
Hi,
My hosting-company offers cPanel to manage your web site, but I don’t have access to the httpd.conf nor to the DNS settings. When I visit xx.domain.nl, I get a standard cPanel-page that tells me: “There’s no website configured at this address”. Is it possible to redirect all those requests to the main domain? (probably with .htaccess)
Hey!
I have been looking for how to do this for a while with CPanel, and your instructions worked!
Thanks!
One note for me though, I didn’t need the RedirectMatch 301 (.*) http://photomatt.net$1 line to make it work, it worked with just adding *.hl2x.com. to the DNS zone, and the *.hl2x.com to the server alias in the httpd.conf file. Restarted the services, and it worked! Thanks again!
-Bizzar
This is great info Matt!! Thanks for helping all us numbskulls!
I have a question that is much like Scott’s above, but unfortunately I don’t think he completed the thought and I was not able to contact him directly to confirm.
He wrote:
*****************************************************
I want to do basically the same thing you are describing but with one critical difference. I don’t want to change the address in the address bar because I need to respond intelligently in my application based on the original subdomain requested. Basically, I don’t want to use it to capture mistyped subdomains but instead to maintain virtual subdomains without having to create individual virtual hosts and dns entries for each.
*****************************************************
I would like to extend the question to add: parse the subdomain out of the request (as sent to the webserver) then search a database for a match on the subdomain string. If a match is found, use that string as the user key and programmatically rebuild a replicated webpage for that user, populating all the fields with the data which that user has previously entered.
This is a critical function I am looking for. If anyone can do this, I would like to further correspond with you.
mas222: This is what I did to accomplish your extended question. I used .htaccess to forward all the subdomain to one particular folder “members” within my public_html folder. I then use php to parse out the subdomain and then do a query in my database to verify if it’s a valid user or not. If it’s a valid user, do the other query stuff else displays an error or the default domain page.
Here’s my code to get the subdomain name:
pretty simple, good luck
< ? p h p / / get server http request info $serverhost = explode( '.' , $_SERVER["HTTP_HOST"]); / / get subdomain $subdomain = $serverhost[0]; ? >
sorry it won’t display my code on the previous post
Exacccctly what I needed to close out my old site and redirect effectively; I found your solution through Google, thanks!!
Hey, everyone.
I’m glad that someone finally got this idea out into the public. I have similar needs to that of everyone else that posted here.
What I’d like to do is take my subdomain and point it at a folder with the subdomain value (i.e. foo.bar.com –> bar.com/special/foo).
I’ve tried to figure out how to do this on my own, and I have yet to find a solution. Now, I read that a .htaccess might do the trick, but the problem is that my .htaccess is already riddled with so many redirects that I don’t think it can take one more.
If anyone knows how to do this, please get back to me. Thanks.
Julian,
You’re really going to have to use Redirects in .htaccess (or httpd.conf if you control it) if you want to do that.
foo.bar.com/some/directory/hello.php -> bar.com/special/foo/some/directory/hello.php
Otherwise your entire site would have to be dynamic and use a common header include that checked the subdomain on every page request and redirect with something like <?php header(“Location: http://bar.com/special/foo“) ?>; And if in the above example /some/directory/hello.php didn’t exist (because it’s under /special/foo/some/directory), your 404 php handler would also have to include the common header to do the check.
Much better to just use the apache builtin redirects.
Julian,
The other option is to use a php’d auto prepended file which saves you manually triggering the command each time. In the prepend file, just have it figure out if there is a subdomain that you want to process (exploding HTTP_HOST returns a 3 part array and part 1 isn’t www) then do a header Location.
Hopefully that makes sense.
C.
Hi.
Thanks a lot for providing this page. I had pretty much figured it out, but reading your advice helped it all came together.
groovy
Thanks for the tutorial, i just set that up for testing at a project i’m working on. Now to look into it’s uses with mod_rewrite with a project i’m working on.
I like the straightforward post. It gave me confidence with a project I’m doing that will need wildcard dns and sub-domains. (Hence my google search of “wild card dns sub-domain”.. you’re #4! haha)
Hi,
for those that haven’t solved the http://domain.com redirecting to cpanel page, you just have to add like this:
DocumentRoot /home/photomat/public_html
BytesLog domlogs/photomatt.net-bytes_log
User photomat
Group photomat
ServerAlias photomatt.net *.photomatt.net
ServerName http://www.photomatt.net
CustomLog domlogs/photomatt.net combined
RedirectMatch 301 (.*) http://photomatt.net$1
on ServerAlias just add your domain without the (*) thing and restar httpd 😀 done..
Thank you Matt.
Found this page googling for “apache wildcard subdomains.” Works perfectly for me. Thanks!
1. I only changed the bind config (/var/named/mydomain.com.db) as you said. No changes to my Apache conf.
2. I have a server with cPanel/WHM. Restarted bind from WHM. That’s all I had to do.
*.mydomain.com/file.php gets automatically forwarded to mydomain.com/file.php and the address bar still shows *.mydomain.com/file.php. Perfect!
Here’s a little code for those who might be using PHP on how to get the subdomain name:
$host = str_replace(array(“www.”, “.mydomain.com”), “”, strtolower(trim($_SERVER[“HTTP_HOST”])));
if($host == “mydomain.com”)
echo “Welcome to My Domain.com!”;
else if(strpos($host, “.”) === false)
echo “Dynamic subdomain: $host”;
else
echo “Invalid Subdomain!”
It’s a little less overhead to do it like this:
Redirect permanent / http://photomatt.net/
That way, you don’t have to involve the whole big regular expression parsing engine. Any URL path beginning with “/” (that would be any URL for that virtual host at all) will be redirected to a URL beginning with http://photomatt.net/. So the URL http://www.photomatt.net/foo/bar.html would be redirected to http://photomatt.net/foo/bar.html.
good information. it was helpful in setting up our wordpress mu (multiple user) version
Matt, any problems with search engines and duplicate content using your method? Seems like it could be a potential problem.
I know this is old, but I just have to give the Lighttpd equivalent to redirect like did in your httpd.conf since I know a lot of people are making the switch.
$HTTP[“host”] =~ “^www\.(.*)$” {
url.redirect = ( “^/(.*)” => “http://%1/$1” )
}
Great tutorial!
Actually it is on the spot for me, and it very nicely written THANKS ALLOT!! you saved me some time in configuration something 🙂 please do continue the nice work 🙂
It’s gonna take me a long long time to understand this, I’m a total noob. I want WP MU installed *sigh*
You can’t put User and Group in a block and expect them to do anything useful, so it would be really helpful if you’d remove that from your example configuration, since it’s misleading people who are using this as an example configuration, and expecting that User directive to have an actual effect on the user permissions that the vhost runs with. Thanks.
–Someone who provides user support on #apache.
Thanks for the suggestion – this was just copied from my httpd.conf so it was doing something ,but it might have been cPanel specific. I’ve removed those two lines. Crazy that 5 years later people still use this.
This could be because this blog post is linked in the WPMU setup (if the installation fails to resolve a random subdomain, it informs you that the wildcard DNS isn’t configured, and refers to this post for detailed explanation).
As disappointed as I am by this fact, I just don't get it. 🙁
Looks like I’ve answered my question by finding a great plugin a few hours later.
WordPress MU Domain Mapping
http://wordpress.org/extend/plugins/wordpress-mu-domain-mapping/
This is still one of the best tutorials I’ve seen around, I am constantly referencing this post to people about how to setup wildcard domains.
Thanks Matt!
Just to add for all and for Shared cPanel Accounts, you should Add:
UseCanonicalName Off
to your VirtualHost Configuration if it doesn’t Exist.
The other option is to use a php’d auto prepended file which saves you manually triggering the command each time. In the prepend file, just have it figure out if there is a subdomain that you want to process (exploding HTTP_HOST returns a 3 part array and part 1 isn’t www) then do a header Location.