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