When managing multiple virtual hosts in Apache that share similar configurations, particularly when they use the same DocumentRoot and directory settings, repetitive configuration becomes inevitable. Here's a common scenario many developers face:
<VirtualHost *:80>
ServerName domain1.com
DocumentRoot "/var/www/shared/web"
<Directory "/var/www/shared/web">
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
<VirtualHost *:80>
ServerName domain2.com
DocumentRoot "/var/www/shared/web"
<Directory "/var/www/shared/web">
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
Just like in programming, we should apply the DRY (Don't Repeat Yourself) principle to Apache configurations. There are several ways to achieve this:
1. Using Include Directive
Create a separate file (e.g., shared_directories.conf) containing common Directory directives:
# shared_directories.conf
<Directory "/var/www/shared/web">
AllowOverride All
Require all granted
</Directory>
<Directory "/usr/share/pear/data/symfony/web/sf">
AllowOverride All
Require all granted
</Directory>
Then include it in each VirtualHost:
<VirtualHost *:80>
ServerName domain1.com
DocumentRoot "/var/www/shared/web"
Include /path/to/shared_directories.conf
</VirtualHost>
2. Using Macros (mod_macro)
For more advanced scenarios, you can use mod_macro to create configuration templates:
<Macro SharedHost $name>
<VirtualHost *:80>
ServerName $name
DocumentRoot "/var/www/shared/web"
<Directory "/var/www/shared/web">
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
</Macro>
Use SharedHost domain1.com
Use SharedHost domain2.com
While these approaches reduce configuration duplication, keep in mind:
- Apache still processes each Directory directive separately for each VirtualHost
- Include files are read at server startup/reload
- Too many includes might make debugging more difficult
Here's how I typically structure this for a multi-domain Symfony project:
# apache2/sites-available/shared_dirs.conf
<Directory "/var/www/symfony_project/web">
Options FollowSymLinks
AllowOverride None
Require all granted
FallbackResource /index.php
</Directory>
<Directory "/var/www/symfony_project/web/bundles">
AllowOverride All
Require all granted
</Directory>
# apache2/sites-available/domain1.conf
<VirtualHost *:80>
ServerName domain1.com
Include /etc/apache2/sites-available/shared_dirs.conf
DocumentRoot "/var/www/symfony_project/web"
ErrorLog ${APACHE_LOG_DIR}/domain1_error.log
CustomLog ${APACHE_LOG_DIR}/domain1_access.log combined
</VirtualHost>
When managing multiple domains with identical directory configurations in Apache, we often face redundant
<VirtualHost *:80>
ServerName domain1.com
DocumentRoot "/var/www/srs/web"
<Directory "/var/www/srs/web">
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
<VirtualHost *:80>
ServerName domain2.com
DocumentRoot "/var/www/srs/web"
<Directory "/var/www/srs/web">
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
Instead of repeating identical configurations, we can move the shared directives to the main server context (httpd.conf or apache2.conf):
# In main Apache configuration
<Directory "/var/www/srs/web">
AllowOverride All
Require all granted
</Directory>
# Individual VirtualHosts become cleaner
<VirtualHost *:80>
ServerName domain1.com
DocumentRoot "/var/www/srs/web"
</VirtualHost>
<VirtualHost *:80>
ServerName domain2.com
DocumentRoot "/var/www/srs/web"
</VirtualHost>
For more complex scenarios, consider using Include directives to manage shared configurations:
# Create shared.conf
<Directory "/var/www/srs/web">
Options FollowSymLinks
AllowOverride All
Require all granted
</Directory>
# In VirtualHost definitions
<VirtualHost *:80>
ServerName domain1.com
DocumentRoot "/var/www/srs/web"
Include /path/to/shared.conf
</VirtualHost>
- Directory directives in VirtualHost blocks override main configuration
- Order of evaluation matters: main config → VirtualHost → .htaccess
- Always test configuration with
apachectl configtest
- For security, restrict Directory directives to necessary paths only
Here's how we handle shared assets in a Symfony project:
# Shared configuration
<Directory "/usr/share/pear/data/symfony/web/sf">
AllowOverride None
Require all granted
</Directory>
<VirtualHost *:80>
ServerName api.example.com
DocumentRoot "/var/www/srs/web"
Alias /sf /usr/share/pear/data/symfony/web/sf
</VirtualHost>
<VirtualHost *:80>
ServerName admin.example.com
DocumentRoot "/var/www/srs/web"
Alias /sf /usr/share/pear/data/symfony/web/sf
</VirtualHost>