Apache Virtual Hosts allow a single server to host multiple independent websites, each identified by its own domain name and configuration file.
Prerequisites
- Apache installed and running
- One or more domains with DNS pointing to your VPS
Step 1 — Create the Website Directory
sudo mkdir -p /var/www/example.com/public_html
sudo chown -R $USER:$USER /var/www/example.com/public_html
Step 2 — Add a Test Page
nano /var/www/example.com/public_html/index.html
<h1>Welcome to example.com</h1>
Step 3 — Create the Virtual Host File
sudo nano /etc/apache2/sites-available/example.com.conf
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com/public_html
ErrorLog ${APACHE_LOG_DIR}/example.com-error.log
CustomLog ${APACHE_LOG_DIR}/example.com-access.log combined
<Directory /var/www/example.com/public_html>
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
Step 4 — Enable the Site
sudo a2ensite example.com.conf
Step 5 — Disable the Default Site (Optional)
sudo a2dissite 000-default.conf
Step 6 — Test and Reload
sudo apache2ctl configtest
sudo systemctl reload apache2
Repeat for Additional Domains
Create a new .conf file per domain, each with its own ServerName and DocumentRoot.
Adding HTTPS
sudo certbot --apache -d example.com -d www.example.com
Common Errors
"AH00558: apache2 could not reliably determine the server's fully qualified domain name" — harmless warning; set ServerName globally in /etc/apache2/apache2.conf to silence it.
403 Forbidden on a specific site — verify both file permissions and the <Directory> block's Require all granted.
Wrong site served for a domain — virtual hosts are matched in file load order when ServerName conflicts exist; check apache2ctl -S to see the resolved order.
Best Practices
- One
.conffile per domain for clarity - Always run
apache2ctl configtestbefore reloading - Set correct ownership (
www-data) on each site's document root
FAQ
Do I need AllowOverride All?
Only if the site uses .htaccess files (common for WordPress); otherwise AllowOverride None is slightly more performant.
Related Articles
- How to Install Apache on Ubuntu & Debian
- How to Install Let's Encrypt SSL with Certbot (Nginx & Apache)
- How to Fix Common Apache Errors (500/403/AH Errors)
