Web presence step by step Chapter 16: Using a script to automate the creation of a virtual host on an Apache web server

Previous step: Chapter 15: Using dwservice.net to provide remote technical support as an alternative to TeamViewer
Next step: Chapter 17: Using subdomains to host multiple websites under a single domain name

Web presence step by step is a series of posts that show you to how to build a web presence.

In this chapter we install and use a script to automate the creation of a virtual host on an Apache web server.

A PHP script that automates the creation of a virtual host under Apache

This script collects and validates inputs, then executes the commands to create a virtual host under Apache.

A note about the source code view below

For formatting reasons, the text is limited to a fixed width. To fully view the text, you can scroll to the right to see the ends of lines, or use the print view for this blog post.

To view the source code in an another text editor, download and uncompress the zip file described below, or select and copy the text from the source code example below, and paste the text into a file on your computer called “addvhost.php”

Consider copying the file to your Apache web server’s /usr/bin directory with a chmod of 755 so that it can be executed from the system path. Steps to do so are included in the procedure below.

Saving the PHP script to a file called addvhost.php

Download this zip file:

https://blog.gordonbuchan.com/files/addvhost.zip

Uncompress the zip file to extract the file “addvhost.php” then copy the file to your Apache web server.

Source code of the script

Scroll right to see the ends of lines.

#!/usr/bin/php
<?PHP
// addvhost.php
// v0102
// updated to variable-ize vhostip as a base setting
// creates a virtual host under Apache
// Gordon Buchan 20210512 https://gordonbuchan.com
// MIT License https://mit-license.org
// tested on Ubuntu 20.04, may work on Debian
// directory structure allows for chroot jails for SFTP:
// in a jail you do not own your home directory, only your webdir
// tip: apt install finger whois
// ////////////////////////////////////////////////////////////////
// start summary
// initialize base settings in variables ie bvhwb
// ask for vhostsubdomain, vhostusername, vhostpassword
// infer vhosthomedir, vhostwebdir by convention
// create user, home directory, password
// create directory
// create index.php document
// chown vhosthomedir as root:root
// chown vhostwebdir as vhostusername:vhostusername
// chmod vhostwebdir
// create virtual host file
// enable virtual host
// echo suggestion that client restart apache, run certbot --apache, restart apache
// end summary

// ////////////////////////////////////////////////////////////////
// start base settings

$bvhostconfdir = "/etc/apache2/sites-available";
$bvhwb = "/usr/web";
$restartcommandstr = "systemctl apache2 restart";
$vhostenablecommandstr = "a2enmod";
$echoplaintextpasswords = TRUE;
$logplaintextpassword = TRUE;
$vhostserveradmin = "info@yourdomain.com";
// tip: could be "xxx.xxx.xxx.xxx"
$vhostip = "*";

// ////////////////////////////////////////////////////////////////
// end base settings

// ////////////////////////////////////////////////////////////////
// start function sink
 
// start polyfill
// str_contains() polyfill for pre PHP8: code for this function taken from php.net
if (!function_exists('str_contains')) {
	function str_contains(string $haystack, string $needle): bool 
	{
	return '' === $needle || false !== strpos($haystack, $needle);
	} // end function str_contains()
}
// ////////////////////////////////////////////////////////////////
// end polyfill

// validate functions
// We will be using the readline() function to ask questions on the command line.
// These functions allow us to do rich validation within a while statement to trap
// the readline in a loop until our conditions are satisfied.
// We will also echo text to the console with reasons for rejection to assist the client.
// For example: bad string format, vhost appears to exist already, etc.

