Updated: 29 September 2026 · Applies to: ModSecurity 2.9 with the OWASP Core Rule Set 3.3 on Apache 2.4: AlmaLinux and Rocky Linux 9, RHEL 9, Ubuntu 24.04 and 26.04, Debian 13

ModSecurity is a web application firewall (WAF) module for Apache. Together with the OWASP Core Rule Set (CRS), it blocks common attacks such as SQL injection and cross-site scripting before they reach your application. We tested the setup below on AlmaLinux 9 (ModSecurity 2.9.6, CRS 3.3.5) and Debian 13 (ModSecurity 2.9.11, CRS 3.3.7): normal requests passed, and test attacks were blocked with "403 Forbidden".

AlmaLinux, Rocky Linux and RHEL 9

dnf install mod_security mod_security_crs
systemctl restart httpd

The module is configured in /etc/httpd/conf.d/mod_security.conf with SecRuleEngine On, so it blocks right away. The rules are in /etc/httpd/modsecurity.d/, and your own rules or exceptions go into /etc/httpd/modsecurity.d/local_rules/. On version 10, mod_security comes from EPEL and the CRS is not packaged; download it from the OWASP CRS project.

Ubuntu and Debian

apt install libapache2-mod-security2 modsecurity-crs
cp /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf

The recommended file starts in detection mode (SecRuleEngine DetectionOnly), which only logs. Watch the log for a while (see below), then switch to blocking by changing that line in /etc/modsecurity/modsecurity.conf to:

SecRuleEngine On
apache2ctl configtest && systemctl restart apache2

The package loads the CRS automatically from /usr/share/modsecurity-crs/.

Test it

curl -s -o /dev/null -w "%{http_code}\n" "http://localhost/"
curl -s -o /dev/null -w "%{http_code}\n" "http://localhost/?q=<script>alert(1)</script>"

The first request should return 200, the second 403. Check that the module is loaded with apachectl -M | grep security2.

Logs and false positives

  • Blocked requests are logged in the Apache error log with the rule ID, and in detail in /var/log/httpd/modsec_audit.log or /var/log/apache2/modsec_audit.log.
  • If a legitimate request is blocked, note the rule id from the log and exclude only that rule, and only where needed, for example for one URL:
    SecRule REQUEST_URI "@beginsWith /wp-admin/" "id:1000001,phase:1,pass,nolog,ctl:ruleRemoveById=941100"
    Put such exceptions in the local rules folder (AlmaLinux, Rocky Linux) or a new file in /etc/modsecurity/ (Ubuntu, Debian), and use your own IDs above 1000000.
  • Start with the default paranoia level. Higher levels catch more but block more legitimate traffic.

On cPanel servers

Do not install these packages on a cPanel server. Use WHM instead: Security Center > ModSecurity Configuration for the engine, and ModSecurity Vendors for the OWASP rule set.

Official documentation: OWASP CRS documentation and ModSecurity 2.x reference manual.

Related services

KVM VPS hosting

NVMe SSD and full root access, with Free Basic Managed Support.

Managed cPanel VPS

cPanel included; we handle updates, security and monitoring.

Server management

on-demand administration, hardening, migrations and monitoring.

Was this answer helpful?

Still stuck? Open a ticket