PHP script to dynamically create/remove apache virtual hosts/ subdomains

by jagbir on September 2, 2011

There’s situation with my friend where his team wanted to dynamically create/remove virtual hosts or subdomains using php. This can be achieved in several ways. You can use a control panel which obviously use resources or develop your own script to do this. There’s security aspects attached with script because it needs to update file which is read by Apache and to apply settings, you need to reload Apache. Here I am describing how my friend achieved their goal, again I’m saying that this might not be the best way to do this thing and may be comparatively insecure or inefficient but this is what worked for them in Ubuntu host.

Create script to update Apache config file to create/remove subdomains/virtual hosts, here’s the script which I called here as subdmanager.php:

$templateStr = '##-- Entry start for <usersubdomain> --
<VirtualHost x.x.x.x:80>
    ServerAdmin webmaster@<usersubdomain>
    ServerName <usersubdomain>
    ServerAlias www.<usersubdomain>
    UseCanonicalName Off
    DirectoryIndex index.php 
    DocumentRoot /var/www/maindomains/<usersubdomain>/
        ErrorLog /var/www/logsvhosts/
        LogLevel error
        <IfModule mod_ssl.c>
                SSLEngine off
        <Directory /var/www/maindomains/<usersubdomain>.com>
                Options -Includes -ExecCGI
##-- Entry End for <usersubdomain> --';
foreach($argv as $k=>$v)
	$argvStr .= $v."<----->";
$argvStr = trim($argvStr,"<----->");
$argvArr = @explode("<----->",$argvStr);
$case = $argvArr[1];//"create";
$subdomain_name = $argvArr[2];

Here we are making a template for virtualhost entry. the string


will be replaced by actual subdomain selected by user. is the main website. No need to mention that all path, IP address (denoted by x.x.x.x here) are used as an example here, please replace them with your own actual values.

Then we are checking the command line option (create or remove), subdomain name and store values in respective variable.

if($case != '')
		case 'create':
		$domainStr2 = str_replace("<usersubdomain>",$subdomain_name,$templateStr);
		$filename = "/etc/apache2/sites-enabled/user-sites";
		$mainStr1 = file_get_contents($filename);
		$fp = fopen($filename,"a");
		case 'remove':
		$filename = "/etc/apache2/sites-enabled/user-sites";
		$contents = file($filename);
		foreach ($contents as $key => $line)
			if(strpos($line,"Entry start for ".$subdomain_name." --") == TRUE)
				$myStartKey = $key;
			if(strpos($line,"Entry End for ".$subdomain_name." --") == TRUE)
				$myLastKey = $key;
		for($i=$myStartKey; $i<=$myLastKey; $i++)
		$newContents = implode("",$contents);
		$fp = fopen($filename,"w");
	exec("/usr/sbin/apache2 -t", $output2, $retval2);
	if($retval2 == 0)	// 0 == Syntax OK; 1 = Syntax Wrong
		exec("touch /tmp/.reapache");
		echo "OK";
		echo "Syntax Error";

Here, if user is supplied ‘create’ as command line argument, we are create a new virtual host and saving it in a file which is stored in Apache directory and read by Apache. This file (/etc/httpd/conf.d/user-sites) is readable by PHP. We are removing the subdomain if user supply ‘remove’ as command line option. After this we are checking the Apache syntax and if its OK then we are creating/touching a simple file in tmp directory. Why? Its because PHP can not reload Apache (as initial apache process is started by root and we can’t let php to reload/restart it), so what we are doing here is that a cron is running every minute in Server and check existing of this file (/tmp/.reapache), if its exist then reload Apache else do nothing. So every minute settings get applied. Of course, this will add a delay of maximum 1 minute for you to create or remove subdomains but initially I guess its acceptable.

You also needs to make sure to create directory (which hold subdomains files) etc. before executing script or update this script itself to create required directories/files for you.

You can see that this is pretty simple script and needs a lots of enhancements before deploying it in production environment but still its giving an idea as how can we achieve that functionality.

