Create subdomains on the fly with .htaccess (PHP)
Asked Answered
C

9

126

I am looking to create a system which on signup will create a subdomain on my website for the users account area.

e.g. johndoe.website.example

I think it would be something to do with the .htaccess file and possibly redirecting to another location on the website? I don't actually know. But any information to start me off would be greatly appreciated.

Creating a sign up area is not the problem - I have done this many a time. I am just unsure where to start with the subdomain.

Collard answered 25/2, 2009 at 14:13 Comment(0)
A
126

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.

Avisavitaminosis answered 25/2, 2009 at 14:21 Comment(3)
Provided you can use wildcard subdomains, see my solution to do this in .htaccess.Abbasid
I don't believe a virtual host can be added from .htaccess it also makes me nervious about the security. From 2.4, it should be possible to select a base directory dependent on the hostname (But Dan's method has some issues too) Consider: RewriteRule "^/?(.*)" "http://%{HTTP_HOST}/%{HTTP_HOST}/$1" [L,R,NE]Tyranny
Note that the PHP code implementing this MUST NOT run as the webserver uid (should be as a dedicated user via sudo)Tyranny
F
13

You could allow every subdomain in the first place and then check if the subdomain is valid. For example:

RewriteEngine on
RewriteCond %{HTTP_HOST} ^[^.]+\.example\.com$
RewriteRule !^index\.php$ index.php [L]

Inside the index.php you can than extract the subdomain using:

if (preg_match('/^([^.]+)\.example\.com$/', $_SERVER['HTTP_HOST'], $match)) {
    var_dump($match[1]);
}

But all this requires that your webserver accepts every subdomain name.

Faultfinder answered 25/2, 2009 at 14:18 Comment(5)
Moreover, it requires that your DNS server resolves every subdomain name.Banda
I have seen this done on other websites, surely they dont have to resolve every subdomain everytime do they?Collard
Well, it depends on what you mean by that. If you mean, every time someone on the internet looks up foo.somedomain.com and it isn't cached, their DNS server has to resolve it, then yes.Banda
If you mean, do they have to set up DNS records specifically for each domain, see Treffynnon's answer.Banda
okay thanks for that. i dont quite understand what Treffynnon means by specifying the wildcard in the vhost?Collard
A
7

In addition to setting up a DNS wildcard, you might want to take a look at Dynamic Mass Virtual Hosting for Apache which is how I've solved this in the past

Agrology answered 25/2, 2009 at 14:38 Comment(0)
I
6

The easiest way is to redirect all subdomains (with wildcard *) to point to your /wwwroot. Then put .htaccess to this folder with the following code:

RewriteCond %{ENV:REDIRECT_SUBDOMAIN} =""
RewriteCond %{HTTP_HOST} ^([a-z0-9][-a-z0-9]+)\.domain\.example\.?(:80)?$ [NC]
RewriteCond %{DOCUMENT_ROOT}/%1 -d
RewriteRule ^(.*) %1/$1 [E=SUBDOMAIN:%1,L]
RewriteRule ^ - [E=SUBDOMAIN:%{ENV:REDIRECT_SUBDOMAIN},L]

This will accomplish that every subfolder of the /wwwroot folder in acceptable via subdomain (foldername.domain.example).

Found this years ago on http://www.webmasterworld.com/apache/3163397.htm

Implication answered 25/2, 2009 at 15:55 Comment(0)
C
6

I found it easier doing it with PHP. In fact is creating a subdomain within cPanel and create your folder under the desired domain name. As you will do it manually in cPanel but all it's done in milliseconds by a simple PHP function. No click necessary :)

function create_subdomain($subDomain,$cPanelUser,$cPanelPass,$rootDomain) {

    //  $buildRequest = "/frontend/x3/subdomain/doadddomain.html?rootdomain=" . $rootDomain . "&domain=" . $subDomain;

    $buildRequest = "/frontend/x3/subdomain/doadddomain.html?rootdomain=" . $rootDomain . "&domain=" . $subDomain . "&dir=public_html/subdomains/" . $subDomain;

    $openSocket = fsockopen('localhost',2082);
    if(!$openSocket) {
        return "Socket error";
        exit();
    }

    $authString = $cPanelUser . ":" . $cPanelPass;
    $authPass = base64_encode($authString);
    $buildHeaders  = "GET " . $buildRequest ."\r\n";
    $buildHeaders .= "HTTP/1.0\r\n";
    $buildHeaders .= "Host:localhost\r\n";
    $buildHeaders .= "Authorization: Basic " . $authPass . "\r\n";
    $buildHeaders .= "\r\n";

    fputs($openSocket, $buildHeaders);
        while(!feof($openSocket)) {
           fgets($openSocket,128);
        }
    fclose($openSocket);

    $newDomain = "http://" . $subDomain . "." . $rootDomain . "/";

   //  return "Created subdomain $newDomain";

}
Caresse answered 13/2, 2013 at 1:55 Comment(4)
Check if it was created successfully on cPanel and, check by FTP (or file manager), what's inside of the public_html/subdomain folder. If you have a cPanel setting adding stuff when you create a subdomain this is not related to creating subdomains on the fly.Caresse
No has not been created in cPanelSanmiguel
Then you don't have enough permission on cPanel. Is this shared hosting VPS or dedicated server?Caresse
It can be multiple reasons for not creating the subdomain. Not related to the script above but with your DNS configuration. Read that and ask for help on cPanel forums. forums.cpanel.net/threads/subdomains-not-working.228132Caresse
B
4

