| |

LFCE 52 ๐Ÿง Apache โ€” Virtual Hosts

โฑ๏ธ Estimated read: 14 min | |

Apache virtual hosts are the mechanism that allows a single server to serve multiple domains. The previous chapter covered the basic configuration: the ServerName, the DocumentRoot, and the <Directory> block that grants access to the filesystem. A virtual host is a <VirtualHost> container that groups those directives and associates them with a specific address and port. When a request arrives, Apache reads the Host header and selects the virtual host whose ServerName or ServerAlias matches. If no host matches, the first virtual host for that address and port handles the request.

The configuration syntax differs slightly between Debian and RHEL in the file layout and the enabling mechanism, but the <VirtualHost> container is the same on both. The previous chapter covered the Nginx equivalent; this chapter covers the Apache implementation, including the name-based virtual host, the ServerAlias directive, the default host selection, and the validation commands that confirm the configuration is correct before the reload.

Key point: A name-based virtual host is selected by matching the request’s Host header against the ServerName and ServerAlias directives. The ServerName is the primary hostname, and the ServerAlias lists additional hostnames that the same virtual host should handle. If no virtual host matches, Apache uses the first virtual host defined for the address and port, which is why the order of the <VirtualHost> blocks matters. Always run apache2ctl configtest (Debian) or httpd -t (RHEL) before reloading.


Why virtual hosts require understanding name-based selection

The name-based selection problem.

A single IP address can host many domains. Apache distinguishes them by the Host header that the client sends with the request. The <VirtualHost> block with a matching ServerName or ServerAlias handles the request. If no block matches, Apache falls back to the first block for that address and port. The fallback is not an error; it is the default behavior, and it is why the order of the virtual host definitions matters. The first block is the default for its address and port, regardless of its content .

The ServerAlias problem.

The ServerName is the primary hostname, but users often reach a site through additional hostnames, such as www.example.com in addition to example.com, or a legacy domain that redirects to the new one. The ServerAlias directive lists those additional hostnames. Without it, a request for www.example.com does not match a virtual host whose ServerName is example.com, and it falls through to the default host, which may serve the wrong site .

The port-binding problem.

A <VirtualHost> block is bound to an address and port: <VirtualHost *:80> listens on all addresses on port 80, and <VirtualHost 192.168.1.10:443> listens on a specific address on port 443. The Listen directive in the main configuration determines which ports Apache accepts connections on. A virtual host for a port that is not in the Listen list is never selected . On Debian, the ports.conf file contains the Listen directives, and the virtual host files are separate. On RHEL, the Listen directive is in httpd.conf, and the virtual host files are in conf.d/.


a. The name-based virtual host

The name-based virtual host is the most common form. The <VirtualHost> block contains the ServerName, the ServerAlias, the DocumentRoot, and a <Directory> block for the document root.

# /etc/apache2/sites-available/example.com.conf (Debian)
# /etc/httpd/conf.d/example.com.conf (RHEL)
<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com

    DocumentRoot /var/www/example.com

    <Directory /var/www/example.com>
        Options -Indexes +FollowSymLinks
        AllowOverride None
        Require all granted
    </Directory>

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

The ServerName is the primary hostname. The ServerAlias lists the additional hostnames that should be handled by this virtual host. The DocumentRoot sets the filesystem path, and the <Directory> block grants access to that path. The ErrorLog and CustomLog directives set per-site log files, which make it easier to diagnose issues with a specific site .

The ${APACHE_LOG_DIR} variable is defined in the Debian configuration and expands to /var/log/apache2. On RHEL, the equivalent path is /var/log/httpd, and the variable is not defined, so the path must be written explicitly.

# RHEL version with explicit paths
<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com

    DocumentRoot /var/www/example.com

    <Directory /var/www/example.com>
        Options -Indexes +FollowSymLinks
        AllowOverride None
        Require all granted
    </Directory>

    ErrorLog /var/log/httpd/example.com-error.log
    CustomLog /var/log/httpd/example.com-access.log combined
</VirtualHost>

