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:

bash
# Accessing site1.example.com shows Apache default page
# Instead of site1 content

Wrong website served:

bash
# Accessing site2.example.com shows site1 content
# VirtualHost pointing to wrong document root

Configuration 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. 1.Syntax error - VirtualHost config has syntax error
  2. 2.Not enabled - Site config not enabled with a2ensite
  3. 3.Wrong ServerName - ServerName doesn't match request
  4. 4.DocumentRoot wrong - Document root path incorrect
  5. 5.DNS not resolving - Domain not pointing to server
  6. 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

CheckCommandExpected
Syntaxapache2ctl -tSyntax OK
Site enabledls sites-enabledSymlink exists
ServerNamegrep ServerNameDomain matches
DocumentRootls -laDirectory exists
DNSdig domainResolves to server
Portss -tlnpApache 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 ```

  • [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)