It's nothing to do with .htaccess. You'll need to set up DNS records and virtual hosting for the subdomains.

Banda answered 25/2, 2009 at 14:17 Comment(0)
G
4

Mod_vhost_alias is the right module to do this.

With one line you can tell Apache to look at the right place, with directory hashing, etc. For example, the line:

VirtualDocumentRoot /http/users/%3.1/%3.2/%3

would tell Apache to set the document root to /http/users/s/u/subdomain when requested for subdomain.yourdomain.example

Gefell answered 14/4, 2009 at 11:20 Comment(0)
B
0

I think the wild card DNS with Apache's Dynamic Mass Virtual Hosting is a reasonable solution also. Although, I have never tried it.

If you have the need to scale out to multiple servers or the other solutions just don't work for you, I recommend using a database driven DNS server. I have successfully used MyDNS in the past. Since it uses MySQL (or PostgreSQL) you can update your DNS on the fly with PHP or just about anything else. The code doesn't look like it has been updated in a while, but it's DNS and therefore not exactly cutting edge.

Bouilli answered 25/2, 2009 at 15:13 Comment(0)
S
0

Wildcard subdomain creation methods

FIrst you have to create the DNS settings using your server DNS editor.

  1. Create A record in DNS settings with host * wild card in server IP address.

    * 1400 IN A ip_address

  2. Create once again a A record in DNS settings with host @ or domainname.example in server IP address. tld means top level domains or the extension of the domains such as .com, .org, etc....

    @ 1400 IN A ip_address or domainname.example 1400 IN A ip_address

  3. Create CNAME record like:

    www 1400 IN A domainname.example

  4. Create the subdomain with * wildcard like *.domainname.example

  5. Create .htaccess in your subdomain directory of *.domainname.example and put this code:

     Options +FollowSymLinks
     RewriteEngine On
     RewriteBase /
     RewriteRule ^([aA-zZ0-9]+)$ index.php?data=$1
     RewriteCond %{HTTP_HOST} ^([aA-zZ0-9]+)\.([aA-zZ0-9-]+)\.([aA-zZ]+)
     RewriteRule ([aA-zZ0-9]+) index.php?data=%1
    

Test your first wildcard subdomain like some.domainname.example

If you are not interest to pass the data as parameter using the .htaccess, you can also get the data by using the following coding:

define("SUBDOMAIN_PARENT","domainname.example");
class getData
    {
         function __construct()
        {
            $this->data="";
            $http_host=$_SERVER['HTTP_HOST'];
         $subdom_data= str_replace(SUBDOMAIN_PARENT,"",$http_host);
         $expl_subdom_data=explode(".",$subdom_data);
      $expl_subdom_data=array_filter($expl_subdom_data);

            if($expl_subdom_data!=NULL)
            {
           $this->data=end($expl_subdom_data);
            }
       }
    }
$GLOBALS['get_data']=new getData();

and use your global variable at any place like global $get_data.

echo $get_data->data; //example

(note: This class mainly used for get the exact subdomainname from http_host. because some extra names combined before your subdomain is also applicable like www.some.domainname.example. This return $_GET['data']='wwww' So my suggestion is to use the $_SERVER['http_host'] for get the exact values instead of using the $_SERVER['query_string'] or passed .htaccess parameters in your index page)

6.Speed up the execution of this wildcard subdomains use N seconds in TTL - DNS SETTINGS.

7.Check the subdomain after your given ttl time (600 - 10 minutes) like => http://abc.domainname.example

(note: wildcard subdomains not override the existed subdomains. Because First priority always for your existed subdomains)

Sainted answered 2/6, 2017 at 10:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.