Create Subdomains on the Fly With .Htaccess (PHP)

Create subdomains on the fly with .htaccess (PHP)

The quick rundown

  1. You need to create a wildcard domain on your DNS server *.website.example
  2. Then in your vhost container you will need to specify the wildcard as well *.website.example - This is done in the ServerAlias DOCs
  3. Then extract and verify the subdomain in PHP and display the appropriate data

The long version

1. Create a wildcard DNS entry

In your DNS settings you need to create a wildcard domain entry such as *.example.org. A wildcard entry looks like this:

*.example.org.   3600  A  127.0.0.1

2. Include the wildcard in vhost

Next up in the Apache configuration you need to set up a vhost container that specifies the wildcard in the ServerAlias DOCs directive. An example vhost container:

<VirtualHost *:80>
ServerName server.example.org
ServerAlias *.example.org
UseCanonicalName Off
</VirtualHost>

3. Work out which subdomain you are on in PHP

Then in your PHP scripts you can find out the domain by looking in the $_SERVER super global variable. Here is an example of grabbing the subdomain in PHP:

preg_match('/([^.]+)\.example\.org/', $_SERVER['SERVER_NAME'], $matches);
if(isset($matches[1])) {
$subdomain = $matches[1];
}

I have used regex here to to allow for people hitting your site via www.subdomain.example.org or subdomain.example.org.

If you never anticipate having to deal with www. (or other subdomains) then you could simply use a substring like so:

$subdomain = substr(
$_SERVER['SERVER_NAME'], 0,
strpos($_SERVER['SERVER_NAME'], '.')
);

Mass Virtual Hosting

Mass virtual hosting is a slightly different scheme to the above in that you would usually use it to host many distinct websites rather than attempting to use it power an application as the question proposes.

I have documented my mod_rewrite based mass virtual hosting environment before in a post on my blog, which you could look at if that is the route you wish to take. There is also, of course, the respective Apache manual page.

Apache also has an internal way of dealing with mass virtual hosting that is slightly less flexible than the mod_rewrite method I have used. This is all described on the Apache Dynamically Configured Mass Virtual Hosting manual page.

Can I dynamically create subdomains (PHP, .htaccess) with GoDaddy Hosting?

DNS is only 1 part of the configuration. You need to have a ServerAlias for *.mydomain.com in the configuration for the virtual host in Apache, otherwise Apache will not have any idea where to route requests for *.mydomain.com - which means the .htaccess never has a chance to work at all.

If GoDaddy provides a way to manually edit your virtual hosts' directives, or at least the ability to add server aliases through their GUI, then it's easy enough. If you can't find it, you should contact GoDaddy for information.

Creating subdomains on the fly

In a nutshell:

  1. Create a wildcard domain in DNS (i.e., resolving whatever.yourdomain.example returns your IP),
  2. create a default virtual host in your web server and
  3. check the URL in your application.

How to do this depends on what technology you use. Let me give you some examples:

  1. How to set up a wildcard domain in BIND and in Windows Server DNS.
  2. To create a default virtual host, you just need to create a web server without a host entry in IIS. In Apache, the first virtual host listed in the configuration file becomes the default host.
  3. Here, you can either (a) rewrite the URL depending on the domain (i.e., converting the subdomain into a parameter in the URL, example for ASP.NET, examples for Apache with mod_rewrite: Link1, Link2), or (b) just have a look at the host part of the URL (e.g. Request.Url in ASP.NET).

Addition by bortzmeyer (sorry for overwriting your edit, there was an edit conflict):

The syntax for a wildcard, in the usual DNS zone file format (described in RFC 1035 and implemented in BIND, nsd and may be others) is with a star:

 *   IN    A   198.51.100.3

Create subdomains on the fly with info from database

I presuppose that you setup a wildcard dns entry (access random.domain.tld to test it!). Then you have two options:

Correct your rewrite rules

Something like [aA-zZ] should be [a-zA-Z] and the RewriteRule should be only after the RewriteCond and not in front of it and two of them. And do you really want to force a - inside the subdomain with ([a-z0-9][-a-z0-9]+)? Maybe you should check this answer. Note: The www inside of your domain is a subdomain as well. So it would rewrite to sub.php?url=www

With the corrected rewriting random.domain.tld returns the content of random.domain.tld/sub.php?url=random. But at the moment your sub.php does not return content. Instead it returns a http redirect to the URL random.domain.tld. This means your sub.php produces an infinite loop on itself. Instead sub.php should only contain something like <?php echo $_SERVER['HTTP_HOST']; ?>.

Maybe you did not understand how URL rewriting works. Then read this answer for further explanation.

Update1

You corrected your code as follows:

RewriteCond %{HTTP_HOST} ^([a-zA-Z0-9]+)\.domain\.tld\.?(:80)?$ [NC]
RewriteRule ([a-zA-Z0-9]+) /view.php?url=$1

But it's still wrong. As I said you need to read and understand this answer. @JoachimIsaksson uses $1 and %1 in his 2nd example:

RewriteEngine on
RewriteCond %{HTTP_HOST} ^(.*)\.example\.com
RewriteRule ^(.*)$ /subdomains/%1/$1 [L,NC,QSA]

%1 is the subdomain catched through RewriteCond %{HTTP_HOST} ^(.*)\.domain\.com. And $1 is the path catched through RewriteRule ^(.*)$. You missed to use %1.

But your code can not work as you forced an unempty alphanummeric string by RewriteRule ([a-zA-Z0-9]+). But a path could contain more than that. For example a slash or question mark. And of course it could be empty as well.

And why did you add (:80)?? Do you think someone will access your domain with a specific port?

And why the last optional dot in tld\.??

At last you need to bring the flags into question. You used the NC flag. It means your rule is case-insensitive. So why do you use [a-zA-Z0-9]? As your rule is already case-insensitive it can be [a-z0-9]. And why don't you used the L and QSA flag? They are important.

Update2

Try this:

RewriteEngine on
RewriteCond %{HTTP_HOST} ^(.*)\.domain\.tld
RewriteRule .* view.php?url=%1 [L,NC,QSA]

Use PHP only

$_SERVER['HTTP_HOST'] contains your full domain. This answer explains how to extract the subdomain name:

$subdomain = array_shift((explode('.', $_SERVER['HTTP_HOST'])));

Now you are able to use your general index.php to switch between your general page or the users subdomain content:

$domain_parts = explode('.', $_SERVER['HTTP_HOST']);
// access without any subdomain (TLDs like "co.uk" would "need == 4")
if (count(domain_parts) == 3) {
$subdomain = "www";
}
else {
$subdomain = array_shift($domain_parts);
}
if ($subdomain == 'www') {
// general page
}
else {
// users page
}


Related Topics



Leave a reply



Submit