ModSecurity is the leading open-source Web Application Firewall (WAF), capable of inspecting all HTTP requests and responses against a ruleset and blocking malicious traffic including SQL injection, cross-site scripting (XSS), remote file inclusion, and OWASP Top 10 attack patterns. Combined with the OWASP Core Rule Set (CRS), ModSecurity transforms Apache into a security gateway that sits in front of your application and filters requests before they reach your code. On RHEL 9, ModSecurity for Apache is installed from the AppStream repository as mod_security, and the OWASP CRS is available separately. This guide covers installing ModSecurity with Apache on RHEL 9, enabling the OWASP Core Rule Set in detection mode, tuning rules to eliminate false positives, and switching to enforcement mode.

Prerequisites

  • Apache (httpd) installed and running on RHEL 9
  • Root or sudo access

Step 1 — Install ModSecurity

dnf install -y mod_security mod_security_crs

# Verify the module loaded
httpd -M | grep security

# Check the version
rpm -q mod_security

Step 2 — Understand the Configuration Files

  • /etc/httpd/conf.d/mod_security.conf — main ModSecurity configuration loaded by Apache
  • /etc/httpd/modsecurity.d/ — additional rule files
  • /usr/share/mod_security_crs/ — OWASP Core Rule Set files
  • /var/log/httpd/modsec_audit.log — ModSecurity audit log

Step 3 — Configure ModSecurity in Detection Mode

Always start in detection mode (DetectionOnly) so you can tune rules before blocking legitimate traffic:

vi /etc/httpd/conf.d/mod_security.conf

    # Enable ModSecurity
    SecRuleEngine DetectionOnly    # Change to On for enforcement

    # Log format
    SecAuditEngine RelevantOnly    # Only log relevant transactions
    SecAuditLog /var/log/httpd/modsec_audit.log
    SecAuditLogParts ABIJDEFHZ
    SecAuditLogType Serial

    # Request body handling
    SecRequestBodyAccess On
    SecRequestBodyLimit 13107200   # 12.5MB
    SecRequestBodyNoFilesLimit 131072

    # Response body handling
    SecResponseBodyAccess Off      # Enable to inspect responses too

    # Temporary file storage for large request bodies
    SecTmpDir /tmp/
    SecDataDir /tmp/

    # Include OWASP CRS
    Include /etc/httpd/modsecurity.d/*.conf
    Include /usr/share/mod_security_crs/crs-setup.conf
    Include /usr/share/mod_security_crs/rules/*.conf
apachectl configtest && systemctl reload httpd

Step 4 — Test ModSecurity is Working

# Test with a known XSS payload
curl -s "http://localhost/?q=alert(1)" -o /dev/null -w "%{http_code}n"
# In DetectionOnly mode: returns 200 but logs the event
# In enforcement mode: returns 403

# Check the audit log
tail -50 /var/log/httpd/modsec_audit.log

Step 5 — Tune Rules to Eliminate False Positives

Before switching to enforcement mode, run in detection mode for at least 48 hours and review the audit log for false positives:

# Find the most frequently triggered rule IDs
grep 'id "[0-9]' /var/log/httpd/modsec_audit.log | 
    grep -oP 'id "[0-9]+"' | sort | uniq -c | sort -rn | head -20
# Create a custom exclusion file
vi /etc/httpd/modsecurity.d/exclusions.conf
# Disable a specific rule by ID
SecRuleRemoveById 920350

# Disable a rule for a specific URI
SecRule REQUEST_URI "@beginsWith /admin/upload" 
    "id:1000,phase:1,pass,nolog,ctl:ruleRemoveById=920420"

# Disable a rule for a specific parameter
SecRuleRemoveTargetById 942100 "ARGS:editor_content"

Step 6 — Switch to Enforcement Mode

Once false positives are resolved, switch from DetectionOnly to enforcement:

sed -i 's/SecRuleEngine DetectionOnly/SecRuleEngine On/' 
    /etc/httpd/conf.d/mod_security.conf

apachectl configtest && systemctl reload httpd

# Verify enforcement is active
grep SecRuleEngine /etc/httpd/conf.d/mod_security.conf

Verification Checklist

httpd -M | grep security2
grep SecRuleEngine /etc/httpd/conf.d/mod_security.conf
curl -si "http://localhost/?q=alert(1)" | head -1
tail -5 /var/log/httpd/modsec_audit.log

Conclusion

ModSecurity with the OWASP Core Rule Set on RHEL 9 Apache provides enterprise-grade WAF protection against OWASP Top 10 attacks. Always deploy in DetectionOnly first, tune false positives with rule exclusions, then switch to enforcement mode. Regular CRS updates (dnf update mod_security_crs) keep your WAF current with evolving threats.

Next steps: How to Configure Nginx with ModSecurity WAF on RHEL 9, How to Configure Nginx Rate Limiting on RHEL 9, and How to Harden Web Servers: Security Headers, CSP, HSTS on RHEL 9.