The content of the block is the same; only the log paths differ. The combined format is the standard log format that includes the client IP, the request, the status code, and the user agent.


b. Enabling virtual hosts on Debian and RHEL

The mechanism for enabling a virtual host differs between the two families. Debian uses the a2ensite and a2dissite helper scripts to manage symlinks between sites-available and sites-enabled. RHEL places the configuration file in conf.d/, and it is included automatically by the main configuration.

# Debian: create the file in sites-available
sudo tee /etc/apache2/sites-available/example.com.conf > /dev/null <<'EOF'
<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/example.com
    <Directory /var/www/example.com>
        Options -Indexes +FollowSymLinks
        AllowOverride None
        Require all granted
    </Directory>
    ErrorLog ${APACHE_LOG_DIR}/example.com-error.log
    CustomLog ${APACHE_LOG_DIR}/example.com-access.log combined
</VirtualHost>
EOF

# Enable the site
sudo a2ensite example.com.conf

# Disable the default site if it conflicts
sudo a2dissite 000-default.conf

# RHEL: create the file in conf.d
sudo tee /etc/httpd/conf.d/example.com.conf > /dev/null <<'EOF'
<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/example.com
    <Directory /var/www/example.com>
        Options -Indexes +FollowSymLinks
        AllowOverride None
        Require all granted
    </Directory>
    ErrorLog /var/log/httpd/example.com-error.log
    CustomLog /var/log/httpd/example.com-access.log combined
</VirtualHost>
EOF

