Apache Virtual Hosts Setup for Multiple Domains
Apache Virtual Hosts allow a single VPS to host multiple websites on one IP address. Each domain has its own document root, configuration, and SSL certificate. This is essential knowledge before deploying multiple websites on a single VPS server.
Install Apache
sudo apt update
sudo apt install apache2 -y
sudo systemctl enable --now apache2
Create Virtual Hosts
# Create document root
sudo mkdir -p /var/www/example.com/public_html
sudo chown -R $USER:www-data /var/www/example.com
sudo chmod -R 755 /var/www/example.com
# Create test index page
echo "example.com is working
" > /var/www/example.com/public_html/index.html
# Create virtual host config
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
<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>
# Enable site
sudo a2ensite example.com.conf
sudo a2enmod rewrite # for .htaccess redirects
sudo systemctl reload apache2
Add SSL with Let's Encrypt
sudo apt install certbot python3-certbot-apache -y
# Issue certificate (DNS must point to VPS first)
sudo certbot --apache -d example.com -d www.example.com
# Certbot automatically updates config with HTTPS redirect and SSL settings
# View the updated config
cat /etc/apache2/sites-available/example.com-le-ssl.conf
Separate PHP-FPM Pool Per Virtual Host
For better security, running a separate PHP-FPM pool for each website is recommended instead of using a shared pool:
sudo apt install php8.3-fpm -y
sudo a2enmod proxy_fcgi setenvif
sudo a2enconf php8.3-fpm
# Add inside VirtualHost block:
<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost"
</FilesMatch>
/etc/php/8.3/fpm/pool.d/www.conf with the site name, then change the user, group, and listen socket. This ensures each site's PHP runs under its own user account.
Verify Virtual Host is Working Correctly
# Check config syntax
sudo apache2ctl configtest
# View active virtual hosts
sudo apache2ctl -S
# Test with curl
curl -H "Host: example.com" http://localhost
# Check error logs
sudo tail -f /var/log/apache2/example.com-error.log
apache2ctl -S displays all virtual hosts with their ports and DocumentRoot, helping you debug which vhost a request is being routed to.
Common Issues & Troubleshooting
Seeing Apache Default Page Instead of Your Site
The default site is still active or the ServerName doesn't match the request DNS. Disable the default site:
sudo a2dissite 000-default.conf
sudo systemctl reload apache2
# Check vhost matching
sudo apache2ctl -S | grep "example.com"
403 Forbidden When Accessing the Site
Directory permissions are incorrect or AllowOverride is not set properly:
# Check permissions
ls -la /var/www/example.com/public_html/
# Fix permissions
sudo chown -R www-data:www-data /var/www/example.com
sudo chmod -R 755 /var/www/example.com
# Check SELinux (if enabled)
ls -laZ /var/www/example.com/
.htaccess Not Working
AllowOverride must be set to All and mod_rewrite must be enabled:
sudo a2enmod rewrite
sudo systemctl reload apache2
# Check AllowOverride in config
grep -r "AllowOverride" /etc/apache2/sites-enabled/
SSL Certificate from One Site Used for Another
Apache uses SNI to select the correct certificate based on ServerName. Verify the ServerName in your SSL config is correct:
# View SSL virtual hosts
sudo apache2ctl -S | grep "*:443"
# Check which certificate the site is using
echo | openssl s_client -servername example.com -connect localhost:443 2>/dev/null | openssl x509 -noout -subject
Frequently Asked Questions
Is Apache or Nginx Better for Virtual Hosting?
Both support virtual hosting well. Nginx uses less memory and is better suited for static files and reverse proxies. Apache excels with .htaccess support, which many PHP applications and WordPress installations rely on. If you're hosting many PHP-based applications that need .htaccess, Apache is more convenient.
How Many Domains Can Run on a Single VPS?
Theoretically unlimited, but constrained by RAM and CPU. A 1GB RAM VPS can comfortably run 10-20 WordPress sites with low traffic. However, if your sites have high traffic, you need to ensure sufficient resources are available for all sites.
Can Each Virtual Host Have Separate Logs?
Yes, each VirtualHost block can have separate ErrorLog and CustomLog directives, making it easy to debug individual sites without filtering through combined logs. You should set separate logs for every site.