// ////////////////////////////////////////////////////////////////
function vhostsubdomainverify($vhostsubdomainstr) {
global $bvhwb;
global $bvhostconfdir;

//assume true until proven false
$returnval = TRUE;

// is the string clean?
// note that "-" hyphen character is permitted, not part of symbol sieve
if ( preg_match('/[\'^£$%&*()}{@#~?><>,|=_+¬]/', $vhostsubdomainstr) ) {
	$returnval = FALSE;
	echo "string has special character that is not permitted\n";
}

// string does not contain a period symbol
if (!str_contains($vhostsubdomainstr,".") ) {
	$returnval = FALSE;
	echo "string does not contain a \".\" period symbol.\n";
}

// string contains two period symbols in a row
if (str_contains($vhostsubdomainstr,"..") ) {
	$returnval = FALSE;
	echo "string contain two \"..\" period symbols in a row.\n";
}

// string contains leading period symbol
$strlen = strlen($vhostsubdomainstr);
$begsample = substr($vhostsubdomainstr,0,1);
if ($begsample == ".") {
	$returnval = FALSE;
	echo "string begins with a \".\" period symbol.\n";
}

// string contains trailing period symbol
$endlen = strlen($vhostsubdomainstr);
$endsample = substr($vhostsubdomainstr,($endlen - 1),1);
if ($endsample == ".") {
	$returnval = FALSE;
	echo "string ends with a \".\" period symbol.\n";
}

// does the vhostsubdomain already exist?
$vhostsubdomainstrund = str_replace(".","_",$vhostsubdomainstr);
clearstatcache();
if (is_dir("$bvhwb/$vhostsubdomainstrund") ) {
	$returnval = FALSE;
	echo "webdir for proposed vhost already exists.\n";
} else {
} // end if (is_dir()

$grepforvhost1str = "grep -i 'ServerName $vhostsubdomainstr' $bvhostconfdir/*";
$grepforvhost2str = "grep -i 'ServerAlias $vhostsubdomainstr' $bvhostconfdir/*";
$grepforvhost1res = shell_exec($grepforvhost1str);
$grepforvhost2res = shell_exec($grepforvhost2str);

// if the string has contents something was there for the grep to find
if ($grepforvhost1res || $grepforvhost2res) {
	echo "subdomain appears to be part of an existing virtual host\n";
	$returnval = FALSE;
}

return $returnval;
} // end function vhostsubdomainverify()

// ////////////////////////////////////////////////////////////////
function prependverify($prependverify) {

// let us make our tests and comparisons case-insensitive
$lowerpv = strtolower($prependverify);

if ( ( $lowerpv == "n") || ($lowerpv == "no") || ($lowerpv == "y") || ($lowerpv == "yes") ) {
	$returnval = TRUE;
} else {
	echo "please indicate n or no, y or yes\n";
	$returnval = FALSE;
}

return $returnval;
} // end function prependverify()

// ////////////////////////////////////////////////////////////////
function usernameverify($vhostusername) {

// force to lower-case
$vhostusername = strtolower($vhostusername);

// assume TRUE until proven false
$returnval = TRUE;

// is the string clean?
// note that "-" hyphen character is permitted, as is the "_" underscore character, not part of symbol sieve
if ( preg_match('/[\'^£$%&*()}{@#~?><>,|=+¬]/', $vhostusername) ) {
	$returnval = FALSE;
	echo "string has special character that is not permitted\n";
}

$vhunstrlen = strlen($vhostusername);

if ($vhunstrlen < 2) {
	echo "username should be minimum 2 characters\n";
	$returnval = FALSE;
}
if ($vhunstrlen > 32) {
	echo "username should be maximum 32 characters\n";
	$returnval = FALSE;
}

// what does finger return?
$fingerstr = shell_exec("finger $vhostusername 2>&1");

if (!str_contains("$fingerstr","no such user") ) {
	echo "finger found this username to already be in use\n";
	$returnval = FALSE;
}

return $returnval;
} // end function usernameverify()

// ////////////////////////////////////////////////////////////////
function passwordplainverify($passwordplain) {

// assume TRUE until proven false
$returnval = TRUE;

// we should do some tests here
// but mostly just for length, not all that fancy stuff.
// but: we will want to offer to auto-generate a plaintext password

$ppstrlen = strlen($passwordplain);

if ($ppstrlen < 8) {
	echo "password should be at least 8 characters\n";
	$returnval = FALSE;
}

return $returnval;
} // end function passwordplainverify()

