Apache logging to central syslog server

Apache logging to central syslog server

Apache web server traditionally writes to local log files in /var/log/httpd.

At work we have been looking into PCI compliance, and it requires that log files are stored centrally so that if a server gets compromised and the local log files are modified, there is still an authoritative copy on the central log server.

Syslog is the standard Linux and UNIX way for transmitting log entries to a central server.

Problem is Apache only supports logging to syslog for it's error log, and not it's access log.

Thankfully the problem is relatively easy to fix with a short Perl script.

Apache Log Config

I am doing this on a RedHat server, so the config file locations will be specific to that.

Create a new file called /etc/httpd/conf.d/syslog.conf:

LogLevel warn
LogFormat "%v %V %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" vcombined
CustomLog "|/usr/bin/httpd_syslog" vcombined
ErrorLog syslog:local2

Next create a Perl script /usr/bin/httpd_syslog to accept piped logs from Apache and send them to the local syslog service:

#!/usr/bin/perl
use strict;
use Sys::Syslog qw( :DEFAULT setlogsock );
setlogsock('unix');
openlog('httpd', 'cons,pid','local1');

#Read from STDIN and log to syslog
while (my $log = <STDIN>) {
        syslog('notice', $log);
}
closelog();

You can now reload Apache and both error logs and access logs should start flowing into /var/log/messages.

Syslog Config

Next up, we need to split out the error logs and access logs into their own files again, rather than have them appearing in the main /var/log/messages file.

To do this we need to modify /etc/syslog.conf:

Comment out the line:

*.info;mail.none;authpriv.none;cron.none  -/var/log/messages

And replace it with:

*.info;mail.none;authpriv.none;cron.none;local1.none;local2.none  -/var/log/messages
local1.*  -/var/log/httpd_access_log
local2.*  -/var/log/httpd_error_log

This tells the local syslog service not to log entries from local1 and local2 facilities (which we are using for Apache) into /var/log/messages, and instead log them into separate log files.

Central Syslog Server

To instruct the local syslog server to send all entries to a central server, add the following line to /etc/syslog.conf:

*.* @IP_ADDRESS_OF_LOG_SERVER

Now restart syslog:

service syslog restart

Log Rotation

Finally, ensure that the new log files get rotated when other syslog files are rotated by modifying /etc/logrotate.d/syslog, modify the top line so it looks like this:

/var/log/messages /var/log/secure /var/log/maillog
/var/log/spooler /var/log/boot.log /var/log/cron
/var/log/httpd_access_log /var/log/httpd_error_log {