Apache virtual hosts allow you to run multiple websites on a single server, each with its own domain name, document root, and configuration. This is the standard approach for hosting multiple sites on shared or dedicated servers.
Types of Virtual Hosts
- Name-based: Multiple sites share one IP address, differentiated by hostname (most common)
- IP-based: Each site gets a dedicated IP address
- Port-based: Different sites on different ports
Creating a Name-Based Virtual Host
# Create document root
sudo mkdir -p /var/www/example.com/public_html
sudo mkdir -p /var/www/blog.example.com/public_html
sudo chown -R www-data:www-data /var/www/
# Create virtual host file
sudo nano /etc/apache2/sites-available/example.com.conf
Virtual Host Configuration
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com/public_html
<Directory /var/www/example.com/public_html>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/example.com-error.log
CustomLog ${APACHE_LOG_DIR}/example.com-access.log combined
</VirtualHost>
Enabling the Site
# Enable the virtual host
sudo a2ensite example.com.conf
# Disable the default site
sudo a2dissite 000-default.conf
# Enable mod_rewrite (for .htaccess rules)
sudo a2enmod rewrite
# Test configuration
sudo apache2ctl configtest
# Reload Apache
sudo systemctl reload apache2
SSL Virtual Host with Let's Encrypt
<VirtualHost *:443>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com/public_html
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
<Directory /var/www/example.com/public_html>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
Header always set Strict-Transport-Security "max-age=63072000"
</VirtualHost>
# HTTP to HTTPS redirect
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
Redirect permanent / https://example.com/
</VirtualHost>
PHP Configuration Per Virtual Host
<VirtualHost *:80>
ServerName phpapp.example.com
DocumentRoot /var/www/phpapp/public
<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost"
</FilesMatch>
# Custom PHP settings for this site
php_value upload_max_filesize 50M
php_value post_max_size 50M
php_value memory_limit 256M
</VirtualHost>
Security Best Practices
- Disable directory listing with
Options -Indexes - Use
AllowOverride Allonly when needed - Set proper file ownership to www-data
- Enable and enforce HTTPS for all sites
- Implement security headers (HSTS, CSP, X-Frame-Options)
- Separate log files per virtual host for easier debugging
Troubleshooting
# Test configuration syntax
sudo apache2ctl configtest
# Check which virtual hosts are enabled
sudo apache2ctl -S
# Check Apache error log
sudo tail -f /var/log/apache2/error.log
# Common issues:
# - DNS not pointing to server IP
# - ServerName mismatch
# - Document root permissions
# - Missing mod_rewrite or mod_ssl
Apache virtual hosts are fundamental to web server administration. Master this skill and you can host dozens of websites efficiently on a single server, each with its own configuration and security settings.