
Running multiple websites on a single server used to mean buying separate hosting for each domain. Apache virtual hosts change that. You can serve dozens of websites from one VPS, each with its own domain name, SSL certificate, and configuration settings.
This apache virtual hosts tutorial walks you through setting up name-based virtual hosts on Ubuntu 22.04 LTS. You'll configure multiple domains, secure them with SSL certificates, and troubleshoot common issues that trip up new administrators.
Understanding Apache Virtual Hosts
Apache virtual hosts let you serve different websites based on the domain name in the incoming request. When someone visits example.com, Apache serves files from one directory. When they visit testsite.net, Apache serves completely different content from another directory.
Two types exist: name-based and IP-based. Name-based virtual hosts share a single IP address but serve different content based on the Host header in the HTTP request. IP-based virtual hosts require a unique IP address for each website.
Name-based hosting handles 99% of use cases. You need IP-based hosting only when serving SSL sites on very old browsers that don't support Server Name Indication (SNI).
Prerequisites and Initial Setup
Start with a clean Ubuntu VPS running Apache 2.4. Update your system first:
sudo apt update && sudo apt upgrade -y
sudo apt install apache2 -y
Enable Apache to start on boot:
sudo systemctl enable apache2
sudo systemctl start apache2
Your server needs at least 1GB RAM to handle multiple websites comfortably. HostMyCode VPS plans include enough resources for hosting multiple domains with room to grow.
Create directories for your websites. Use a consistent structure that's easy to manage:
sudo mkdir -p /var/www/example.com/html
sudo mkdir -p /var/www/testsite.net/html
sudo mkdir -p /var/www/example.com/logs
sudo mkdir -p /var/www/testsite.net/logs
Creating Your First Virtual Host
Apache stores virtual host configurations in /etc/apache2/sites-available/. Create a configuration file for your first domain:
sudo nano /etc/apache2/sites-available/example.com.conf
Add this basic configuration:
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com/html
ErrorLog /var/www/example.com/logs/error.log
CustomLog /var/www/example.com/logs/access.log combined
<Directory /var/www/example.com/html>
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
The ServerName directive sets the primary domain. ServerAlias handles the www subdomain. DocumentRoot points to your website files.
Set proper ownership and permissions:
sudo chown -R www-data:www-data /var/www/example.com/
sudo chmod -R 755 /var/www/example.com/html/
Create a simple test page:
echo "<h1>Welcome to example.com</h1>" | sudo tee /var/www/example.com/html/index.html
Enabling Virtual Hosts and Testing
Enable your new virtual host:
sudo a2ensite example.com.conf
sudo systemctl reload apache2
Check Apache's configuration syntax before reloading:
sudo apache2ctl configtest
You should see "Syntax OK". Fix any errors before continuing.
Test your virtual host locally first. Add an entry to your /etc/hosts file on your local machine (not the server):
YOUR_SERVER_IP example.com
YOUR_SERVER_IP www.example.com
Visit http://example.com in your browser. You should see your test page.
For proper DNS setup, point your domain's A record to your server's IP address. Most DNS changes take 5-30 minutes to propagate globally.
Adding Multiple Virtual Hosts
Add a second website following the same pattern. Create the configuration file:
sudo nano /etc/apache2/sites-available/testsite.net.conf
Use similar configuration with different paths:
<VirtualHost *:80>
ServerName testsite.net
ServerAlias www.testsite.net
DocumentRoot /var/www/testsite.net/html
ErrorLog /var/www/testsite.net/logs/error.log
CustomLog /var/www/testsite.net/logs/access.log combined
<Directory /var/www/testsite.net/html>
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
Set ownership and create content:
sudo chown -R www-data:www-data /var/www/testsite.net/
sudo chmod -R 755 /var/www/testsite.net/html/
echo "<h1>Welcome to testsite.net</h1>" | sudo tee /var/www/testsite.net/html/index.html
Enable the site:
sudo a2ensite testsite.net.conf
sudo systemctl reload apache2
You can repeat this process for as many domains as your server resources allow. Most VPS configurations handle 20-50 low-traffic websites comfortably.
SSL Certificate Configuration
Secure your virtual hosts with Let's Encrypt SSL certificates. Install Certbot:
sudo apt install certbot python3-certbot-apache -y
Obtain certificates for both domains in one command:
sudo certbot --apache -d example.com -d www.example.com -d testsite.net -d www.testsite.net
Certbot automatically modifies your virtual host files. It adds SSL configuration and redirects from HTTP to HTTPS. Your sites now serve on both port 80 (HTTP) and port 443 (HTTPS).
For more detailed SSL management, check out our SSL certificate setup guide. It covers advanced configuration options.
Set up automatic renewal:
sudo systemctl enable certbot.timer
sudo systemctl start certbot.timer
Advanced Virtual Host Configuration
Real hosting environments need more sophisticated setups. Add PHP support by installing the necessary modules:
sudo apt install php8.1 php8.1-mysql php8.1-curl php8.1-gd php8.1-mbstring -y
sudo systemctl restart apache2
Configure different PHP versions per virtual host. Install multiple PHP versions:
sudo add-apt-repository ppa:ondrej/php -y
sudo apt update
sudo apt install php7.4 php7.4-fpm php8.1 php8.1-fpm -y
Enable the FPM module and disable the default PHP module:
sudo a2enmod proxy_fcgi setenvif
sudo a2enconf php8.1-fpm
sudo a2dismod php8.1
Modify your virtual host to use a specific PHP version:
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com/html
<FilesMatch \.php$>
SetHandler "proxy:unix:/var/run/php/php8.1-fpm.sock|fcgi://localhost"
</FilesMatch>
ErrorLog /var/www/example.com/logs/error.log
CustomLog /var/www/example.com/logs/access.log combined
</VirtualHost>
Performance Optimization
Optimize Apache for hosting multiple websites. Enable compression and caching modules:
sudo a2enmod deflate expires headers rewrite
sudo systemctl restart apache2
Add performance directives to your virtual hosts:
<Directory /var/www/example.com/html>
AllowOverride All
Require all granted
# Enable compression
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/x-javascript
</IfModule>
# Set cache headers
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpg "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/pdf "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
ExpiresByType application/x-javascript "access plus 1 month"
ExpiresByType application/x-shockwave-flash "access plus 1 month"
ExpiresByType image/x-icon "access plus 1 year"
ExpiresDefault "access plus 2 days"
</IfModule>
</Directory>
Tune Apache's worker settings in /etc/apache2/apache2.conf:
# For servers with 2-4GB RAM
ServerLimit 10
MaxRequestWorkers 250
ThreadsPerChild 25
Log Management and Monitoring
Each virtual host generates separate log files. Monitor them with log rotation to prevent disk space issues:
sudo nano /etc/logrotate.d/apache-vhosts
Add this configuration:
/var/www/*/logs/*.log {
daily
missingok
rotate 52
compress
delaycompress
notifempty
create 644 www-data www-data
postrotate
systemctl reload apache2
endscript
}
Monitor your virtual hosts with basic commands:
# Check active connections per site
sudo ss -tuln | grep :80
# Monitor access logs in real-time
sudo tail -f /var/www/example.com/logs/access.log
# Check error logs
sudo tail -20 /var/www/example.com/logs/error.log
For comprehensive monitoring, consider our VPS monitoring tutorial. It covers setting up automated alerts and resource tracking.
Security Hardening
Secure your virtual hosts by hiding Apache version information. Add to /etc/apache2/conf-available/security.conf:
ServerTokens Prod
ServerSignature Off
Enable the security configuration:
sudo a2enconf security
sudo systemctl restart apache2
Add security headers to your virtual hosts:
<IfModule mod_headers.c>
Header always set X-Frame-Options DENY
Header always set X-Content-Type-Options nosniff
Header always set X-XSS-Protection "1; mode=block"
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</IfModule>
Disable unnecessary modules and limit access to configuration files:
<Files ".ht*">
Require all denied
</Files>
<Directory /var/www/*/html>
Options -Indexes -Includes -ExecCGI
</Directory>
Managing multiple websites on a single server requires reliable hosting infrastructure. HostMyCode VPS hosting provides the performance and flexibility needed for multi-domain setups. Our managed VPS plans include Apache optimization and 24/7 support to keep your virtual hosts running smoothly.
Frequently Asked Questions
How many virtual hosts can I run on one server?
The limit depends on your server resources and website traffic. A 2GB VPS typically handles 20-50 low-traffic websites. High-traffic sites need dedicated resources. Monitor CPU and memory usage to find your server's capacity.
Can I use different PHP versions for each virtual host?
Yes, using PHP-FPM allows different PHP versions per virtual host. Install multiple PHP versions and configure each virtual host with specific FPM sockets. This is useful for legacy applications that require older PHP versions.
What happens if DNS isn't configured properly?
Apache serves the first virtual host (alphabetically by filename) as the default when DNS doesn't resolve correctly. Create a catch-all virtual host to handle undefined domains and show a custom error page instead.
How do I troubleshoot virtual host conflicts?
Use apache2ctl -S to see all configured virtual hosts and check for conflicts. Common issues include duplicate ServerName directives, incorrect DocumentRoot paths, or DNS problems. Check both Apache error logs and system logs for detailed error messages.
Is there a performance difference between many small sites versus fewer large sites?
Many small sites typically use fewer resources than fewer large sites with equivalent total traffic. Virtual hosts add minimal overhead. The main factors are total requests per second, database queries, and file I/O operations rather than the number of configured virtual hosts.