// ////////////////////////////////////////////////////////////////
function genpassverify($genpassverify) {

// let us make our tests and comparisons case-insensitive
$lowergpv = strtolower($genpassverify);

if ( ( $lowergpv == "n") || ($lowergpv == "no") || ($lowergpv == "y") || ($lowergpv == "yes") ) {
	$returnval = TRUE;
} else {
	echo "please indicate n or no, y or yes\n";
	$returnval = FALSE;
}

return $returnval;
} // end function genpassverify()

// ////////////////////////////////////////////////////////////////
function genuserverify($genuserverify) {

// let us make our tests and comparisons case-insensitive
$lowerguv = strtolower($genuserverify);

if ( ( $lowerguv == "n") || ($lowerguv == "no") || ($lowerguv == "y") || ($lowerguv == "yes") ) {
	$returnval = TRUE;
} else {
	echo "please indicate n or no, y or yes\n";
	$returnval = FALSE;
}

return $returnval;
} // end function genuserverify()

// end function sink

// ////////////////////////////////////////////////////////////////
// start get information at command line: vhostsubdomain, vhostusername, vhostpassword
// also, generate and derive values
echo "\naddvhost.php\n";
echo "Add a virtual host to Apache\n\n";

// ask and validate inputs
// the readline is trapped in a loop until vhostsubdomainverify() is satisfied
// function will also echo text to the console with reasons for rejection to assist the client
// bad string format or vhost appears to exist already, etc.

// ////////////////////////////////////////////////////////////////
// vhostsubdomain

$vhostsubdomain = "";
while (!$vhostsubdomain || !vhostsubdomainverify($vhostsubdomain) ) {
    $vhostsubdomain = readline("Enter domain xxxxxxxx.xxx or subdomain xxxxxxxx.xxxxxxxx.xxx: ");
}

// putting this here because it is right after we have the $vhostsubdomain string, and just before we need it for $genuseranswer
// will also need this later for derived values like the $vhostwebdir

$vhostsubdomainund = str_replace(".","_",$vhostsubdomain);

// should we prepend with www. as well?

$prependanswer = "";
while (!$prependanswer || !prependverify($prependanswer) ) {
    $prependanswer = readline("Do you wish to prepend the subdomain www.$vhostsubdomain as well (n/y)? ");
}

$prependanswer = strtolower($prependanswer);

// ////////////////////////////////////////////////////////////////
// vhostusername

// default username
// should we offer to automatically generate a username based on the subdomain host name?

$genuseranswer = "";
while (!$genuseranswer || !genuserverify($genuseranswer) ) {
    $genuseranswer = readline("Generate a username? ");
}

$genuseranswer = strtolower($genuseranswer);

if ( ($genuseranswer=="yes") || ($genuseranswer=="y") ) {
	// generate a username
	// we are counting on the novel construction of this name with _ modeled on subdomain

	$vhostusername = $vhostsubdomainund;
	$vhostusernamestrlen = strlen($vhostusername);
	// the unique stuff is closer to the front
	// so we will truncate to first 32 characters
	if ($vhostusernamestrlen > 32) {
		$vhostusername = substr($vhostusername,0,32);
	}

	// what does finger return?
	$fingerstr2 = shell_exec("finger $vhostusername 2>&1");
	if (!str_contains("$fingerstr2","no such user") ) {
		echo "finger found this username to already be in use\n";
		exit();
	}

} else {
	// the client said no to automatic generation of username so we will ask for one
	$vhostusername = "";
	while (!$vhostusername || !usernameverify($vhostusername) ) {
	    $vhostusername = readline("Enter username: ");
	}
} // end if ($genuseranswer=="yes")

// ////////////////////////////////////////////////////////////////
// vhostpasswordplain

// should we offer to automatically generate a plaintext password?

