Apache virtual hosts are the mechanism by which a single Apache HTTP Server instance serves multiple websites, distinguishing between them using the ServerName directive and the incoming Host HTTP header. Name-based virtual hosting (the most common type) allows hundreds of domains to share a single IP address, with Apache routing each request to the correct document root and configuration based on the domain name. On RHEL 9, virtual host files live in /etc/httpd/conf.d/ as individual .conf files. This guide covers creating HTTP and HTTPS virtual hosts, configuring .htaccess overrides, setting up redirects, implementing custom logging, and testing the configuration with apachectl configtest.
Prerequisites
- Apache installed and running on RHEL 9 (see: How to Install Apache HTTP Server on RHEL 9)
- Domain names pointing to your server’s IP (or entries in
/etc/hostsfor testing)
Step 1 — Create Document Roots
mkdir -p /var/www/site1.com/html
mkdir -p /var/www/site2.com/html
chown -R apache:apache /var/www/site1.com /var/www/site2.com
chmod -R 755 /var/www/site1.com /var/www/site2.com
echo 'site1.com — Apache on RHEL 9
' > /var/www/site1.com/html/index.html
echo 'site2.com — Apache on RHEL 9
' > /var/www/site2.com/html/index.html
# Set SELinux file context
semanage fcontext -a -t httpd_sys_content_t '/var/www/site1.com(/.*)?'
semanage fcontext -a -t httpd_sys_content_t '/var/www/site2.com(/.*)?'
restorecon -Rv /var/www/site1.com /var/www/site2.com
Step 2 — Create an HTTP Virtual Host
vi /etc/httpd/conf.d/site1.com.conf
ServerName site1.com
ServerAlias www.site1.com
DocumentRoot /var/www/site1.com/html
ServerAdmin [email protected]
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
CustomLog /var/log/httpd/site1.com.access_log combined
ErrorLog /var/log/httpd/site1.com.error_log
Step 3 — Create an HTTPS Virtual Host with HTTP Redirect
vi /etc/httpd/conf.d/site2.com.conf
# Redirect HTTP to HTTPS
ServerName site2.com
ServerAlias www.site2.com
Redirect permanent / https://site2.com/
# HTTPS virtual host
ServerName site2.com
ServerAlias www.site2.com
DocumentRoot /var/www/site2.com/html
ServerAdmin [email protected]
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/site2.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/site2.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/site2.com/chain.pem
# Modern TLS only
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLHonorCipherOrder off
SSLSessionTickets off
# Security headers
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Frame-Options DENY
Header always set X-Content-Type-Options nosniff
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
CustomLog /var/log/httpd/site2.com.ssl.access_log combined
ErrorLog /var/log/httpd/site2.com.ssl.error_log
Step 4 — Redirect www to non-www
# Add a separate block at the top of the conf file
ServerName www.site1.com
Redirect permanent / http://site1.com/
Step 5 — Use .htaccess for Per-Directory Rules
When AllowOverride All is set in the <Directory> block, Apache reads .htaccess files in each directory. This enables WordPress, Laravel, and other frameworks to manage their own URL rewriting:
# Example .htaccess for a PHP framework with clean URLs
cat > /var/www/site1.com/html/.htaccess << 'EOF'
Options -MultiViews
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]
EOF
Step 6 — Custom Error Pages
# Inside a VirtualHost block
ErrorDocument 404 /404.html
ErrorDocument 500 /500.html
# Create the error pages
echo '404 — Page not found
' > /var/www/site1.com/html/404.html
Step 7 — Test and Reload
# Always test before reloading
apachectl configtest
# Graceful reload (existing connections finish first)
systemctl reload httpd
# Test that virtual hosts respond correctly
curl -H "Host: site1.com" http://localhost
curl -H "Host: site2.com" http://localhost
Step 8 — List Active Virtual Hosts
# Show all parsed virtual hosts
apachectl -S
# List virtual host conf files
ls -la /etc/httpd/conf.d/
Troubleshooting
- 403 Forbidden — check SELinux (
ls -lZ /var/www/site1.com/html/), directory permissions, and thatRequire all grantedis set in the<Directory>block. - Wrong site served — Apache serves the first matching VirtualHost by default. Ensure each
ServerNameis unique. Useapachectl -Sto debug routing. - .htaccess not working — check that
AllowOverride Allis set andmod_rewriteis loaded:httpd -M | grep rewrite.
Conclusion
Apache virtual hosts on RHEL 9 give you granular per-site control over document roots, SSL, rewrites, logging, and access control. Drop-in .conf files in /etc/httpd/conf.d/ keep each site’s configuration isolated, and apachectl -S gives an instant overview of all active virtual hosts and how requests will be routed.
Next steps: How to Secure Apache with Let’s Encrypt on RHEL 9, How to Configure Apache mod_proxy as a Reverse Proxy on RHEL 9, and How to Set Up ModSecurity WAF with Apache on RHEL 9.