NewHalo Edge 3 is here: HTTP/3 everywhere and 42 edge locations.Learn more
Docs / Web servers

Host multiple sites with Apache virtual hosts

Web servers8 min readUbuntu 24.04 LTS

Apache calls this name-based virtual hosting. Each site gets its own file in /etc/apache2/sites-available/ that names the domain with ServerName, lists other names with ServerAlias, and points to its own folder. Apache matches the Host header of each request to the right virtual host.

Before you begin

  • Apache installed and running. See Install and configure Apache.
  • Two domains to host. This guide uses example.com and example.org.
  • A sudo user, such as deploy, and the server's IP address, 203.0.113.10.

Step 1: Create a folder for each site

Create a document root for each domain and give your user ownership so you can edit the files without sudo. Then add a test page to the first site.

sudo mkdir -p /var/www/example.com/public_html /var/www/example.org/public_html
sudo chown -R $USER:$USER /var/www/example.com /var/www/example.org
echo "<h1>Welcome to example.com</h1>" > /var/www/example.com/public_html/index.html

Step 2: Create a virtual host file

Open a new file with sudo nano /etc/apache2/sites-available/example.com.conf and enter the following. The Directory block sets permissions for the folder, and Options -Indexes stops Apache from listing files when no index page exists.

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    ServerAdmin webmaster@example.com

    DocumentRoot /var/www/example.com/public_html

    <Directory /var/www/example.com/public_html>
        Options -Indexes +FollowSymLinks
        AllowOverride None
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/example.com-error.log
    CustomLog ${APACHE_LOG_DIR}/example.com-access.log combined
</VirtualHost>

Step 3: Repeat for the second site

Create /etc/apache2/sites-available/example.org.conf with the same structure. Change the domain names, the DocumentRoot and the log file names to match example.org, and add a test page in its public_html folder.

Step 4: Enable the sites and disable the default

a2ensite links a site into the active configuration, and a2dissite removes that link. Apache ships with a default site called 000-default, which you can disable so it does not answer requests meant for your domains.

sudo a2ensite example.com.conf
sudo a2ensite example.org.conf
sudo a2dissite 000-default.conf
To activate the new configuration, you need to run:
  systemctl reload apache2
Careful: Apache uses the first virtual host it finds for any name it does not recognize. If you disable the default and a virtual host has no matching ServerName, every request may land on the wrong site.

Step 5: Test and reload

Check the configuration, then reload Apache so the changes take effect.

sudo apache2ctl configtest
sudo systemctl reload apache2
Syntax OK

Step 6: Test each site by name

Send requests with the Host header set to each domain. This works before DNS points at your server.

curl -H "Host: example.com" http://203.0.113.10/
curl -H "Host: example.org" http://203.0.113.10/
<h1>Welcome to example.com</h1>
<h1>Welcome to example.org</h1>

Step 7: Review the virtual host map

To see how Apache has interpreted your files, list every virtual host with its port and names:

sudo apache2ctl -S

Each site should appear with its ServerName and DocumentRoot. If a site is missing, it is probably not enabled.

Troubleshooting

  • The wrong site appears for a domain. Check the output of sudo apache2ctl -S. Make sure each file has its own ServerName and that no two files claim the same name.
  • 403 Forbidden. The Require all granted line may be missing, or the folder is not readable. Confirm the Directory block matches your DocumentRoot.
  • A warning about the fully qualified domain name. Apache could not determine a server name. Silence it with echo "ServerName localhost" | sudo tee /etc/apache2/conf-available/servername.conf, then run sudo a2enconf servername and reload Apache.
  • configtest fails. The message names the file and line. Fix it and run configtest again before reloading.

Next steps

Once both domains respond, add HTTPS with Enable HTTPS with free TLS certificates. Then use Redirect HTTP to HTTPS and www to non-www so every visitor reaches one secure address.

Something not working? Chat or email our support team and we will help you get unstuck.

Contact support