$genpassanswer = "";
while (!$genpassanswer || !genpassverify($genpassanswer) ) {
    $genpassanswer = readline("Generate a plaintext password? ");
}

$genpassanswer = strtolower($genpassanswer);

if ( ($genpassanswer=="yes") || ($genpassanswer=="y") ) {
	// generate a random plaintext password
	$vhostpasswordplain = "";
	$passwordlength = "8";
	$posscharsplain = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
	$posscharssymbols = '!@#%*?';
	$posscharspstrlen = strlen($posscharsplain);
	$posscharssstrlen = strlen($posscharssymbols);
	// first the plain characters
	for ($i=0;$i<($passwordlength-1);$i++) {
		$randomint = random_int(0,$posscharspstrlen-1);
		$randomchar = substr($posscharsplain,$randomint,1);
		$vhostpasswordplain .= $randomchar;
	} //end for $i
	// now the symbol character
		$randomint = random_int(0,$posscharssstrlen-1);
		$randomchar = substr($posscharssymbols,$randomint,1);
		$vhostpasswordplain .= $randomchar;
	// now shuffle the string so the symbol position moves and as bonus the string is different
	$vhostpasswordplain = str_shuffle($vhostpasswordplain);
} else {
	// the client said no to automatic generation of plaintext, so we will ask for one
	$vhostpasswordplain = "";
	while (!$vhostpasswordplain || !passwordplainverify($vhostpasswordplain) ) {
		$vhostpasswordplain = readline("Enter plaintext password: ");
	}
} // end if ($genpassanswer=="yes")

// ////////////////////////////////////////////////////////////////
// vhostpasswordhashed (transformation)

// yes, i tried password_hash() -- it did not work for SHA512, this does.
// tip: apt install whois to get mkpasswd command
$vhostpasswordhashed = shell_exec("mkpasswd -m sha-512 $vhostpasswordplain");
// remove linefeed from the string
$vhostpasswordhashed = str_replace("\n","",$vhostpasswordhashed);

// ////////////////////////////////////////////////////////////////
// end get information at command line: vhostsubdomain, vhostusername, vhostpassword

// ////////////////////////////////////////////////////////////////
// start print collected values

$vhosthomedir = "$bvhwb/$vhostusername";
$vhostwebdir = "$bvhwb/$vhostusername/$vhostsubdomain";

echo "\nvalues collected, generated, and derived\n\n";

echo "vhostsubdomain: $vhostsubdomain\n";
echo "prependanswer: $prependanswer\n";
echo "vhostusername: $vhostusername\n";
echo "genpassanswer: $genpassanswer\n";
if ($echoplaintextpasswords) {
	echo "vhostpasswordplain: $vhostpasswordplain\n";
}
echo "vhostpasswordhashed: $vhostpasswordhashed\n";
echo "vhosthomedir: $vhosthomedir\n";
echo "vhostwebdir: $vhostwebdir\n";

// ////////////////////////////////////////////////////////////////
// end print collected values

// ////////////////////////////////////////////////////////////////
// start engine section

// ////////////////////////////////////////////////////////////////
// create the $vhostusername with $vhosthomedir and $vhostpasswordhashed

// build the string, look at the string, then maybe do a shell_exec of the string
$shelluseraddstr = "useradd -m -d '$vhosthomedir' '$vhostusername' -s '/usr/bin/bash' -p '$vhostpasswordhashed'";

// disable for production
// echo "shelluseraddstr: $shelluseraddstr\n";

// so it will always be declared
$shelluseraddret = "";
// disable for testing other conditions without committing to this
$shelluseraddret = shell_exec($shelluseraddstr);

//echo "shelluseraddret: $shelluseraddret\n";
// non-null (non-0) exit value from shell indicates an error
if ($shelluseraddret) {
	echo "ERROR: there was a problem executing the shell command to create the vhostusername $vhostusername. Stopping.\n";
	exit();
} else {
	//echo "SUCCESS: the vhostusername $vhostusername was created\n";
}

