ModSecurity is a powerful open-source web application firewall (WAF) module for Apache HTTP servers. A WAF acts as a security layer between your web server and incoming traffic, analyzing HTTP requests in real time and blocking malicious activity before it reaches your applications. ModSecurity protects against common attacks including SQL injections (where attackers try to manipulate database queries), cross-site scripting (XSS, where malicious scripts are injected into web pages), and remote code execution attempts.
This guide covers installing ModSecurity 2 on Debian using the Digitalwave repository, which provides up-to-date stable binaries. You will also configure the OWASP Core Rule Set (CRS), a comprehensive collection of predefined security rules maintained by the Open Web Application Security Project. Together, ModSecurity and OWASP CRS form a robust defense layer for any Apache web server running on Debian. For production deployments, combine this setup with SSL/TLS encryption using Let’s Encrypt for complete transport security.
Update Debian System Packages
Before proceeding with ModSecurity installation, start by ensuring your Debian system is updated. Additionally, keeping all packages current not only boosts performance but also minimizes security vulnerabilities:
sudo apt update && sudo apt upgrade
After updating, check if Apache is installed on your system. If Apache is missing, install it with this command:
sudo apt install apache2
Add the Digitalwave ModSecurity Repository
Next, configure the Digitalwave repository for up-to-date ModSecurity packages. While Debian’s default repositories include ModSecurity, the version available is often outdated, which could lead to compatibility issues or missing security patches. However, the Digitalwave repository provides stable, up-to-date binaries of ModSecurity and the OWASP Core Rule Set specifically packaged for Debian and Ubuntu systems.
Install Required Dependencies
First, install the necessary packages for secure repository management:
sudo apt install apt-transport-https lsb-release ca-certificates curl -y
Import the GPG Key
Next, download and store the repository GPG key to verify package authenticity:
curl -fsSL https://modsecurity.digitalwave.hu/archive.key | sudo gpg --dearmor -o /usr/share/keyrings/digitalwave-modsecurity.gpg
Add the Repository
Now, create the repository configuration file using DEB822 format, which is the modern standard for Debian 12 and newer:
cat <<EOF | sudo tee /etc/apt/sources.list.d/digitalwave-modsecurity.sources
Types: deb
URIs: http://modsecurity.digitalwave.hu/debian/
Suites: $(lsb_release -cs) $(lsb_release -cs)-backports
Components: main
Architectures: $(dpkg --print-architecture)
Signed-By: /usr/share/keyrings/digitalwave-modsecurity.gpg
EOF
Debian 12 (Bookworm) is the oldest currently supported stable Debian version and uses the modern DEB822 .sources format shown above. All current and future Debian releases (12, 13 Trixie, and onwards) use this format as standard. Debian 11 (Bullseye) still uses the legacy .list format—if running Debian 11, use the alternative command format instead.
Configure APT Package Priorities
To ensure APT prioritizes ModSecurity packages from the Digitalwave repository over default Debian packages, create a pinning configuration:
cat <<EOF | sudo tee /etc/apt/preferences.d/99modsecurity
Package: *libapache2-mod-security2*
Pin: origin modsecurity.digitalwave.hu
Pin-Priority: 900
Package: *modsecurity-crs*
Pin: origin modsecurity.digitalwave.hu
Pin-Priority: 900
Package: *libmodsecurity*
Pin: origin modsecurity.digitalwave.hu
Pin-Priority: 900
EOF
Following this, update the package list to include the new repository:
sudo apt update
Then, verify the repository priority is correctly applied:
apt-cache policy libapache2-mod-security2 modsecurity-crs libmodsecurity3
The output should show the Digitalwave repository with priority 900, confirming packages will be installed from there:
libapache2-mod-security2:
Installed: (none)
Candidate: 2.9.7-1+deb12u1
Version table:
2.9.7-1+deb12u1 900
900 http://modsecurity.digitalwave.hu/debian bookworm/main amd64 Packages
modsecurity-crs:
Installed: (none)
Candidate: 3.3.4-1
Version table:
3.3.4-1 900
900 http://modsecurity.digitalwave.hu/debian bookworm-backports/main amd64 Packages
Install the ModSecurity 2 Module
Now, install the ModSecurity Apache module from the Digitalwave repository:
sudo apt install libapache2-mod-security2
Once installed, enable the module in Apache:
sudo a2enmod security2
The output confirms the module is enabled:
Enabling module security2. To activate the new configuration, you need to run: systemctl restart apache2
Finally, restart Apache to load the new module:
sudo systemctl restart apache2
Configure ModSecurity 2
Verify the Module Configuration
The ModSecurity configuration file is located at /etc/apache2/mods-enabled/security2.conf. Open it to verify the configuration:
sudo nano /etc/apache2/mods-enabled/security2.conf
Confirm the following line is present and uncommented, as it includes configuration files from the ModSecurity directory:
IncludeOptional /etc/modsecurity/*.conf
Apache leaves this line uncommented by default. After verification, close the file.
Activate the ModSecurity Configuration
Next, activate the ModSecurity configuration. ModSecurity ships with a recommended configuration file. Rename it to activate ModSecurity:
sudo mv /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf
Then, open the configuration file to enable active protection:
sudo nano /etc/modsecurity/modsecurity.conf
By default, ModSecurity runs in DetectionOnly mode, which logs potential threats without blocking them. This is useful for initial testing but does not provide active protection. To enable blocking, locate the SecRuleEngine line near line 7 and change it from:
SecRuleEngine DetectionOnly
To:
SecRuleEngine On
Running in DetectionOnly mode for a few days before switching to On is recommended. This allows you to review logs and identify any false positives that might block legitimate traffic before enabling active blocking.
Configure Audit Log Settings
Additionally, configure the audit log settings for comprehensive monitoring. Further down in the configuration file (around line 224), locate the SecAuditLogParts setting. However, the default configuration does not capture all useful transaction data. Therefore, change the line from:
SecAuditLogParts ABDEFHIJZ
To:
SecAuditLogParts ABCEFHJKZ
Each letter represents a section of the audit log: A (audit log header), B (request headers), C (request body), E (response body), F (final response headers), H (audit log trailer with additional data), J (upload file information), K (matched rules), and Z (final boundary). This configuration provides comprehensive logging for analyzing blocked requests and troubleshooting false positives. Save your changes and exit the editor.
After making these changes, restart Apache to apply the configuration:
sudo systemctl restart apache2
Install OWASP Core Rule Set
ModSecurity provides the engine for processing security rules, but needs a rule set to identify and block threats. Furthermore, the OWASP Core Rule Set (CRS) is the industry-standard rule set used by web application firewalls worldwide. It provides protection against common attack vectors including SQL injection, XSS, local file inclusion, and remote code execution.
While the Digitalwave repository includes the OWASP CRS as a packaged installation (modsecurity-crs), which simplifies updates and maintenance, you can alternatively download the latest release directly from the OWASP CRS GitHub releases page. This guide covers the manual installation method to give you full control over the CRS version.
Create the CRS Directory
First, create a directory to store the OWASP CRS files:
sudo mkdir -p /etc/apache2/modsec/
Download and Extract the CRS
Next, download the latest stable OWASP CRS release. As of this writing, version 4.20.0 is the current stable release. However, always verify the latest version on the GitHub releases page before downloading:
wget https://github.com/coreruleset/coreruleset/archive/refs/tags/v4.20.0.tar.gz -O /tmp/coreruleset.tar.gz
Once downloaded, extract the archive to the ModSecurity directory:
sudo tar -xzf /tmp/coreruleset.tar.gz -C /etc/apache2/modsec/
Then, rename the directory for easier reference:
sudo mv /etc/apache2/modsec/coreruleset-4.20.0 /etc/apache2/modsec/crs
The OWASP CRS project releases updates quarterly and when urgent security patches arrive. Subscribe to the GitHub releases page to receive notifications about new versions.
Configure the Rule Set
The CRS includes a sample configuration file. Copy it to activate the rule set:
sudo cp /etc/apache2/modsec/crs/crs-setup.conf.example /etc/apache2/modsec/crs/crs-setup.conf
Enable the Rules in Apache
Now, edit the ModSecurity Apache configuration to include the CRS rules:
sudo nano /etc/apache2/mods-enabled/security2.conf
Inside the file, add the following lines before the closing </IfModule> tag to load the CRS configuration and rules:
Include /etc/apache2/modsec/crs/crs-setup.conf
Include /etc/apache2/modsec/crs/rules/*.conf
Additionally, if the following line exists, comment it out or remove it to prevent conflicts with the manual CRS installation:
# IncludeOptional /usr/share/modsecurity-crs/*.load
After saving the file, restart Apache to load the rules:
sudo systemctl restart apache2
Understanding OWASP CRS Configuration
The OWASP Core Rule Set offers extensive customization options. The default configuration provides solid protection for most servers without blocking legitimate traffic or affecting search engine crawlers. This section covers the key configuration concepts.
Edit the CRS Configuration
Open the CRS configuration file to customize settings:
sudo nano /etc/apache2/modsec/crs/crs-setup.conf
CRS Scoring Modes
ModSecurity with CRS operates in two modes:
- Anomaly Scoring Mode (default and recommended): Each rule match adds points to an anomaly score. After processing all rules, if the total score exceeds a threshold, ModSecurity triggers a blocking action (typically a 403 Forbidden response). Furthermore, this mode provides detailed logging and allows fine-tuning of sensitivity through score thresholds.
- Self-Contained Mode: In contrast, each rule acts independently and can block requests immediately upon matching. While this uses fewer resources, it provides less flexibility and less detailed logs. As a result, the rule processing stops after the first match that triggers a block.
Paranoia Levels
The CRS defines four paranoia levels that control how aggressively rules are applied:
- Paranoia Level 1 (default): Suitable for most production environments with minimal false positives.
- Paranoia Level 2: Enables additional rules for environments requiring higher security.
- Paranoia Level 3: For security-critical applications where some false positives are acceptable.
- Paranoia Level 4: Maximum security with the highest rate of false positives. Only suitable after extensive tuning.
Higher paranoia levels enable more rules, increasing security coverage but also increasing the likelihood of blocking legitimate requests. Therefore, start with Paranoia Level 1 and only increase after monitoring logs for several weeks to understand your traffic patterns.
Test the Configuration
To verify ModSecurity and OWASP CRS are working correctly, trigger a test rule. First, open a browser and access the following URL (replace yourdomain.com with your actual domain):
https://yourdomain.com/index.html?exec=/bin/bash
If ModSecurity is configured correctly with SecRuleEngine set to On, you will receive a 403 Forbidden error. Consequently, this confirms that the CRS detected the command injection attempt in the query string and blocked the request.
However, if you receive a normal page response instead of a 403 error, verify that:
- SecRuleEngine is set to On (not DetectionOnly) in /etc/modsecurity/modsecurity.conf
- Apache was restarted after configuration changes
- The CRS rules are properly included in the security2.conf file
Manage False Positives and Exclusion Rules
Managing false positives is an ongoing task when running a web application firewall. The CRS is designed to minimize false positives at the default paranoia level, but certain applications or custom functionality may trigger rules incorrectly. The recommended approach is to run at a low paranoia level initially and monitor logs for several weeks before adjusting rules or increasing security levels.
Application-Specific Exclusions
Furthermore, the CRS includes built-in exclusion profiles for common applications. While these are disabled by default, they can be enabled in the crs-setup.conf file. Look for the SecAction block with id:900130:
#SecAction \
# "id:900130,\
# phase:1,\
# nolog,\
# pass,\
# t:none,\
# setvar:tx.crs_exclusions_cpanel=1,\
# setvar:tx.crs_exclusions_dokuwiki=1,\
# setvar:tx.crs_exclusions_drupal=1,\
# setvar:tx.crs_exclusions_nextcloud=1,\
# setvar:tx.crs_exclusions_phpbb=1,\
# setvar:tx.crs_exclusions_phpmyadmin=1,\
# setvar:tx.crs_exclusions_wordpress=1,\
# setvar:tx.crs_exclusions_xenforo=1"
To enable exclusions for specific applications, uncomment the block and set the value to 1 for applications you use. For example, to enable WordPress and phpMyAdmin exclusions:
SecAction \
"id:900130,\
phase:1,\
nolog,\
pass,\
t:none,\
setvar:tx.crs_exclusions_wordpress=1,\
setvar:tx.crs_exclusions_phpmyadmin=1"
Create Custom Exclusion Rules
For custom exclusions beyond the built-in profiles, use the pre-CRS exclusion file. First, copy the example file:
sudo cp /etc/apache2/modsec/crs/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example /etc/apache2/modsec/crs/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
Then, edit the file to add custom exclusion rules:
sudo nano /etc/apache2/modsec/crs/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
Each exclusion rule requires a unique ID number. The following examples demonstrate common exclusion patterns:
Exclude a specific URL path from all rules:
SecRule REQUEST_URI "@beginsWith /api/webhook" "id:1001,phase:1,nolog,allow,ctl:ruleEngine=off"
Whitelist a specific IP address:
SecRule REMOTE_ADDR "@ipMatch 192.168.1.100" "id:1002,phase:1,nolog,allow,ctl:ruleEngine=off"
Whitelist a subnet:
SecRule REMOTE_ADDR "@ipMatch 10.0.0.0/8,192.168.0.0/16" "id:1003,phase:1,nolog,allow,ctl:ruleEngine=off"
These exclusion rules integrate well with Fail2Ban for creating dynamic block lists based on repeated malicious behavior.
Disable Specific Rules
Alternatively, if specific rules consistently cause false positives for legitimate functionality, you can disable them for specific paths rather than globally. For example, to disable rules 941000-942999 for an admin area:
SecRule REQUEST_FILENAME "@beginsWith /admin" "id:1004,phase:1,pass,nolog,ctl:ruleRemoveById=941000-942999"
Following any exclusions, restart Apache to apply changes:
sudo systemctl restart apache2
Monitor Logs for False Positives
To maintain an effective WAF configuration, regular log analysis is essential. ModSecurity logs blocked requests and rule matches to /var/log/modsec_audit.log. Therefore, review this log to identify patterns that need exclusion rules:
sudo tail -f /var/log/modsec_audit.log
When analyzing logs, look for rule IDs that appear frequently with legitimate requests and create targeted exclusions for those specific scenarios rather than disabling rules globally.
Configure Log Rotation
To manage disk space effectively, configure log rotation for ModSecurity audit logs. Since these logs can grow rapidly on busy servers, implementing log rotation helps manage disk space and maintain readable log files.
First, create a logrotate configuration file for ModSecurity:
sudo nano /etc/logrotate.d/modsecurity
Next, add the following configuration:
/var/log/modsec_audit.log {
rotate 31
daily
missingok
compress
delaycompress
notifempty
}
This configuration:
- rotate 31: Keeps 31 days of logs (adjust based on your retention requirements)
- daily: Rotates logs every day
- compress: Compresses rotated logs to save disk space
- delaycompress: Delays compression until the second rotation cycle
- missingok: Does not generate an error if the log file is missing
- notifempty: Does not rotate empty log files
Conclusion
ModSecurity 2 with the OWASP Core Rule Set provides comprehensive protection against common web application attacks on your Debian server. Furthermore, the Digitalwave repository simplifies installation and maintenance by providing up-to-date packages. When combined with proper log monitoring and targeted exclusion rules, this configuration forms a robust security layer for Apache web servers hosting any type of web application.
Not a bad article, everything is explained in detail, but some parts feel overly drawn out. I liked that it covers not only the installation of ModSecurity but also the setup of the OWASP Core Rule Set. This is useful for those just starting to explore web security. The section on paranoia levels and handling false positives stood out—it clearly highlights what to focus on to ensure stable system performance. One thing I wish it had is more practical examples for setting up exclusions for popular applications like WordPress or phpMyAdmin. Overall, it’s a solid resource, especially for beginners.
Thanks Alex, I could not cover too much more into OWASP core rule set as the needs a separate beginners guide and probably advanced guides, so many possibilities with the core rule set to customize, whitelist, create custom options and much more. The guide was just focused on installing it and doing a brief run through as you mentioned.
Appreciate the feedback.