What's Actually Happening

Apache virtual host configuration exists but requests to the domain return 404, default page, or connection refused. The virtual host is not properly serving content despite configuration appearing correct.

The Error You'll See

404 Not Found:

```bash $ curl http://mydomain.local

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>404 Not Found</title> </head><body> <h1>Not Found</h1> The requested URL was not found on this server. </body></html> ```

Default page served:

```bash $ curl http://mydomain.local

# Shows default Apache page, not site content ```

Connection refused:

```bash $ curl http://mydomain.local:8080

curl: (7) Failed to connect to mydomain.local port 8080: Connection refused ```

Why This Happens

  1. 1.Syntax error in config - Invalid virtual host configuration
  2. 2.DocumentRoot wrong - Path doesn't exist or wrong permissions
  3. 3.Port not listening - Apache not configured to listen on port
  4. 4.DNS not resolving - Domain not pointing to server
  5. 5.Default vhost override - Default vhost takes precedence
  6. 6.Module missing - Required module not enabled

Step 1: Check Apache Status

```bash # Check Apache is running systemctl status apache2 systemctl status httpd

# Check Apache processes ps aux | grep apache ps aux | grep httpd

# Check listening ports ss -tlnp | grep apache netstat -tlnp | grep :80

# Check Apache version apache2 -v httpd -v

# Check loaded modules apache2ctl -M apachectl -M

# Test configuration syntax apache2ctl configtest apachectl configtest

# Expected: Syntax OK ```

Step 2: Verify Virtual Host Configuration

```bash # List virtual hosts apache2ctl -S apachectl -S

# Output shows: VirtualHost configuration: *:80 is a NameVirtualHost default server default.example.com (/etc/apache2/sites-enabled/000-default.conf) port 80 namevhost mydomain.local (/etc/apache2/sites-enabled/mydomain.conf) port 80 namevhost otherdomain.local (/etc/apache2/sites-enabled/other.conf)

# Check if virtual host is enabled ls /etc/apache2/sites-enabled/ a2ensite mydomain a2dissite mydomain

# Check virtual host file cat /etc/apache2/sites-enabled/mydomain.conf

# Check configuration syntax apache2ctl -t -D DUMP_VHOSTS ```

Step 3: Verify DocumentRoot Exists

```bash # Check DocumentRoot in config grep DocumentRoot /etc/apache2/sites-enabled/mydomain.conf

# Verify path exists ls -la /var/www/mydomain/

# Check permissions stat /var/www/mydomain/

# Apache needs read access chmod 755 /var/www/mydomain/ chown -R www-data:www-data /var/www/mydomain/

# Check for index file ls /var/www/mydomain/index.html ls /var/www/mydomain/index.php

# If no index file, create one: echo "<h1>Test Page</h1>" > /var/www/mydomain/index.html

# Check directory permissions ls -la /var/www/ ls -la /var/www/mydomain/

# Check SELinux (if enabled) getenforce ls -laZ /var/www/mydomain/

# Fix SELinux context: chcon -R -t httpd_sys_content_t /var/www/mydomain/ ```

Step 4: Check Port Configuration

```bash # Check Apache listening ports grep -r Listen /etc/apache2/ grep -r Listen /etc/httpd/

# In ports.conf or main config: Listen 80 Listen 8080 # If virtual host uses port 8080

# Verify virtual host uses correct port grep VirtualHost /etc/apache2/sites-enabled/mydomain.conf

<VirtualHost *:80> # Correct - matches Listen directive # Or: <VirtualHost 192.168.1.10:80> # Specific IP and port

# Check if port is open ss -tlnp | grep :80 netstat -tlnp | grep :80

# Test connection curl -I http://localhost/ curl -I http://127.0.0.1/ ```

Step 5: Fix Virtual Host Configuration

```apache # Correct virtual host configuration

<VirtualHost *:80> ServerName mydomain.local ServerAlias www.mydomain.local

DocumentRoot /var/www/mydomain

<Directory /var/www/mydomain> Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory>

ErrorLog ${APACHE_LOG_DIR}/mydomain-error.log CustomLog ${APACHE_LOG_DIR}/mydomain-access.log combined </VirtualHost>

# Common mistakes:

# WRONG: Missing ServerName <VirtualHost *:80> DocumentRoot /var/www/mydomain # No ServerName - won't match any request </VirtualHost>

# WRONG: Wrong DocumentRoot path <VirtualHost *:80> ServerName mydomain.local DocumentRoot /var/www/wrong-path </VirtualHost>

# WRONG: Directory permissions missing <VirtualHost *:80> ServerName mydomain.local DocumentRoot /var/www/mydomain # No <Directory> block - may deny access </VirtualHost>

# Enable site a2ensite mydomain.conf systemctl reload apache2 ```