echo "\n";

// ////////////////////////////////////////////////////////////////
// mkdir $vhostwebdir

$mkdirvhostwebdirret = mkdir($vhostwebdir,0775,TRUE);

if (!$mkdirvhostwebdirret) {
	echo "ERROR: there was a problem creating the vhostwebdir $vhostwebdir. Stopping\n";
	exit();
} else {
	//echo "SUCCESS: the vhostwebdir $vhostwebdir was created.\n";
}

// ////////////////////////////////////////////////////////////////
// fwrite $vhostwebdir/index.php

$indexfilecontents = "<?PHP\n\necho \"<p>$vhostsubdomain</p>\\n\";\n";

$fh1 = fopen("$vhostwebdir/index.php","w");
$filesuccess1 = fwrite($fh1,$indexfilecontents);
fclose($fh1);
 
if ($filesuccess1) {

	//chown root $vhosthomedir

	$vhosthomedirownretu1 = chown("$vhosthomedir","root");
	if ($vhosthomedirownretu1) {
		//echo "SUCCESS chown root $vhosthomedir\n";
	} else {
		echo "ERROR chown root $vhosthomedirdir not successful\n";
		exit();
	}

	//chgrp root $vhosthomedir

	$vhosthomedirownretg1 = chgrp("$vhosthomedir","root");
	if ($vhosthomedirownretg1) {
		//echo "SUCCESS chgrp root $vhosthomedir\n";
	} else {
		echo "ERROR chgrp root $vhosthomedirdir not successful\n";
		exit();
	}

	//echo "SUCCESS indexfile written to file: $vhostwebdir/index.php\n";

	// chmod the $vhostwebdir
	chmod("$vhostwebdir", 0755);
	$vhostwebdirperms = substr(sprintf('%o', fileperms("$vhostwebdir")), -4);
	//echo "vhostwebdirperms: $vhostwebdirperms\n";
	if ($vhostwebdirperms == "0755") {
		//echo "SUCCESS chmod 755 $vhostwebdir\n";
	} else {
		echo "ERROR chmod 755 $vhostwebdir not successful. Stopping.\n";
	exit();
	}

	// chown $vhostusername $vhostwebdir
	$vhostwebdirownretu1 = chown("$vhostwebdir",$vhostusername);
	if ($vhostwebdirownretu1) {
		//echo "SUCCESS chown $vhostusername $vhostwebdir\n";
	} else {
		echo "ERROR chown $vhostusername $vhostwebdir not successful\n";
		exit();
	}

	// chgrp $vhostusername $vhostwebdir
	$vhostwebdirownretg1 = chgrp("$vhostwebdir",$vhostusername);
	if ($vhostwebdirownretu1) {
		//echo "SUCCESS chgrp $vhostusername $vhostwebdir\n";
	} else {
		echo "ERROR chgrp $vhostusername $vhostwebdir not successful\n";
		exit();
	}

	// chmod the $vhostwebdir/index.php
	chmod("$vhostwebdir/index.php", 0755);
	$vhostindexperms = substr(sprintf('%o', fileperms("$vhostwebdir/index.php")), -4);
	//echo "vhostindexperms: $vhostindexperms\n";
	if ($vhostindexperms == "0755") {
		//echo "SUCCESS chmod 755 $vhostwebdir/index.php\n";
	} else {
		echo "ERROR chmod 755 $vhostwebdir/index.php not successful. Stopping.\n";
	exit();
	}

	// chown $vhostusername $vhostwebdir/index.php
	$vhostindexownretu1 = chown("$vhostwebdir/index.php",$vhostusername);
	if ($vhostindexownretu1) {
		//echo "SUCCESS chown $vhostusername $vhostwebdir/index.php\n";
	} else {
		echo "ERROR chown $vhostusername $vhostwebdir/index.php not successful\n";
		exit();
	}

	// chgrp $vhostusername $vhostwebdir/index.php
	$vhostindexownretg1 = chgrp("$vhostwebdir/index.php",$vhostusername);
	if ($vhostindexownretu1) {
		//echo "SUCCESS chgrp $vhostusername $vhostwebdir/index.php\n";
	} else {
		echo "ERROR chgrp $vhostusername $vhostwebdir/index.php not successful\n";
		exit();
	}
} else {
	echo "ERROR indexfile not written to file: $vhostwebdir/index.php\n";
	exit();
}

