Apache#

Integration Details

Ingester

File Follower

Apache Configuration#

Apache defines its log locations via the ErrorLog and CustomLog directives, which can be configured globally (typically /etc/apache2/apache2.conf) or per virtual host (typically /etc/apache2/sites-available/{VHOST_NAME}.conf). By default, these write to error.log and access.log in /var/log/apache2/. Follow the steps below to configure Apache to output clean data for Gravwell ingestion, then install File Follower on your Apache host by following the instructions in File Follower. Then add the configuration from the File Follower section below.

Define LogFormat#

Apache uses the Common Log Format by default, so we will define a custom structure called: json_combined. This will write the logs cleanly as JSON before ingestion into Gravwell.

You can define this globally in /etc/apache2/apache2.conf or inside a specific Virtual Host in /etc/apache2/sites-available/{VHOST_NAME}.conf.

LogFormat \
  "{\"time\":\"%{%Y-%m-%dT%H:%M:%S}t\",\
  \"remote_addr\":\"%a\",\
  \"method\":\"%m\",\
  \"uri\":\"%U\",\
  \"query\":\"%q\",\
  \"status\":%>s,\
  \"bytes\":%B,\
  \"duration\":%D,\
  \"user_agent\":\"%{User-Agent}i\",\
  \"referer\":\"%{Referer}i\"}" json_combined

Key Field Mechanics:#

  • %a uses the client IP address ( or the proxy-decode address if mod_remoteip is enabled).

  • %D reports the request duration in microseconds.

  • %q includes the query string, complete with leading ?. If no query string exists, outputs an empty string.

Note

If you’re using this in a template or config management tool, the %{%Y-%m-%dT%H:%M:%S}t strftime pattern contains {% which many templating engines will try to interpret — escape it appropriately for your tooling.

Apply custom logging#

Once the format is defined, update the configuration file to apply it:

CustomLog /var/log/apache2/access.log json_combined
ErrorLog  /var/log/apache2/error.log

Common Gotchas & Advanced Tweaks#

RewriteRule placement (Extensionless URLS)#

If you’re using mod_rewrite to handle extensionless URLs (e.g. routing /status to /status.php), your rules must must be placed inside a <Directory> block rather than directly at the global VirtualHost level.

At the global VirtualHost level, %{REQUEST_FILENAME} treats the target as a plain URI string instead of a filesystem path. This causes -f (file) and -d (directory) checks to always evaluate false:

<Directory /var/www/html>
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.+)$ $1.php [L]
</Directory>

Proxy Configuration#

If Apache sits behind a proxy, the standard remote host field will log the proxy’s internal IP address instead of the real clients. We can fix this using mod_remoteip.

  1. Enable the required modules: Run the following commands to enable both the proxy headers and rewrite engines:

a2enmod remoteip
a2enmod rewrite   # if you need extensionless URL rewrites
  1. Configure mod_remoteip: Create a dedicated configuration file at /etc/apache2/conf-available/remoteip.conf:

RemoteIPHeader X-Real-IP
RemoteIPTrustedProxy 172.18.100.60   # nginx's IP
  1. Activate the Configuration

a2enconf remoteip
systemctl restart apache2

Gravwell Configuration#

Gravwell Storage Well Configuration#

Setup the well configuration in your Gravwell indexers.

Sample well config:
Create or edit: /opt/gravwell/etc/gravwell.conf.d/apache-well.conf

[Storage-Well "apache"]
    Location=/opt/gravwell/storage/apache
    Tags=apache*

Gravwell Ingester Configuration: File Follower#

Sample Apache config:
Create or edit: /opt/gravwell/etc/file_follow.conf.d/apache.conf

[Follower "apache-access"]
    Base-Directory = /var/log/apache2
    File-Filter    = access.log
    Tag-Name       = apache

[Follower "apache-error"]
    Base-Directory = /var/log/apache2
    File-Filter    = error.log
    Tag-Name       = apache-err

Note

Remember to restart the service to apply the new config: sudo systemctl restart gravwell_file_follow.service