# ModSecurity audit log empty when CRS rules are included inside a VirtualHost (Rocky 9.8, works on Rocky 8)

**URL:** <https://forums.rockylinux.org/t/modsecurity-audit-log-empty-when-crs-rules-are-included-inside-a-virtualhost-rocky-9-8-works-on-rocky-8/20845>\
**Category:** Rocky Linux Help & Support\
**Tags:** rocky-linux-9\
**Created:** [October 16, 2026, 12:18pm UTC](https://forums.rockylinux.org/t/modsecurity-audit-log-empty-when-crs-rules-are-included-inside-a-virtualhost-rocky-9-8-works-on-rocky-8/20845 "2026-10-16T12:18:52Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![samael](https://avatars.discourse-cdn.com/v4/letter/s/b5ac83/32.png) [@samael](https://forums.rockylinux.org/u/samael)\
**Post date:** [October 16, 2026, 12:18pm UTC](https://forums.rockylinux.org/t/modsecurity-audit-log-empty-when-crs-rules-are-included-inside-a-virtualhost-rocky-9-8-works-on-rocky-8/20845/1 "2026-10-16T12:18:52Z")

</div>

Hi,

Since moving to Rocky Linux 9.8, ModSecurity no longer writes anything to the audit log when the CRS rules are included inside a `<VirtualHost>`. The exact same setup works fine on Rocky 8.

## Versions

- Rocky 9.8: `mod_security-2.9.6-4.el9`, `httpd-2.4.62-13.el9_8.6`
- Rocky 8: `mod_security-2.9.6-2.el8_10`, `httpd-2.4.37-65.module+el8.10.0+40312+2c72bb9b.10` (works)

## Configuration

`/etc/httpd/conf.modules.d/10-modsec.conf` (loads the module and the main config, global context):

```apache
LoadModule security2_module modules/mod_security2.so

<IfModule !mod_unique_id.c>
    LoadModule unique_id_module modules/mod_unique_id.so
</IfModule>

Include /etc/modsec/modsec.conf

```

`/etc/modsec/modsec.conf` (main config, audit log settings):

```apache
SecRuleEngine On
SecAuditEngine RelevantOnly
SecAuditLog /var/log/modsecurity_audit.log
SecDefaultAction "phase:2,log,pass"

SecResponseBodyAccess Off
SecRequestBodyAccess On

SecDebugLog /var/log/modsecurity_debug.log
SecDebugLogLevel 0

```

`/etc/modsec/vhosts/website.conf` CRS setup and rules for website:

```apache
SecDefaultAction "phase:1,log,auditlog,pass"
SecDefaultAction "phase:2,log,auditlog,pass"
SecResponseBodyAccess On

SecAction \
    "id:900000,\
    phase:1,\
    pass,\
    t:none,\
    nolog,\
    setvar:tx.blocking_paranoia_level=1"

SecAction \
    "id:900001,\
    phase:1,\
    pass,\
    t:none,\
    nolog,\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/4.30.0',\
    setvar:tx.detection_paranoia_level=1"

SecAction \
    "id:900990,\
    phase:1,\
    pass,\
    t:none,\
    nolog,\
    setvar:tx.crs_setup_version=400"

Include /etc/modsec/crs/rules/*.conf

```

`/etc/httpd/conf.d/website.conf` VirtualHost of a protected site, where the CRS rules are included:

```apache
<VirtualHost *:80>
    DocumentRoot /var/www/html/app
    ServerName website.local

    <Directory "/var/www/html/app">
       AllowOverride All
       Options +FollowSymLinks +ExecCGI
       Options -Indexes
       <FilesMatch "\.php$">
                SetHandler "proxy:unix:/var/run/php80-php-fpm.socket|fcgi://website.local"
        </FilesMatch>
   </Directory>
    
    Include /etc/modsec/vhosts/website.conf

    ErrorLog "/var/log/httpd/website.local-error_log"
    CustomLog "/var/log/httpd/website.local-access_log" combined
</VirtualHost>

```

The CRS rules are included inside the VirtualHost because only some sites need the WAF.

## Behaviour

- CRS rules included outside any VirtualHost: audit log is written normally
- CRS rules included inside a VirtualHost: audit log stays empty, and the debug log shows:

```auto
Audit log: Skipping request since there is nowhere to write to.

```

There are no SELinux denials, and the log file exists and is writable.

## What I found

- Red Hat KB 7143907 describes the same issue after upgrading to RHEL 9.8 with mod\_security-2.9.6-4 (the resolution is subscriber-only)
- Upstream ModSecurity issue #3446 reports the same message on Amazon Linux 2023, and a comment there points to the Fedora `pipedlogs` patch (related to upstream issue #2822), which moves the audit log opening to the `open_logs` hook

My guess is that a VirtualHost with its own ModSecurity config inherits the log path but not the opened file descriptor.

## Questions

1. Has anyone else hit this on Rocky 9.8?
2. Is there a known fix or a planned package update?
3. Is there a cleaner workaround than keeping all rules global and disabling the engine per host with `ctl:ruleEngine=Off`?

Thanks!

---

<div class="post-metadata">

**Author:** ![JDunphy](https://avatars.discourse-cdn.com/v4/letter/j/b9e5f3/32.png) [@JDunphy](https://forums.rockylinux.org/u/JDunphy)\
**Post date:** [October 23, 2026, 1:01am UTC](https://forums.rockylinux.org/t/modsecurity-audit-log-empty-when-crs-rules-are-included-inside-a-virtualhost-rocky-9-8-works-on-rocky-8/20845/2 "2026-10-23T01:01:20Z")

</div>

FWIW, I’m also running Rocky Linux 9.8, and I checked that my installed packages match yours exactly:

```plaintext
mod_security-2.9.6-4.el9.x86_64
httpd-2.4.62-13.el9_8.6.x86_64

```

Audit logging is working here. My configuration is customized, but the relevant layout is:

- Audit-log configuration is global.

- All CRS setup and rule includes are global.

- `SecRuleEngine Off` is set globally.

- The only ModSecurity directive inside a protected virtual host is `SecRuleEngine On`.

I’ve used this arrangement for the past 2–3 years, and it continues to work on Rocky 9.8. However, it doesn’t exercise your failing case, where the CRS setup and rules themselves are included inside the virtual host.

The root-cause section of the Red Hat article seems relevant here. It explains that the change moved audit-log descriptor initialization and management into the main server’s pool to address hangs during graceful restarts with piped logging. The article describes `SecAuditLog` defined inside a virtual host failing to initialize its log target.

**Your `SecAuditLog` is already global** , though, so moving that directive outside the virtual host would not change your posted configuration.

If moving only the CRS setup/rule includes into the virtual host causes logging to fail, that seems consistent with your suspicion that the vhost’s effective configuration is not receiving the globally opened audit-log handle.

My working setup supports your finding that global rule inclusion avoids the problem, but it doesn’t address your goal of keeping the rule includes inside the protected vhosts.