// ////////////////////////////////////////////////////////////////
// fwrite $bvhostconfdir/$vhostsubdomain.conf

$timestring = date("Y/m/d H:i:s T");

$vhostconffilecontents  = "# generated $timestring by addvhost.php\n";
$vhostconffilecontents .= "<VirtualHost $vhostip:80>\n";
$vhostconffilecontents .= "<IfModule mpm_itk_module>\n";
$vhostconffilecontents .= "\tAssignUserID $vhostusername $vhostusername\n";
$vhostconffilecontents .= "</IfModule>\n";
$vhostconffilecontents .= "ServerName $vhostsubdomain\n";
if ( ($prependanswer == "y") || ($prependanswer == "yes") ) {
	$vhostconffilecontents .= "ServerAlias www.$vhostsubdomain\n";
}
$vhostconffilecontents .= "DocumentRoot $vhostwebdir\n";
$vhostconffilecontents .= "ServerAdmin $vhostserveradmin\n";
$vhostconffilecontents .= "CustomLog /var/log/apache2/$vhostsubdomain-access_log combined\n";
$vhostconffilecontents .= "ErrorLog /var/log/apache2/$vhostsubdomain-error_log\n";
$vhostconffilecontents .= "</VirtualHost>\n";

// disable in production
// echo "vhostconffilecontents = \n$vhostconffilecontents\n";

// write the text file
$fh2 = fopen("$bvhostconfdir/$vhostsubdomain.conf","w");
$filesuccess2 = fwrite($fh2,$vhostconffilecontents);
fclose($fh2);
 
if ($filesuccess2) {
	//echo "SUCCESS virtual host config written to file: $bvhostconfdir/$vhostsubdomain.conf\n";
} else {
 	echo "ERROR virtual host config not written to file: $bvhostconfdir/$vhostsubdomain.conf\n";
 	exit();
}

// ////////////////////////////////////////////////////////////////
// shell_exec a2ensite $bvhostconfdir/$vhostsubdomain.conf

// so it will always be declared
$shella2enret = "";
// disable for testing other conditions without committing to this
$shella2enret = shell_exec("a2ensite $vhostsubdomain.conf");

//echo "shella2enret: $shella2enret\n";
// non-null (non-0) exit value from shell indicates an error
if ( str_contains($shella2enret,"ERROR") ) {
	//echo "ERROR: there was a problem executing the shell command to enable the vhostsubdomain $vhostsubdomain. Stopping.\n";
	exit();
} else {
	echo "SUCCESS: enabled vhostsubdomain $vhostsubdomain\n";
}

// ////////////////////////////////////////////////////////////////
// echo to console suggestion that systemctl restart apache2 be executed

echo "\n";
echo "Next steps:\n";
echo "This script did not restart apache2. That is up to you.\n";
echo "systemctl restart apache2\n";
echo "validate site on port 80\n";
echo "run certbot --apache to expand ssl cert\n";
echo "systemctl restart apache2\n";
echo "validate site on port 443\n";
echo "\n";

// ////////////////////////////////////////////////////////////////
// end engine section

Declaring the host name in DNS

Declare the host name in the DNS zone file for the domain:

Testing that the host name loads a “park page”

Use a web browser to visit the host name:

Executing commands as root

This chapter assumes that you are logged in as the root user. If you are not already root, escalate using this command:

sudo su

Installing the finger, whois, and unzip utilities

This script depends on the finger, whois, and unzip utilities.

Enter this command:

apt install finger whois unzip

Downloading and uncompressing the addvhost.zip file

Enter this command:

wget https://blog.gordonbuchan.com/files/addvhost.zip

Enter this command:

unzip addvhost.zip

Enter these commands:

mv addvhost.php /usr/bin
chmod 755 /usr/bin/addvhost.php

Enter this command:

addvhost.php

Completing the addvhost.php questionnaire, entering a username and a plaintext password

In this example, we decline the option to generate a username, and enter a value for the username. We also decline the option to generate a plaintext password, and enter a value for the plaintext password.

root@server01:~# addvhost.php

addvhost.php
Add a virtual host to Apache

Enter domain xxxxxxxx.xxx or subdomain xxxxxxxx.xxxxxxxx.xxx: webpresencestepbystep.ca
Do you wish to prepend the subdomain www.webpresencestepbystep.ca as well (n/y)? y
Generate a username? n
Enter username: webuserca
Generate a plaintext password? n
Enter plaintext password: password

values collected, generated, and derived

vhostsubdomain: webpresencestepbystep.ca
prependanswer: y
vhostusername: webuserca
genpassanswer: n
vhostpasswordplain: password
vhostpasswordhashed: $6$IdLp5YrW.Z3Tvnm$hlRvIBour47UcZrVm0QA2YgLp2z3C3e5W7PwiS3o.KbZz.mtFeCvWdew/eemdec3Wz9t.WEIuIm3Q2EKTuXYd1
vhosthomedir: /usr/web/webuserca
vhostwebdir: /usr/web/webuserca/webpresencestepbystep.ca

SUCCESS: enabled vhostsubdomain webpresencestepbystep.ca

Next steps:
This script did not restart apache2. That is up to you.
systemctl restart apache2
validate site on port 80
run certbot --apache to expand ssl cert
systemctl restart apache2
validate site on port 443

Enter this command:

systemctl restart apache2

Enter this command:

certbot --apache

Enter this command:

systemctl restart apache2

Visiting the virtual host

Use a web browser to visit the host name:

Completing the addvhost.php questionnaire, accepting a generated username and plaintext password

In this example, we accept the option to generate a username. We also accept the option to generate a plaintext password.

Take careful note of the plaintext password value, as shown in the “vhostpasswordplain” field.

root@server01:~# addvhost.php

addvhost.php
Add a virtual host to Apache

Enter domain xxxxxxxx.xxx or subdomain xxxxxxxx.xxxxxxxx.xxx: webpresencestepbystep.com
Do you wish to prepend the subdomain www.webpresencestepbystep.com as well (n/y)? y
Generate a username? y
Generate a plaintext password? y

values collected, generated, and derived

vhostsubdomain: webpresencestepbystep.com
prependanswer: y
vhostusername: webpresencestepbystep_com
genpassanswer: y
vhostpasswordplain: NQeQ2%VT
vhostpasswordhashed: $6$Woe9pPUwnXqUP$9RW60p6SSNfqLJSi4BeAyhe89mBpyTELk2/at7eJcKqou5Q9Y6Nti4P7EoyTV0CBfin6SxlvNHvkZjrpEGxxX0
vhosthomedir: /usr/web/webpresencestepbystep_com
vhostwebdir: /usr/web/webpresencestepbystep_com/webpresencestepbystep.com

SUCCESS: enabled vhostsubdomain webpresencestepbystep.com

Next steps:
This script did not restart apache2. That is up to you.
systemctl restart apache2
validate site on port 80
run certbot --apache to expand ssl cert
systemctl restart apache2
validate site on port 443

Enter this command:

systemctl restart apache2

Enter this command:

certbot --apache

Enter this command:

systemctl restart apache2

Visiting the virtual host

Use a web browser to visit the host name:

Previous step: Chapter 15: Using dwservice.net to provide remote technical support as an alternative to TeamViewer
Next step: Chapter 17: Using subdomains to host multiple websites under a single domain name