The a2ensite command creates a symlink in sites-enabled that points to the file in sites-available. The a2dissite command removes the symlink. The a2ensite and a2dissite helpers are part of the apache2 package on Debian and are not available on RHEL . On RHEL, the file in conf.d/ is included automatically by the IncludeOptional conf.d/*.conf directive in httpd.conf.

The default site on Debian is 000-default.conf, which listens on port 80 and serves /var/www/html. It should be disabled or modified when a new virtual host is added, because it is the first virtual host for port 80 and therefore the default host. If it is not disabled, requests that do not match any other virtual host are handled by the default site rather than the new site .


c. The default host and testing

The first <VirtualHost> block for a given address and port is the default host. If no other block matches the request’s Host header, the default host handles the request. The order of the blocks in the configuration files determines which one is first, and the a2ensite command creates symlinks that are included in alphabetical order.

# List the enabled sites in order
ls -l /etc/apache2/sites-enabled/
# Output: 000-default.conf -> ../sites-available/000-default.conf
#         example.com.conf -> ../sites-available/example.com.conf
# The 000-default.conf is included first, so it is the default host

To make the new site the default, either disable the default site or name the new site’s symlink so that it sorts first. A common convention is to prefix the site name with a number, such as 001-example.com.conf, to control the order.

Testing uses curl with the Host header to simulate a request for a specific virtual host. The -H flag sets the header, and the URL can be http://localhost because the Host header overrides the default .

# Test the example.com virtual host
curl -H "Host: example.com" http://localhost
# Output: the content from /var/www/example.com/index.html

# Test the www alias
curl -H "Host: www.example.com" http://localhost

# Test an unknown hostname; it goes to the default host
curl -I -H "Host: unknown.com" http://localhost

The apache2ctl -S command (or httpd -S on RHEL) shows the virtual host configuration that Apache has parsed, including the default host and the ServerName and ServerAlias for each block. It is the definitive verification that the virtual hosts are recognized .

# Show the virtual host configuration
sudo apache2ctl -S    # Debian
sudo httpd -S         # RHEL
# Output lists each virtual host, its port, its name, and its aliases

Complete Example Session

# ============================================
# PART 1: CREATE THE SITE DIRECTORY
# ============================================
sudo mkdir -p /var/www/example.com
echo "<h1>Example Site</h1>" | sudo tee /var/www/example.com/index.html
sudo chown -R www-data:www-data /var/www/example.com    # Debian
# sudo chown -R apache:apache /var/www/example.com      # RHEL

# ============================================
# PART 2: CREATE THE VIRTUAL HOST FILE
# ============================================
sudo tee /etc/apache2/sites-available/example.com.conf > /dev/null <<'EOF'
<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/example.com
    <Directory /var/www/example.com>
        Options -Indexes +FollowSymLinks
        AllowOverride None
        Require all granted
    </Directory>
    ErrorLog ${APACHE_LOG_DIR}/example.com-error.log
    CustomLog ${APACHE_LOG_DIR}/example.com-access.log combined
</VirtualHost>
EOF

# ============================================
# PART 3: ENABLE THE SITE
# ============================================
sudo a2ensite example.com.conf

# ============================================
# PART 4: DISABLE THE DEFAULT SITE
# ============================================
sudo a2dissite 000-default.conf

# ============================================
# PART 5: VALIDATE THE CONFIGURATION
# ============================================
sudo apache2ctl configtest
# Output: Syntax OK

# ============================================
# PART 6: RELOAD APACHE
# ============================================
sudo systemctl reload apache2

# ============================================
# PART 7: TEST THE MAIN HOST
# ============================================
curl -H "Host: example.com" http://localhost
# Output: <h1>Example Site</h1>

# ============================================
# PART 8: TEST THE ALIAS
# ============================================
curl -H "Host: www.example.com" http://localhost
# Output: <h1>Example Site</h1>

# ============================================
# PART 9: TEST AN UNKNOWN HOST
# ============================================
curl -I -H "Host: unknown.com" http://localhost
# Output: the default host handles the request

# ============================================
# PART 10: VERIFY THE VIRTUAL HOST CONFIGURATION
# ============================================
sudo apache2ctl -S
# Output lists example.com on port 80 with the www alias

The ten parts demonstrate the complete virtual host workflow: content creation, configuration, enablement, disabling the default site, validation, reload, testing the main host, testing the alias, testing an unknown host, and verifying the parsed configuration. The critical verification is Part 10: apache2ctl -S shows exactly which virtual hosts Apache has recognized and which one is the default.


Quick Reference

Virtual Host Directives

DirectivePurposeExample
<VirtualHost>Container for a virtual host<VirtualHost *:80>
ServerNamePrimary hostnameServerName example.com
ServerAliasAdditional hostnamesServerAlias www.example.com
DocumentRootFilesystem pathDocumentRoot /var/www/example.com
<Directory>Access control<Directory /var/www/example.com>
ErrorLogPer-site error logErrorLog .../error.log
CustomLogPer-site access logCustomLog .../access.log combined

Enablement Commands

DistributionEnableDisableFile Location
Debian / Ubuntua2ensite <name>a2dissite <name>/etc/apache2/sites-available/
RHEL / RockyAutomaticMove file/etc/httpd/conf.d/

Validation and Verification

CommandDistributionPurpose
apache2ctl configtestDebianValidate syntax
httpd -tRHELValidate syntax
apache2ctl -SDebianShow virtual host config
httpd -SRHELShow virtual host config
curl -H "Host: ..."BothTest a specific virtual host

Best Practices

โœ… Do This:

# Use ServerAlias for the www subdomain
ServerName example.com
ServerAlias www.example.com                                   # โœ…

# Give each virtual host its own log files
ErrorLog ${APACHE_LOG_DIR}/example.com-error.log              # โœ…

# Disable the default site when adding a new one
a2dissite 000-default.conf                                    # โœ…

# Validate before reloading
apache2ctl configtest                                         # โœ…

# Verify with apache2ctl -S
apache2ctl -S                                                 # โœ…

# Test with the Host header
curl -H "Host: example.com" http://localhost                  # โœ…

โŒ Don’t Do This:

# Omit ServerAlias for the www subdomain
ServerName example.com    # www.example.com falls to default  # โŒ

# Leave the default site enabled
# It becomes the default host and handles unmatched requests  # โŒ

# Omit the <Directory> block
DocumentRoot /var/www/example.com    # 403 Forbidden          # โŒ

# Use a wildcard <VirtualHost *:80> without ServerName
# Every request matches the first block                       # โŒ

# Reload without validation
systemctl reload apache2    # Syntax error prevents reload    # โŒ

Common Pitfalls

PitfallWhy It HappensFix
Wrong site servedDefault host handles the requestDisable the default site; check order
www subdomain failsServerAlias not setAdd ServerAlias www.example.com
403 Forbidden on the new site<Directory> block missing or permissions wrongAdd the block; chown to the web user
Virtual host not recognizedFile not enabled or not in conf.da2ensite on Debian; move file on RHEL
Configuration errorMissing directive or typoapache2ctl configtest reports the line
Logs mixed between sitesShared ErrorLog and CustomLogSet per-site log files

Real-World Examples

1. Name-based virtual host

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/example.com
</VirtualHost>

2. DocumentRoot with access control

<Directory /var/www/example.com>
    Options -Indexes +FollowSymLinks
    Require all granted
</Directory>

3. Per-site logs

ErrorLog ${APACHE_LOG_DIR}/example.com-error.log
CustomLog ${APACHE_LOG_DIR}/example.com-access.log combined

4. Enable the site on Debian

a2ensite example.com.conf

5. Disable the default site

a2dissite 000-default.conf

6. RHEL file placement

cp example.com.conf /etc/httpd/conf.d/

7. Validate configuration

apache2ctl configtest    # Debian
httpd -t                 # RHEL

8. Show virtual host config

apache2ctl -S    # Debian
httpd -S         # RHEL

9. Test the main host

curl -H "Host: example.com" http://localhost

10. Test the alias

curl -H "Host: www.example.com" http://localhost

Visual

Virtual Host Selection

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  APACHE SELECTS THE VIRTUAL HOST BY Host HEADER              โ”‚
โ”‚                                                              โ”‚
โ”‚  Request: GET / HTTP/1.1                                     โ”‚
โ”‚  Host: example.com                                           โ”‚
โ”‚       โ”‚                                                      โ”‚
โ”‚       โ–ผ                                                      โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚ <VirtualHost *:80>                                     โ”‚  โ”‚
โ”‚  โ”‚   ServerName example.com      โ† MATCH                  โ”‚  โ”‚
โ”‚  โ”‚   ServerAlias www.example.com                          โ”‚  โ”‚
โ”‚  โ”‚ </VirtualHost>                                         โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                                              โ”‚
โ”‚  Request: GET / HTTP/1.1                                     โ”‚
โ”‚  Host: unknown.com                                           โ”‚
โ”‚       โ”‚                                                      โ”‚
โ”‚       โ–ผ                                                      โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚ No ServerName or ServerAlias match                     โ”‚  โ”‚
โ”‚  โ”‚ โ†’ First <VirtualHost> for the address and port         โ”‚  โ”‚
โ”‚  โ”‚ โ†’ The default host                                     โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Debian vs RHEL File Layout

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  DEBIAN vs RHEL                                              โ”‚
โ”‚                                                              โ”‚
โ”‚  Debian / Ubuntu:                                            โ”‚
โ”‚  /etc/apache2/                                               โ”‚
โ”‚  โ”œโ”€โ”€ sites-available/     โ† All site configs                 โ”‚
โ”‚  โ”‚   โ”œโ”€โ”€ 000-default.conf                                    โ”‚
โ”‚  โ”‚   โ””โ”€โ”€ example.com.conf                                    โ”‚
โ”‚  โ””โ”€โ”€ sites-enabled/       โ† Symlinks to active sites         โ”‚
โ”‚      โ”œโ”€โ”€ 000-default.conf โ†’ ../sites-available/...           โ”‚
โ”‚      โ””โ”€โ”€ example.com.conf โ†’ ../sites-available/...           โ”‚
โ”‚                                                              โ”‚
โ”‚  a2ensite creates the symlink. a2dissite removes it.         โ”‚
โ”‚                                                              โ”‚
โ”‚  RHEL / Rocky:                                               โ”‚
โ”‚  /etc/httpd/                                                 โ”‚
โ”‚  โ””โ”€โ”€ conf.d/              โ† All .conf files auto-included    โ”‚
โ”‚      โ”œโ”€โ”€ example.com.conf                                    โ”‚
โ”‚      โ””โ”€โ”€ other.com.conf                                      โ”‚
โ”‚                                                              โ”‚
โ”‚  Files are enabled by their presence in conf.d.              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Default Host Selection

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  THE FIRST VIRTUAL HOST IS THE DEFAULT                       โ”‚
โ”‚                                                              โ”‚
โ”‚  sites-enabled/ (in alphabetical order):                     โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚ 000-default.conf    โ† first โ†’ DEFAULT HOST             โ”‚  โ”‚
โ”‚  โ”‚ example.com.conf    โ† second                           โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                                              โ”‚
โ”‚  If 000-default.conf is enabled:                             โ”‚
โ”‚  โ†’ It handles requests that match no other host             โ”‚
โ”‚  โ†’ The new site is only served for its own hostnames        โ”‚
โ”‚                                                              โ”‚
โ”‚  If 000-default.conf is disabled:                            โ”‚
โ”‚  โ†’ example.com.conf becomes the default host                โ”‚
โ”‚  โ†’ It handles unmatched requests as well                    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Summary

ItemValue
Virtual host container<VirtualHost *:80>
Primary hostnameServerName
Additional hostnamesServerAlias
Filesystem pathDocumentRoot
Access control<Directory> + Require
Per-site logsErrorLog, CustomLog
Debian enablementa2ensite <name>
Debian disablementa2dissite <name>
RHEL enablementFile in conf.d/
Validation (Debian)apache2ctl configtest
Validation (RHEL)httpd -t
Config verificationapache2ctl -S / httpd -S
Default hostFirst virtual host for the address and port

Key takeaways:

  • Apache selects the virtual host by the Host header. The ServerName and ServerAlias directives define the hostnames that the block responds to. A request whose hostname matches neither falls to the default host .
  • ServerAlias is required for additional hostnames. The ServerName is the primary hostname, and the ServerAlias lists the alternatives. Without it, www.example.com does not match a virtual host whose ServerName is example.com .
  • The first virtual host is the default. If no block matches, Apache uses the first block for the address and port. The order is determined by the alphabetical order of the files in sites-enabled on Debian, and by the order of the blocks on RHEL.
  • Debian and RHEL use different enablement mechanisms. Debian uses a2ensite and a2dissite to manage symlinks. RHEL places the file in conf.d/, where it is included automatically .
  • Each site should have its own logs. The ErrorLog and CustomLog directives inside the <VirtualHost> block write to per-site files, which makes it possible to diagnose issues with a specific site without scanning a combined log.
  • apache2ctl -S shows the parsed configuration. It lists every virtual host, its port, its name, and its aliases, and it identifies the default host. It is the definitive verification that the virtual hosts are recognized .

Remember: A virtual host is a <VirtualHost> container with a ServerName that distinguishes it from the others. The Host header selects the block, and the first block is the default when no name matches. The ServerAlias covers the additional hostnames, and the <Directory> block grants access to the document root. Debian enables sites with a2ensite; RHEL enables them by placing the file in conf.d/. Validate with configtest or -t, verify with -S, and test with curl and the correct Host header. A configuration that parses is not necessarily a configuration that serves the right site; the verification confirms both.


Was this helpful?


Stop using slow, ad-bloated tool sites! ๐Ÿคฎ

๐Ÿ”Ž Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
โœ… Finance (Mortgage, Interest, Inflation)
โœ… Tech (Base64, JSON, Dev Suite, IP)
โœ… Health (BMI, BMR, TDEE)
โœ… Productivity (Timer, Workspace, QR)

โšก๏ธ Fast & Private
๐Ÿ”’ No data leaves your device
๐Ÿ’Ž 100% Free

๐Ÿ”— Use it now: https://tools.kandz.me
๐Ÿ”– Bookmark itโ€”youโ€™ll need it later!