ModSecurity and OWASP CRS for shared hosting without false positives
ModSecurity OWASP CRS setup for shared hosting without false positives: engine versions, anomaly scoring, paranoia levels and per-site exclusions.

Key takeaways
- ModSecurity v2 and v3 are both maintained by OWASP; for new CRS 4 deployments the CRS project recommends Coraza, and supports v3 only with nginx.
- CRS 3.3.x has reached end of life, yet Ubuntu and Debian still ship 3.3.x packages.
- False positives are handled with anomaly thresholds, paranoia levels and narrow exclusions scoped to one site, path and parameter.
- On shared hosting, never add a server-wide exclusion to fix one customer's site.
To run ModSecurity with the OWASP Core Rule Set (CRS) on shared hosting without false positives, keep the rules at paranoia level 1, use anomaly scoring with the default inbound threshold of 5 as your target, roll each site out gradually, and fix false positives with narrow exclusions scoped to one site, one URL and one parameter instead of switching rules off for the whole server. Also check your versions: CRS 3.3.x has reached end of life, while the current CRS 4 releases and both ModSecurity engines are actively maintained.
This article is the server-side companion to our WordPress WAF guide, which compares cloud WAFs, plugins and server WAFs. Here we focus on what matters when one firewall protects dozens or hundreds of unrelated websites.
Which ModSecurity and CRS versions are current?
The landscape changed in 2024: Trustwave ended its support for ModSecurity on 1 July 2024 and the project moved to OWASP, where both engine lines continue in the ModSecurity repository.
| Component | Latest release (October 2026) | Status |
|---|---|---|
| ModSecurity v2 (Apache module) | 2.9.15, 29 September 2026 | Maintained by OWASP |
| ModSecurity v3 (libmodsecurity) | 3.0.17, 29 September 2026 | Maintained by OWASP; used with nginx through the ModSecurity-nginx connector |
| Coraza (Go) | See Coraza | Recommended by CRS for new CRS 4 deployments |
| CRS 4 | 4.30.0, 2 October 2026 | Current CRS releases |
| CRS 4 LTS | 4.25.2, 2 October 2026 | Long-term support line, supported until Q3 2027 |
| CRS 3.3 | 3.3.10, 2 July 2026 | End of life, per the CRS website |
The CRS team's engine notes for migrating from CRS 3 to 4 are worth reading before you choose:
- ModSecurity v2 on Apache is "the most mature engine and the one where CRS has historically been developed and tested". CRS 4 requires v2.9.x.
- ModSecurity v3 with nginx is supported, but the nginx connector "has historically had gaps in SecLang support", so the CRS team recommends testing your setup. Apache with v3 is not supported, and nginx with v2 support has been removed.
- Coraza "moves faster than ModSecurity v3" and is "the recommended engine for new CRS 4 deployments".
What your distribution ships
If you install from Ubuntu or Debian packages, you get CRS 3.3.x, not CRS 4:
| Release | modsecurity-crs package |
nginx ModSecurity module |
|---|---|---|
| Ubuntu 22.04 | 3.3.2 | Not packaged |
| Ubuntu 24.04 | 3.3.5 | Packaged |
| Ubuntu 26.04 | 3.3.8 | Packaged |
| Debian 12 | 3.3.4 (with security updates) | Packaged |
| Debian 13 | 3.3.7 (with security updates) | Packaged |
Sources: Launchpad and Debian sources. Distribution security teams backport fixes into their packages, but you get neither CRS 4's new features nor the upstream support window. If you maintain the WAF yourself for years, plan a move to CRS 4.
How CRS decides to block: anomaly scoring
CRS does not block on the first matching rule. Each rule that matches adds points to an anomaly score, and the request is blocked only when the total reaches a threshold. Per the CRS documentation on anomaly scoring:
| Severity | Points |
|---|---|
| CRITICAL | 5 |
| ERROR | 4 |
| WARNING | 3 |
| NOTICE | 2 |
The default inbound threshold is 5, so one critical match (a clear SQL injection, for example) blocks the request. The outbound threshold is 4. Raising thresholds makes CRS less sensitive, and the documentation warns that keeping them high lets many attacks through, so higher values should only be temporary while you tune.
This matters for false positives: a single noisy NOTICE rule cannot block a request on its own. When a legitimate request is blocked, it is usually one critical rule or a few warnings adding up, and the audit log tells you which.
Paranoia levels: start at 1
CRS groups its rules into four paranoia levels. Level 1 is "baseline security with a minimal need to tune away false positives". Level 2 suits sites handling real user data, such as shops. Levels 3 and 4 are for high-value targets and come with many false positives.
On shared hosting, keep the server at paranoia level 1. You do not control the code of the sites you host, and every extra level multiplies the tuning work across all of them. CRS also has an "executing paranoia level": rules from a higher level can run and log without counting toward blocking, which lets you see what PL2 would catch before you commit to it.
Rolling out on a shared server
There are two schools:
- Detection only first. Set the engine to
DetectionOnlyfor a site, collect a few days of traffic, fix the false positives, then switch to blocking. Easy to understand and safe for customers. - Blocking with a very high threshold. The CRS documentation recommends, for new deployments, starting in blocking mode with very high anomaly thresholds, even as high as 10000, and lowering them over time. The advantage is that the blocking machinery is live from day one.
On a shared server the first approach is usually easier to explain to customers, because per-site detection mode never breaks anything. Whichever you choose, do it per site, not for the whole server at once, and start with sites you know well.
Fixing false positives without weakening every site
Read the audit log first
Every blocked or logged request lands in the ModSecurity audit log with the rule IDs that matched. With JSON audit logging (SecAuditLogFormat JSON on v3), you can list the host, URI and rules quickly:
jq -r '.transaction | [.request.headers.Host // .request.headers.host, .request.uri,
(.messages | map(.details.ruleId) | join(","))] | @tsv' /var/log/modsec_audit.log | sort | uniq -c | sort -rn | head
Adjust the path to your setup. Look for patterns: the same rule on the same URL for the same site, again and again, is a false positive candidate. A rule matching random URLs from many IPs is probably real attack traffic.
Choose the narrowest exclusion
The CRS documentation on false positives and tuning describes two families of exclusions:
| Type | Directives | Applies | Where to put it |
|---|---|---|---|
| Configure-time | SecRuleRemoveById, SecRuleRemoveByTag, SecRuleUpdateTargetById |
Every request in its scope | After the CRS include |
| Runtime | ctl:ruleRemoveById, ctl:ruleRemoveTargetById inside a SecRule |
Only requests that match your condition | Before the CRS include |
The narrowest fix is to exclude one parameter from one rule on one site and path. For example, a page builder on shop.example.com that saves HTML in a content field and trips SQL injection rule 942100:
# Before the CRS rules. Only this host, only this URL, only this field.
SecRule REQUEST_HEADERS:Host "@streq shop.example.com" \
"id:10001,phase:1,pass,nolog,chain"
SecRule REQUEST_FILENAME "@endsWith /wp-admin/post.php" \
"t:none,ctl:ruleRemoveTargetById=942100;ARGS:content"
Rule 942100 still protects every other field on that site, and every other site on the server. Compare that with SecRuleRemoveById 942100 at server level, which removes SQL injection detection for every customer at once.
The CRS documentation also advises: never edit the CRS rule files themselves (updates overwrite them), avoid excluding by broad tags such as language-multi that cover hundreds of rules, and do not match on rule messages.
Use the application exclusion packages
CRS ships exclusion packages for common applications, including WordPress, Drupal, Nextcloud, phpBB, phpMyAdmin, DokuWiki, XenForo and cPanel. In CRS 3.3 you enable one with a variable such as tx.crs_exclusions_wordpress=1; in CRS 4 they moved to separate plugins. On shared hosting, enable each package only for the hosts that run that application, never globally, and treat it as a starting point: plugins and page builders can still trigger rules.
Keeping the WAF light
- Skip static files. Images, CSS and JavaScript do not need inspection and make up most requests.
- Leave response body inspection off unless you need data leak detection. It costs memory and CPU on every page.
- Keep the audit log to relevant events (blocked requests and server errors), and rotate it.
- Stay at paranoia level 1 on the server, and raise it only for specific sites that need it.
How ZoPanel handles ModSecurity and CRS
ZoPanel installs ModSecurity v3 with the nginx connector and the distribution's OWASP CRS package, from Security → Web application firewall. According to the website tools documentation and the security documentation:
- The firewall is off for every site until enabled, and the rules are only loaded while at least one website uses them, at about 25 MB of RAM per nginx worker.
- Each website has three modes in its Tools tab: On (block attacks), Detect only (log) and Off. Apply to all websites sets one mode everywhere.
- The events table shows time, IP, request and reason for each site. Allow this on an event adds the matching rule IDs to that website's Allowed rules, so the exception never affects other customers.
- Static files skip the firewall.
- Sites created as a known application, such as WordPress, get the CRS exclusion package for that application, matched by host name.
The honest limits: because it uses distribution packages, the rule set is CRS 3.3.x (3.3.5 on Ubuntu 24.04, for example), not CRS 4. Allow this removes a rule for the whole website rather than for one parameter, which is coarser than the runtime exclusion shown above. And Ubuntu 22.04 has no ModSecurity module for nginx, so the WAF is not available there. Customers who need parameter-level tuning or CRS 4 today will get more control from a hand-maintained setup or a dedicated WAF service. Either way, a WAF only filters requests: it does not replace account isolation or a plan for cleaning a hacked site.
Conclusion
ModSecurity with OWASP CRS works on shared hosting when you treat it as a per-site rollout rather than a server-wide switch: paranoia level 1, the default threshold as the target, detection or high-threshold blocking first, and exclusions scoped to one site, one path and one parameter. Check your versions too, because the CRS 3.3 packages most distributions ship have reached end of life upstream.
If you want per-site WAF modes and one-click exceptions without writing SecLang, you can try it on the ZoPanel Free plan (3 hosting accounts, 10 websites, no time limit) on Ubuntu 24.04, 26.04 or Debian. More on the security layers is on the security features page.
Frequently asked questions
What is the difference between ModSecurity and OWASP CRS?
ModSecurity is the engine: it inspects HTTP requests and runs rules written in its rule language. The OWASP Core Rule Set is a set of generic attack detection rules for that engine, covering SQL injection, cross-site scripting, remote code execution, scanners and more. You need both, or a compatible engine such as Coraza.
Should I use ModSecurity v2 or v3?
It depends on your web server. On Apache, ModSecurity v2 is the most mature option and is fully supported by CRS 4. On nginx, v3 with the nginx connector is the supported path. For brand-new CRS 4 deployments, the CRS project recommends Coraza.
Is CRS 3.3 still supported?
No. The CRS website states that CRS 3.3.x has reached end of life and recommends migrating. Ubuntu and Debian still ship 3.3.x packages and patch them through their own security process, so check how your distribution handles updates.
How do I stop ModSecurity blocking a legitimate request?
Find the rule IDs in the audit log, then add the narrowest exclusion that fixes it: remove one parameter from one rule for one URL and host, using ctl:ruleRemoveTargetById before the CRS rules. Avoid removing whole rules server-wide, and never edit the CRS files themselves.
Does ModSecurity slow down websites?
It adds some CPU per inspected request and memory per web server worker. Skipping static files, leaving response body inspection off, staying at paranoia level 1 and serving cached pages keep the overhead small compared with the time PHP spends building a page.
Install ZoPanel free
One command on a fresh Ubuntu or Debian server. Up and running in minutes.
Install in 5 minutesKeep reading

Hosting account resource limits: CPU, RAM and I/O done right
What hosting account resource limits for CPU, RAM, I/O, processes and inodes do, how Linux enforces them, and how to size plans so one site can't sink a server.

Hosting panel security incidents 2024–2026: what went wrong and what to learn
A sourced timeline of hosting control panel vulnerabilities 2024–2026 (cPanel, CyberPanel, CWP, Plesk, HestiaCP), the patterns and a defense checklist.

Hosting server security checklist: 40 checks
A hosting server security checklist with 40 checks for a VPS that hosts websites: updates, SSH, firewall, panel, account isolation, web layer and backups.