When managing multiple virtual hosts in Apache, maintaining both individual logs and a centralized access log often becomes necessary for security auditing and traffic analysis. The default configuration shown creates this exact scenario:
ErrorLog /var/log/httpd-error.log
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
CustomLog /var/log/httpd-access.log combined
NameVirtualHost *:80
<VirtualHost *:80>
ServerName myhost.com
ErrorLog /var/www/myhost.com/log/error.log
CustomLog /var/www/myhost.com/log/access.log combined
</VirtualHost>
The solution lies in Apache's environment variables and conditional logging. Here's how to implement a global catch-all:
# In main server configuration (not inside VirtualHost)
LogFormat "%v %h %l %u %t \"%r\" %>s %b" global_combined
CustomLog /var/log/httpd-access-global.log global_combined env=!skip_global_log
# In each VirtualHost (optional)
SetEnvIf Request_URI "^/health-check$" skip_global_log
For comprehensive logging while maintaining per-VHost logs:
# Define multiple log formats
LogFormat "%h %l %u %t \"%r\" %>s %b" basic
LogFormat "%v %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
# Global log captures all requests
CustomLog /var/log/httpd-global.log basic
# VirtualHost-specific logging
<VirtualHost *:80>
ServerName site.example.com
CustomLog /var/log/site.example.com-access.log vhost_combined
</VirtualHost>
For error logs, Apache provides a different approach:
# Main server config
ErrorLog "|/usr/bin/tee -a /var/log/httpd-error-global.log"
# VirtualHost config
ErrorLog "|/usr/bin/tee -a /var/log/httpd-error-global.log | /usr/bin/logger -t httpd/vhost1"
When implementing dual logging:
- Use asynchronous logging with piped loggers for high-traffic sites
- Consider log rotation for the global log file
- Monitor disk I/O when logging to the same physical disk
Example rotation config for logrotate:
/var/log/httpd-global.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
sharedscripts
postrotate
/usr/sbin/apachectl graceful 2>/dev/null || true
endscript
}
When managing multiple Apache Virtual Hosts, maintaining separate log files for each host can make it challenging to monitor overall server activity. The current configuration shows some requests falling through to the main error log (/var/log/httpd-error.log
) while the main access log remains empty.
Apache's logging directives follow an inheritance pattern. Virtual Host configurations that don't specify their own ErrorLog
or CustomLog
will inherit these settings from the main server configuration. However, when Virtual Hosts define their own logs, they override the main configuration completely.
# Main server configuration (acts as fallback)
ErrorLog /var/log/httpd-error.log
CustomLog /var/log/httpd-access.log combined
# Virtual Host configuration (overrides main config)
<VirtualHost *:80>
ServerName example.com
ErrorLog /path/to/vhost-error.log # Overrides main ErrorLog
CustomLog /path/to/vhost-access.log combined # Overrides main CustomLog
</VirtualHost>
To maintain both per-VirtualHost logs and a centralized log, we can use multiple CustomLog
directives:
<VirtualHost *:80>
ServerName example.com
ErrorLog /path/to/vhost-error.log
CustomLog /path/to/vhost-access.log combined
CustomLog "|/usr/sbin/rotatelogs /var/log/all-access.log.%Y%m%d 86400" combined
</VirtualHost>
For servers with many Virtual Hosts, editing each one would be tedious. Instead, we can use Apache's LogFormat
and environment variables:
# In main server configuration
LogFormat "%v %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
CustomLog "|/usr/sbin/rotatelogs /var/log/all-access.log.%Y%m%d 86400" vhost_combined env=!nolog
# In each VirtualHost
SetEnvIf Request_URI "^/healthcheck$" nolog
For more sophisticated logging, we can use piped logs with custom scripts:
CustomLog "|/usr/local/bin/log-processor.pl" combined
# Sample log-processor.pl
#!/usr/bin/perl
while (<STDIN>) {
open(MAIN, ">>/var/log/all-access.log");
print MAIN $_;
close(MAIN);
open(VHOST, ">>/var/log/$ENV{SERVER_NAME}-access.log");
print VHOST $_;
close(VHOST);
}
When implementing centralized logging, consider:
- Use asynchronous logging when possible (piped logs)
- Rotate logs regularly to prevent disk space issues
- Consider using syslog for centralized logging across multiple servers
- For high-traffic servers, evaluate the impact of additional logging