What's Actually Happening
Apache VirtualHost configuration not taking effect. Requests show default page or wrong website content.
The Error You'll See
Browser shows default page:
# Accessing site1.example.com shows Apache default page
# Instead of site1 contentWrong website served:
# Accessing site2.example.com shows site1 content
# VirtualHost pointing to wrong document rootConfiguration ignored:
```bash $ apachectl -S
VirtualHost configuration: *:80 is a NameVirtualHost default server site1.example.com port 80 namevhost site1.example.com # site2.example.com not listed! ```
Why This Happens
- 1.Syntax error - VirtualHost config has syntax error
- 2.Not enabled - Site config not enabled with a2ensite
- 3.Wrong ServerName - ServerName doesn't match request
- 4.DocumentRoot wrong - Document root path incorrect
- 5.DNS not resolving - Domain not pointing to server
- 6.Port mismatch - VirtualHost on wrong port
Step 1: Check Apache Status
```bash # Check Apache status: systemctl status apache2 # Or: systemctl status httpd
# Check Apache version: apache2 -v httpd -v
# Check loaded modules: apache2ctl -M apachectl -M
# Check configuration syntax: apache2ctl -t apachectl -t
# Check VirtualHost configuration: apache2ctl -S apachectl -S
# Output shows all VirtualHosts # Syntax OK should display ```
Step 2: List and Enable VirtualHosts
```bash # List available sites: ls -la /etc/apache2/sites-available/
# List enabled sites: ls -la /etc/apache2/sites-enabled/
# Enable site: a2ensite site1.conf a2ensite site2.conf
# Disable site: a2dissite site1.conf
# Check symlink created: ls -la /etc/apache2/sites-enabled/
# Should be symlink to sites-available
# Reload Apache: systemctl reload apache2
# Or restart: systemctl restart apache2 ```
Step 3: Check VirtualHost Configuration
```bash # View VirtualHost config: cat /etc/apache2/sites-available/site1.conf
# Basic VirtualHost: <VirtualHost *:80> ServerName site1.example.com ServerAlias www.site1.example.com DocumentRoot /var/www/site1
ErrorLog ${APACHE_LOG_DIR}/site1_error.log CustomLog ${APACHE_LOG_DIR}/site1_access.log combined
<Directory /var/www/site1> Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory> </VirtualHost>
# Check for syntax errors: apache2ctl -t
# Validate specific config: apache2ctl -t -f /etc/apache2/sites-available/site1.conf ```
Step 4: Check ServerName Configuration
```bash # ServerName must match incoming request:
# Test with curl: curl -H "Host: site1.example.com" http://server-ip/
# Should return site1 content
# Check ServerName in config: grep ServerName /etc/apache2/sites-available/*.conf
# ServerName is required for name-based VirtualHost # Without ServerName, uses first VirtualHost
# Check global ServerName: grep ServerName /etc/apache2/apache2.conf grep ServerName /etc/apache2/conf-enabled/servername.conf
# Set global ServerName: echo "ServerName localhost" | sudo tee /etc/apache2/conf-available/servername.conf a2enconf servername systemctl reload apache2 ```
Step 5: Check Document Root
```bash # Check document root exists: ls -la /var/www/site1
# Check permissions: stat /var/www/site1
# Apache user needs read access: chown -R www-data:www-data /var/www/site1 chmod -R 755 /var/www/site1
# Check Apache user: ps aux | grep apache # User: www-data or apache
# Test with index file: echo "Site 1" > /var/www/site1/index.html
# Check SELinux (if enabled): getenforce # If Enforcing, set context: chcon -R -t httpd_sys_content_t /var/www/site1
# Check directory access: # Must have <Directory> block allowing access: <Directory /var/www/site1> Require all granted </Directory> ```
Step 6: Check DNS Resolution
```bash # Check DNS resolves to server: dig site1.example.com +short nslookup site1.example.com
# Should return server IP
# Check from server: curl http://site1.example.com
# Test with local hosts: echo "10.0.0.1 site1.example.com" >> /etc/hosts
# Check if domain pointing elsewhere: whois site1.example.com
# For local testing, use curl with Host header: curl -H "Host: site1.example.com" http://server-ip/ ```
Step 7: Check Port Configuration
```bash # Check ports Apache listens on: grep -r "Listen" /etc/apache2/ports.conf grep -r "Listen" /etc/apache2/apache2.conf
# VirtualHost port must match: # If listening on 80: Listen 80
# VirtualHost must be: <VirtualHost *:80>
# For HTTPS: Listen 443 <VirtualHost *:443>
# Check all listening ports: ss -tlnp | grep apache
# Check VirtualHost ports: apache2ctl -S | grep port
# Port order matters - first VirtualHost for port is default ```
Step 8: Check VirtualHost Order
```bash # Check VirtualHost order: apache2ctl -S
# Output shows order: # *:80 is a NameVirtualHost # default server default-site # port 80 namevhost site1.example.com # port 80 namevhost site2.example.com
# First VirtualHost is default for unmatched requests # Default typically: /etc/apache2/sites-enabled/000-default.conf
# Create explicit default: <VirtualHost *:80> ServerName default DocumentRoot /var/www/html </VirtualHost>
# File naming affects order: # 000-default.conf loads first # site1.conf loads after # z-site1.conf loads last ```
Step 9: Debug VirtualHost Issues
```bash # Enable rewrite logging: # In VirtualHost: LogLevel alert rewrite:trace3
# Check access logs: tail -f /var/log/apache2/access.log
# Check error logs: tail -f /var/log/apache2/error.log
# Check specific site logs: tail -f /var/log/apache2/site1_error.log
# Enable debug level: LogLevel debug
# Test config without reload: apache2ctl -t -D DUMP_VHOSTS
# Check loaded modules for VirtualHost: apache2ctl -M | grep vhost # Should show: vhost_alias_module
# Test with lynx: lynx http://site1.example.com ```
Step 10: Apache VirtualHost Verification Script
```bash # Create verification script: cat << 'EOF' > /usr/local/bin/check-apache-vhost.sh #!/bin/bash
echo "=== Apache Status ===" systemctl status apache2 --no-pager | head -5
echo "" echo "=== VirtualHost Configuration ===" apache2ctl -S 2>&1
echo "" echo "=== Enabled Sites ===" ls -la /etc/apache2/sites-enabled/
echo "" echo "=== Available Sites ===" ls -la /etc/apache2/sites-available/
echo "" echo "=== Listening Ports ===" ss -tlnp | grep apache
echo "" echo "=== Document Roots ===" for conf in /etc/apache2/sites-enabled/*.conf; do echo "File: $conf" grep -E "ServerName|DocumentRoot" "$conf" | head -5 echo "" done
echo "=== Testing VirtualHosts ===" for domain in $(grep -h ServerName /etc/apache2/sites-enabled/*.conf | awk '{print $2}'); do echo "Testing $domain:" curl -s -I -H "Host: $domain" http://localhost/ | head -3 echo "" done
echo "=== Apache Error Logs (last 10) ===" tail -10 /var/log/apache2/error.log EOF
chmod +x /usr/local/bin/check-apache-vhost.sh
# Run: /usr/local/bin/check-apache-vhost.sh ```
Apache VirtualHost Checklist
| Check | Command | Expected |
|---|---|---|
| Syntax | apache2ctl -t | Syntax OK |
| Site enabled | ls sites-enabled | Symlink exists |
| ServerName | grep ServerName | Domain matches |
| DocumentRoot | ls -la | Directory exists |
| DNS | dig domain | Resolves to server |
| Port | ss -tlnp | Apache listening |
Verify the Fix
```bash # After fixing VirtualHost
# 1. Check syntax apache2ctl -t // Syntax OK
# 2. Check VirtualHosts apache2ctl -S // All sites listed
# 3. Test with curl curl -H "Host: site1.example.com" http://localhost/ // Returns site1 content
# 4. Check logs tail -f /var/log/apache2/site1_access.log // Requests logged
# 5. Test DNS curl http://site1.example.com/ // Returns correct site
# 6. Test all VirtualHosts for site in site1 site2; do curl -s http://$site.example.com | head -1 done // Each returns correct content ```
Related Issues
- [Fix Apache 403 Forbidden](/articles/fix-apache-403-forbidden)
- [Fix Apache Configuration Error](/articles/fix-apache-configuration-error)
- [Fix Apache SSL Certificate Error](/articles/fix-apache-ssl-certificate-error)