This is the procedure, with examples in FreeBSD, for how to create a virtual host in Apache HTTP server, including, how to create a seperate system user account, create the document root directory, setting permissions and constructing the virtual host configuration in Apache.

What is a virtual host in an Apache HTTP server?

The term virtual host in an Apache HTTP server means the practice of serving more than one website on the same physical server or virtual private server (VPS). This is possible, because the Apache HTTP server supports IP-based and name-based virtual hosts, which means, that it can serve several IP addresses, several ports on each IP address and several hostnames on each of those. See Apache Virtual Host documentation and VirtualHost Examples by The Apache Software Foundation.

Create system user account for the virtual host.

You might want to serve your new virtual host in a seperate system user account. This has several advantages, such as added security.

Authentication with SSH key.

In the following example, the user will be assigned the username example, the group sftp and the shell /etc/nologin. The group will be used to restrict the user to its home directory. The shell will restrict the user from having access to a command line enterpreter shell. The user will be able to authenticate with an SSH key.

# pw useradd -n example -d /home/example -g sftp -s /usr/sbin/nologin
# mkdir -m 0755 /home/example
# mkdir -m 0750 /home/example/.ssh
# mkdir -m 0755 /home/example/www
# cat example.key >> /home/example/.ssh/authorized_keys
# chmod 0640 /home/example/.ssh/authorized_keys
# chown -R root:sftp /home/example

Authentication with password.

In the following example, the user will be assigned the username example, the group sftp, the shell /etc/nologin an the password AbCd. The group will be used to restrict the user to its home directory. The shell will restrict the user from having access to a command line enterpreter shell.

# echo "AbCd" | pw useradd -n example -d /home/example -g sftp -s /usr/sbin/nologin -h 0
# mkdir -m 0755 /home/example
# mkdir -m 0755 /home/example/www
# chown -R root:sftp /home/example

Create a document root directory for virtual host.

In the following example, the website, that will be served as a virtual host, will be served from a directory within the user home. This is also known as the document root directory. The permissions does not allow the user to rename nor delete the directory. The permissions allow Apache HTTP server to read the HTML documents.

# mkdir -m 0755 /home/example/www/www.example.com

Create a virtual host in Apache HTTP server.

Go to the configuration files, where virtual hosts are configured. On FreeBSD, these are located in /usr/local/etc/apache24/extra.

# cd /usr/local/etc/apache24/extra

Define general constants as needed. This could include your log directory, lists of IP addresses of privileged users and similar constants, you might want to use in your virtual hosts.

In the following example, the log directory for Apache HTTP is set to /var/log/http. The log directory will be storing HTTP queries to the virtual host and errors, related to the virtual host. Other often used constants are also defined.

# nano httpd-vhosts.conf
Define log "/var/log/http"
Define vhosts "etc/apache24/extra"
Define ssl "${vhosts}/ssl.conf"
Define letsencrypt "${vhosts}/letsencrypt.conf"
Define wordpress "${vhosts}/wordpress.conf"

Create a new configuration file for your new virtual host. This way, you will not confuse your configuration with other virtual hosts.

# nano www.example.com.conf

Example of a virtual host configuration in Apache.

Define host "www.example.com"
Define user "example"
<VirtualHost *:80>
  ServerName ${host}
  DocumentRoot "/home/${user}/www/${host}"
  ErrorLog "${log}/${host}-error.log"
  CustomLog "${log}/${host}-common.log" combined
</VirtualHost>

Example of a virtual host configuration with SSL.

Define host "www.example.com"
Define user "example"
<VirtualHost *:443>
  ServerName ${host}
  DocumentRoot "/home/${user}/www/${host}"
  ErrorLog "${log}/${host}-error.log"
  CustomLog "${log}/${host}-common.log" combined
  Include ${ssl}
  Include ${letsencrypt}