Step 6: Check DNS Resolution

```bash # Test DNS resolution dig mydomain.local nslookup mydomain.local

# Check if domain points to server IP curl http://$(dig +short mydomain.local)/

# For local testing, add to /etc/hosts: 192.168.1.10 mydomain.local www.mydomain.local

# Test with hosts file curl http://mydomain.local/

# Check if request reaches server # Add to Apache access log monitoring: tail -f /var/log/apache2/mydomain-access.log curl http://mydomain.local/

# See request in log ```

Step 7: Check Default Virtual Host Priority

```bash # Apache uses first virtual host as default for unmatched requests

# List virtual hosts by priority ls -la /etc/apache2/sites-enabled/

# Files are loaded alphabetically: # 000-default.conf - first, becomes default # mydomain.conf - loaded after

# If mydomain.conf has syntax error, requests go to default

# Ensure default doesn't match your domain: grep ServerName /etc/apache2/sites-enabled/000-default.conf

# Or disable default: a2dissite 000-default systemctl reload apache2

# Or make mydomain.conf first: mv /etc/apache2/sites-enabled/mydomain.conf /etc/apache2/sites-enabled/001-mydomain.conf

# Reload systemctl reload apache2 ```

Step 8: Enable Required Modules

```bash # Check required modules for virtual host

# For .htaccess support: a2enmod rewrite a2enmod headers

# For PHP: a2enmod php8.1 # Or: a2enmod proxy_fcgi setenvif a2enconf php8.1-fpm

# For SSL: a2enmod ssl

# Check enabled modules apache2ctl -M | grep rewrite apache2ctl -M | grep ssl

# Restart after enabling systemctl restart apache2

# Test configuration after changes apache2ctl configtest ```

Step 9: Test Virtual Host Directly

```bash # Test with explicit Host header curl -H "Host: mydomain.local" http://localhost/

# Test with verbose output curl -v -H "Host: mydomain.local" http://localhost/

# Test with IP address curl -H "Host: mydomain.local" http://192.168.1.10/

# Test different paths curl -H "Host: mydomain.local" http://localhost/test.html

# Check Apache response headers curl -I -H "Host: mydomain.local" http://localhost/

# Compare with default curl -I http://localhost/ ```

Step 10: Debug with Apache Logs

```bash # Check error log tail -f /var/log/apache2/error.log tail -f /var/log/apache2/mydomain-error.log

# Enable debug logging # In apache2.conf or virtual host: LogLevel debug

# Reload systemctl reload apache2

# Watch logs while testing tail -f /var/log/apache2/mydomain-error.log & curl http://mydomain.local/

# Check access log tail -f /var/log/apache2/mydomain-access.log

# Common errors: # "Permission denied" - DocumentRoot access denied # "File does not exist" - Path wrong # "No matching Directory" - Directory block missing

# Use strace for deeper debugging strace -p $(pgrep apache2 | head -1) -e trace=open,read,write ```

Apache Virtual Host Checklist

CheckCommandExpected
Syntaxapache2ctl configtestSyntax OK
Vhost enabledls sites-enabledConfig present
DocumentRootls -la pathExists, readable
Port listeningss -tlnpPort open
DNS/Hostsdig/curlResolves to server
Modulesapache2ctl -MRequired enabled

Verify the Fix

```bash # After fixing virtual host configuration

# 1. Check syntax is valid apache2ctl configtest // Syntax OK

# 2. Verify virtual host loaded apache2ctl -S | grep mydomain // Shows virtual host configuration

# 3. Test request curl -H "Host: mydomain.local" http://localhost/ // Returns site content, not default

# 4. Check logs for requests tail /var/log/apache2/mydomain-access.log // Shows request entries

# 5. Verify DocumentRoot ls /var/www/mydomain/index.html // File exists

# 6. Test from browser # Visit http://mydomain.local // Site loads correctly ```

  • [Fix Apache 403 Forbidden Error](/articles/fix-apache-403-forbidden-error)
  • [Fix Apache SSL Certificate Error](/articles/fix-apache-ssl-certificate-error)
  • [Fix Apache Configuration Syntax Error](/articles/fix-apache-configuration-syntax-error)