How to Enable mod_security for Apache

How to enable mod_security for Apache

If Apache-level IP blocking and basic hardening are the locks on your doors, mod_security is the alarm system that watches everything happening inside. I install it on nearly every production server I manage, because it catches entire categories of attacks — SQL injection, XSS, malicious file uploads — before they ever reach your application code. Here’s my complete process for setting it up.

What Is mod_security?

mod_security is an open-source Web Application Firewall (WAF) module for Apache. It inspects incoming HTTP requests (and outgoing responses) against a set of rules, and can block, log, or flag anything that matches a known attack pattern. Most people pair it with the OWASP Core Rule Set (CRS), a community-maintained ruleset covering the most common web application attacks.

Why I Install mod_security on Every Server

  • Blocks common attack patterns like SQL injection and cross-site scripting before they hit your application
  • Provides detailed audit logging for forensic analysis after an incident
  • Virtual patching — lets you block a known vulnerability in your application before you’ve had time to actually fix the code
  • Works alongside application-level security, not as a replacement for it

Prerequisites

  • Root or sudo access
  • Apache 2.4+ installed
  • A staging environment (mod_security in blocking mode can break legitimate functionality if misconfigured, so I never enable it in blocking mode directly on production without testing)

Step 1: Install mod_security

On Debian/Ubuntu:

sudo apt update
sudo apt install libapache2-mod-security2

On CentOS/RHEL:

sudo yum install mod_security

Step 2: Enable the Module

sudo a2enmod security2
sudo systemctl restart apache2

On CentOS/RHEL it’s usually enabled automatically after install; confirm with:

httpd -M | grep security

Step 3: Set Up the Base Configuration

The package typically installs a recommended config file. I copy it to activate it:

sudo cp /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf

Step 4: Start in Detection Mode First

This is the single most important piece of advice I can give: never flip straight to blocking mode on a live site. I always start in DetectionOnly mode so I can review logs for false positives before anything actually gets blocked:

SecRuleEngine DetectionOnly

I leave this running for at least a few days to a week on a real production site, reviewing the audit log for anything that would have blocked legitimate traffic.

Step 5: Install the OWASP Core Rule Set

The base mod_security install has minimal rules on its own — the real protection comes from the OWASP CRS.

cd /etc/modsecurity
sudo git clone https://github.com/coreruleset/coreruleset.git
sudo mv coreruleset/crs-setup.conf.example coreruleset/crs-setup.conf

Then I include the ruleset in the main Apache config, typically in /etc/apache2/mods-enabled/security2.conf:

<IfModule security2_module>
    SecDataDir /var/cache/modsecurity
    IncludeOptional /etc/modsecurity/*.conf
    IncludeOptional /etc/modsecurity/coreruleset/crs-setup.conf
    IncludeOptional /etc/modsecurity/coreruleset/rules/*.conf
</IfModule>

Step 6: Restart and Verify

sudo apachectl configtest
sudo systemctl restart apache2

I then check that the module is actively processing requests:

sudo tail -f /var/log/apache2/modsec_audit.log

Trigger a harmless test request with an obvious attack pattern to confirm logging is working:

curl "http://yourdomain.com/?test=<script>alert(1)</script>"

You should see an entry appear in the audit log, even in detection mode.

Step 7: Review Logs and Tune False Positives

This is the step most people skip, and it’s the reason mod_security gets a bad reputation for “breaking sites.” I go through the audit log methodically and look for legitimate requests that triggered rules. For each false positive, I add a targeted exception rather than disabling the rule globally:

SecRuleRemoveById 942100

Or scope the exception to a specific URL:

<LocationMatch "/wp-admin/admin-ajax.php">
    SecRuleRemoveById 942100
</LocationMatch>

Step 8: Switch to Blocking Mode

Once I’m confident false positives are handled, I flip the switch:

SecRuleEngine On

Restart Apache and monitor closely for the first 24-48 hours after enabling blocking mode.

sudo systemctl restart apache2

Step 9: Set the Paranoia Level

The OWASP CRS has a “paranoia level” that controls how aggressive the rules are. I almost always start at level 1 (the default, least aggressive) and only increase it if the specific application demands stricter security, since higher levels significantly increase false positive risk:

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

Real-World Use Case

For a client running a custom PHP application with a known SQL injection vulnerability that couldn’t be patched immediately due to a code freeze, I used mod_security as a virtual patch — writing a targeted rule to block the specific injection pattern at the WAF level while the development team worked on a proper fix. It bought them two weeks of safety without touching a line of application code.

Common Mistakes to Avoid

  • Enabling blocking mode immediately without a detection-mode testing period, which frequently causes false positives that break legitimate site functionality (like file uploads or search forms).
  • Disabling entire rule categories instead of scoping exceptions narrowly, which reopens the exact attack surface you were trying to close.
  • Never updating the Core Rule Set, missing coverage for newly discovered attack patterns.
  • Ignoring the audit log entirely after setup, missing both false positives and genuine attack attempts.

Troubleshooting Tips

If legitimate form submissions or file uploads start failing after enabling blocking mode, check the modsec_audit.log for the specific rule ID that triggered and add a scoped exception for that endpoint rather than disabling mod_security altogether. If performance seems impacted on a high-traffic site, consider tuning SecRequestBodyLimit and disabling response body inspection for endpoints that don’t need it.

Security and Performance Best Practices

  • Keep the OWASP Core Rule Set updated regularly — cd /etc/modsecurity/coreruleset && sudo git pull.
  • Combine mod_security with rate limiting and IP blocking for layered defense.
  • Monitor the audit log with a log analysis tool or SIEM for ongoing visibility into attack attempts.
  • Always test rule changes in staging before deploying to production.

Frequently Asked Questions

Will mod_security slow down my website? There’s a small performance overhead from request inspection, but on modern hardware it’s generally negligible compared to the security benefit, especially if you tune the paranoia level appropriately.

Do I need the OWASP Core Rule Set, or can I write my own rules? The CRS gives you broad, community-vetted coverage out of the box. Custom rules are useful for application-specific virtual patching, but I always start with the CRS as the foundation.

What’s the difference between DetectionOnly and On? DetectionOnly logs matched rules without blocking anything, letting you review for false positives. On mode actually blocks requests matching a rule.

Can mod_security replace regular security patching? No. It’s a defense-in-depth layer, not a substitute for keeping your application code and dependencies updated.

Summary and Key Takeaways

mod_security combined with the OWASP Core Rule Set gives your Apache server real, application-layer attack protection against SQL injection, XSS, and other common exploits. The key to a smooth rollout is patience: start in detection mode, review logs thoroughly, scope your exceptions narrowly, and only move to blocking mode once you’re confident false positives are handled.

References

Total
1
Shares

Leave a Reply

Previous Post
How to limit the number of concurrent connections in Apache

How to Limit the Number of Concurrent Connections in Apache

Next Post
How to block IP addresses in Apache

How to Block IP Addresses in Apache

Related Posts