</VirtualHost>
<VirtualHost *:80>
  ServerName ${host}
  Redirect permanent / https://${host}/
</VirtualHost>

Example of SSL engine configuration in Apache.

SSLEngine on
SSLProtocol all -SSLv2 -SSLv3
SSLHonorCipherOrder on
SSLCipherSuite "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384   EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH EDH+aRSA :!R$

Example of Let’s Encrypt configuration in Apache.

SSLCertificateFile /usr/local/etc/letsencrypt/live/${host}/cert.pem
SSLCertificateChainFile /usr/local/etc/letsencrypt/live/${host}/chain.pem
SSLCertificateKeyFile /usr/local/etc/letsencrypt/live/${host}/privkey.pem

Example of a virtual host configuration with WordPress protection.

Define host "www.example.com"
Define user "example"
Include ${wordpress}
<VirtualHost *:443>
  ServerName ${host}
  DocumentRoot "/home/${user}/www/${host}"
  ErrorLog "${log}/${host}-error.log"
  CustomLog "${log}/${host}-common.log" combined
  Include ${ssl}
  Include ${letsencrypt}
</VirtualHost>

Example of WordPress protection configuration in virtual host.

<Directory "/usr/home/${user}/www/${host}">
  <Files "xmlrpc.php">
    Require all denied
    Require ip ${admin}
  </Files>
  <Files "wp-cron.php">
    Require all denied
    Require ip ${admin}
  </Files>
  <Files "wp-login.php">
    Require all denied
    Require ip ${admin}
  </Files>
</Directory>
<Directory "/usr/home/${user}/www/${host}/wp-admin">
  <Files "admin-ajax.php">
    Require all granted
  </Files>
  Require all denied
  Require ip ${admin}
</Directory>

Example of a virtual host configuration with restricted Webalizer statistics directory.

Define host "www.example.com"
Define user "example"
Include ${webalizer}
<VirtualHost *:443>
  ServerName ${host}
  DocumentRoot "/home/${user}/www/${host}"
  ErrorLog "${log}/${host}-error.log"
  CustomLog "${log}/${host}-common.log" combined
  Include ${ssl}
  Include ${letsencrypt}
</VirtualHost>

Example of Webalizer configuration in virtual host.

<Directory "/usr/home/${user}/www/${host}/webalizer">
  Require all denied
  Require ip ${admin}
</Directory>

Include the virtual host configuration in Apache.

When you have constructed your new virtual host, it is ready to be indcluded in the main Apache configuration. Include your new virtual host in the virtual hosts configuration file.

# nano httpd-vhosts.conf
Include ${vhosts}/www.example.com.conf

Sanity check of Apache HTTP server configuration.

Before you reload Apache, which will make Apache read your new virtual host configuration file, you should have Apache perform a sanity check of the configuration files.

In the following example, Apache on FreeBSD will perform a sanity check on the configuration files. This includes access to directories and validity of declarations.

# service apache24 configtest
Performing sanity check on apache24 configuration:
Syntax OK

Reload Apache HTTP server.

In the following example, Apache is reloaded on a FreeBSD system. Your new virtual host configuration file will be loaded and Apache will be serving the virtual host.

# service apache24 reload

Test virtual host with HTML document.

You can now test your new virtual host by creating a HTML document. In the following example, a very basic Hello, World HTML document is created.

# cd /home/example/www/www.example.com
# echo "Hello, World!" > index.html
# chown example:sftp index.html
# chmod 0664 index.html

Examine logs for more detailed information about errors.

In the event of error, such as error messages from Apache, the logs can provide more detailed information. In the following examples, the logs are examined for more detailed information.

# tail /var/log/http/www.example.com-common.log
# tail /var/log/http/www.example.com-error.log

More about virtual hosts in Apache HTTP server.

Configure Apache HTTP web server to redirect HTTP to HTTPS. How to block user agents with Apache .htaccess. How to install WordPress from the command line on FreeBSD.