As an example, you can run this script like this:

$ php subdmanager.php --create mynewsubdomain
$ php subdmanager.php --remove myoldsubdomain

or call this script from your website php files using syntax mentioned above.

Here’s the contents of simple cron file (bash script) which you can set to run every minute which will reload Apache in case /tmp/.reapache is present:

if [ -a /tmp/.reapache ]; 
	`/etc/init.d/apache2 reload`; 
	`rm -f /tmp/.reapache`;

Hah, pretty simple, isn’t it? yah but don’t rush and put it in production. I guess it needs to be fine tuned/needs better exception handling etc.

So things from Server side is completed but what about DNS? To make new subdomian work, you need to update DNS as well, right? Let me cover up that part in next article which I will post here after 2-3 days as the process is still in testing phase.

  • Ryan

    I made my own. My script rebuilds the vhosts config based on what directories exist in www. I run dnsmasq locally with a wildcard for *.localhost so no need to worry about DNS.

    Here’s my script. Save it somewhere, make it executable then run it directly with sudo when you want to update. Of course you’ll need to change the username. This works on Ubuntu but should be easily modifiable for other systems. It probably requires php5-cli to be installed.


    $hosts = glob('/home/ryan/www/*', GLOB_ONLYDIR);
    $template = file_get_contents('/etc/apache2/sites-available/autohosts-skel');

    $fp = fopen('/etc/apache2/sites-available/autohosts', 'w');

    foreach ($hosts as $hostname) {
    $hostname = basename($hostname);
    $config = str_replace('{hostname}', $hostname, $template);
    fwrite($fp, $config."\n");


    `service apache2 reload`;
    # (end of script)

    The autohosts-skel file is:

    ServerName {hostname}.localhost
    DocumentRoot /home/ryan/www/{hostname}

    The first time you run it you’ll need to run sudo a2ensite autohosts then reload apache again, but after that you should be good to just run the script.

  • Ryan

    Your silly WordPress decided that my VirtualHost tags in the autohosts-skel file should be removed rather than converted to HTML entities. Your loss.

  • jagbir

    Thank you Ryan for your comment and sharing this script. As I mentioned in article, my approach may not be that efficient and yours look like better. I will surely check it, as you mentioned you skel file is ripped, if possible, could you please send the script and skel file to me via mail? you can send it at hello AT jagbir DOT com.

  • Pingback: Manage virtual hosts via PHP scripting (1) « 0ddn1x: tricks with *nix

  • brandon

    If you are already going to pay the price of doing a reload you should be using mod_macro. With Apache macros you define any number of templates and then feed parameters into the templates. This is really handy for when you have to make an update to your template being all existing hosts would get the updates.

    A macro might look like:

    ServerAdmin webmaser@$host
    ServerName $host
    ServerAlias http://www.$host
    DocumentRoot /var/http/$host/html
    ScriptAlias /cgi-bin/ /var/http/$host/cgi/
    ErrorLog /var/log/http/error-$log.log
    CustomLog /var/log/http/access-$log.log combined

    And you would call the macro in another text file such as:
    Use NAME linux
    Use NAME linux

    • jagbir

      Thanks brandon for the comment. I’ll check this macro based approach as well.

  • Konsult

    Great blog right here! Additionally your web site quite a bit up very fast! What host are you the use of? Can I get your associate hyperlink on your host? I want my website loaded up as fast as yours lol

  • James

    Was very interested in Ryan’s solution, can you post it so we can learn?

  • jagbir

    Hi James, haven’t got script from Ryan yet. If Ryan would read this comment, requesting to share that.

  • Pingback: Php script installation service

  • Pingback: A best review of hookah Experience.

  • situsunik

    Thanks for sharing this great articles, may i know if i want to create 1 php additional page asking user email,name, and subdomain name that need to create, how to do that ?
    User email and name and domain name will also store in additional database ? Thanks

Previous post:

Next post: