Set up ModSecurity 3 with OWASP Core Rule Set 4.0 to protect web applications from SQL injection, XSS, and other attacks. Configure integration with Nginx and Apache, implement custom rules, and optimize performance for production environments.
Prerequisites
- Root or sudo access
- Web server (Nginx or Apache) installed
- Basic understanding of web server configuration
- At least 2GB RAM for compilation
What this solves
ModSecurity 3 is an open-source web application firewall (WAF) that protects your web applications from common attacks like SQL injection, cross-site scripting (XSS), and remote file inclusion. Combined with the OWASP Core Rule Set (CRS), it provides enterprise-grade threat detection and blocking capabilities. This tutorial shows you how to install ModSecurity 3, configure it with OWASP CRS 4.0, integrate it with popular web servers, and optimize performance for production use.
Step-by-step installation
Update system packages
Start by updating your package manager to ensure you get the latest security patches and dependencies.
sudo apt update && sudo apt upgrade -y
Install build dependencies
Install the required development tools and libraries needed to compile ModSecurity 3 from source.
sudo apt install -y build-essential git cmake libpcre2-dev libxml2-dev libcurl4-openssl-dev libyajl-dev libgeoip-dev liblua5.3-dev libfuzzy-dev libpcre3-dev zlib1g-dev
Download and compile ModSecurity 3
Clone the ModSecurity repository and compile the library with optimizations enabled for production use.
cd /opt
sudo git clone --depth 1 -b v3.0.12 https://github.com/owasp-modsecurity/ModSecurity.git
cd ModSecurity
sudo git submodule init
sudo git submodule update
sudo ./build.sh
sudo ./configure --with-pcre2 --with-yajl --with-geoip --with-lua --enable-parser-generation
sudo make -j$(nproc)
sudo make install
Configure library path
Add ModSecurity libraries to the system library path so web servers can find them at runtime.
echo '/usr/local/modsecurity/lib' | sudo tee /etc/ld.so.conf.d/modsecurity.conf
sudo ldconfig
Download OWASP Core Rule Set
Download the latest OWASP CRS 4.0 which provides comprehensive protection rules against common web attacks.
cd /opt
sudo wget https://github.com/coreruleset/coreruleset/archive/v4.0.0.tar.gz
sudo tar -xzf v4.0.0.tar.gz
sudo mv coreruleset-4.0.0 /etc/modsecurity
sudo chown -R root:root /etc/modsecurity
sudo chmod -R 755 /etc/modsecurity
Create ModSecurity configuration
Set up the main ModSecurity configuration with logging, audit settings, and security policies.
# ModSecurity Configuration
SecRuleEngine On
SecRequestBodyAccess On
SecRule REQUEST_HEADERS:Content-Type "^(?:application(?:/soap\+|/)|text/)xml" "id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"
SecRule REQUEST_HEADERS:Content-Type "^application/json" "id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON"
SecRequestBodyLimit 13107200
SecRequestBodyNoFilesLimit 131072
SecRequestBodyInMemoryLimit 131072
SecRequestBodyLimitAction Reject
SecRule REQBODY_ERROR "!@eq 0" "id:'200002', phase:2,t:none,log,deny,status:400,msg:'Failed to parse request body.',logdata:'Error %{reqbody_error_msg}',severity:2"
SecRule MULTIPART_STRICT_ERROR "!@eq 0" "id:'200003',phase:2,t:none,log,deny,status:400, msg:'Multipart request body failed strict validation'"
SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" "id:'200004',phase:2,t:none,log,deny,status:44"
SecRule TX:/^MSC_/ "!@streq 0" "id:'200005',phase:2,t:none,deny,msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'"
SecResponseBodyAccess On
SecResponseBodyMimeType text/plain text/html text/xml
SecResponseBodyLimit 524288
SecResponseBodyLimitAction ProcessPartial
SecTmpDir /tmp/
SecDataDir /tmp/
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
SecAuditLogParts ABIJDEFHZ
SecAuditLogType Serial
SecAuditLog /var/log/modsecurity/audit.log
SecArgumentSeparator &
SecCookieFormat 0
SecUnicodeMapFile unicode.mapping 20127
SecStatusEngine On
Configure OWASP Core Rule Set
Create the CRS setup configuration with custom settings for your environment and security requirements.
# OWASP CRS 4.0 Setup Configuration
Include /etc/modsecurity/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example
SecDefaultAction "phase:1,log,auditlog,pass"
SecDefaultAction "phase:2,log,auditlog,pass"
SecAction "id:900000,phase:1,nolog,pass,t:none,setvar:tx.paranoia_level=1"
SecAction "id:900001,phase:1,nolog,pass,t:none,setvar:tx.executing_paranoia_level=1"
SecAction "id:900010,phase:1,nolog,pass,t:none,setvar:tx.inbound_anomaly_score_threshold=5"
SecAction "id:900011,phase:1,nolog,pass,t:none,setvar:tx.outbound_anomaly_score_threshold=4"
SecAction "id:900020,phase:1,nolog,pass,t:none,setvar:tx.allowed_methods=GET HEAD POST OPTIONS"
SecAction "id:900021,phase:1,nolog,pass,t:none,setvar:tx.allowed_request_content_type=|application/x-www-form-urlencoded| |multipart/form-data| |text/xml| |application/xml| |application/soap+xml| |application/x-amf| |application/json| |application/octet-stream| |application/csp-report| |application/xss-auditor-report| |text/plain|"
SecAction "id:900022,phase:1,nolog,pass,t:none,setvar:tx.allowed_http_versions=HTTP/1.0 HTTP/1.1 HTTP/2 HTTP/2.0"
SecAction "id:900023,phase:1,nolog,pass,t:none,setvar:tx.restricted_extensions=.asa/ .asax/ .ascx/ .axd/ .backup/ .bak/ .bat/ .cdx/ .cer/ .cfg/ .cmd/ .com/ .config/ .conf/ .cs/ .csproj/ .csr/ .dat/ .db/ .dbf/ .dll/ .dos/ .htr/ .htw/ .ida/ .idc/ .idq/ .inc/ .ini/ .key/ .licx/ .lnk/ .log/ .mdb/ .old/ .pass/ .pdb/ .pol/ .printer/ .pwd/ .resources/ .resx/ .sql/ .sys/ .vb/ .vbs/ .vbproj/ .vsdisco/ .webinfo/ .xsd/ .xsx/"
SecAction "id:900024,phase:1,nolog,pass,t:none,setvar:tx.restricted_headers=/proxy-connection/ /lock-token/ /content-range/ /translate/ /if/"
SecAction "id:900030,phase:1,nolog,pass,t:none,setvar:tx.crs_validate_utf8_encoding=1"
SecAction "id:900031,phase:1,nolog,pass,t:none,setvar:tx.arg_name_length=100"
SecAction "id:900032,phase:1,nolog,pass,t:none,setvar:tx.arg_length=400"
SecAction "id:900033,phase:1,nolog,pass,t:none,setvar:tx.total_arg_length=64000"
SecAction "id:900034,phase:1,nolog,pass,t:none,setvar:tx.max_num_args=255"
Create log directory
Set up the directory structure for ModSecurity logs with appropriate permissions for the web server.
sudo mkdir -p /var/log/modsecurity
sudo chown www-data:www-data /var/log/modsecurity
sudo chmod 755 /var/log/modsecurity
Nginx integration
Compile Nginx ModSecurity connector
Download and compile the Nginx connector module that enables ModSecurity integration with Nginx.
cd /opt
sudo git clone --depth 1 https://github.com/owasp-modsecurity/ModSecurity-nginx.git
Recompile Nginx with ModSecurity module
Get Nginx source and recompile it with the ModSecurity module enabled for dynamic loading.
sudo apt install -y nginx-dev
nginx_version=$(nginx -v 2>&1 | grep -o '[0-9.]\+')
cd /opt
sudo wget http://nginx.org/download/nginx-${nginx_version}.tar.gz
sudo tar -xzf nginx-${nginx_version}.tar.gz
cd nginx-${nginx_version}
sudo ./configure --with-compat --add-dynamic-module=../ModSecurity-nginx
sudo make modules
sudo cp objs/ngx_http_modsecurity_module.so /usr/lib/nginx/modules/
Configure Nginx with ModSecurity
Update the Nginx configuration to load the ModSecurity module and enable WAF protection on your sites. This configuration builds on standard Nginx reverse proxy setups with additional security layers.
load_module modules/ngx_http_modsecurity_module.so;
user www-data;
worker_processes auto;
pid /run/nginx.pid;
error_log /var/log/nginx/error.log;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# ModSecurity
modsecurity on;
modsecurity_rules_file /etc/nginx/modsecurity.conf;
# Logging
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
# Basic settings
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Create Nginx ModSecurity rules file
Create the main rules file that Nginx will use to load ModSecurity configuration and OWASP CRS rules.
# Include ModSecurity configuration
Include /etc/modsecurity/modsecurity.conf
Include OWASP CRS setup
Include /etc/modsecurity/crs-setup.conf
Include OWASP CRS rules
Include /etc/modsecurity/rules/*.conf
Create symbolic links for CRS rules
Set up the rules directory structure and link the OWASP CRS rule files for easy management.
sudo mkdir -p /etc/modsecurity/rules
sudo ln -sf /etc/modsecurity/rules/*.conf /etc/modsecurity/rules/
for rule in /etc/modsecurity/rules/REQUEST-9*.conf; do
sudo ln -sf "$rule" /etc/modsecurity/rules/
done
for rule in /etc/modsecurity/rules/RESPONSE-9*.conf; do
sudo ln -sf "$rule" /etc/modsecurity/rules/
done
Apache integration
Install Apache ModSecurity module
For Apache integration, compile the mod_security2 module from source for optimal compatibility with ModSecurity 3.
sudo apt install -y apache2-dev
cd /opt
sudo git clone --depth 1 https://github.com/owasp-modsecurity/ModSecurity-apache.git
cd ModSecurity-apache
sudo ./autogen.sh
sudo ./configure --with-libmodsecurity=/usr/local/modsecurity/
sudo make
sudo make install
Enable ModSecurity in Apache
Create Apache configuration to load and enable ModSecurity with OWASP CRS rules. This works alongside existing Apache virtual host configurations.
LoadModule security3_module /usr/lib/apache2/modules/mod_security3.so
# Enable ModSecurity
modsecurity On
# Include rules
modsecurity_rules_file /etc/modsecurity/apache-modsecurity.conf
# Logging
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\" %D" modsec
CustomLog /var/log/apache2/modsec_audit.log modsec
Create Apache rules configuration
Set up the Apache-specific rules file that includes all ModSecurity and OWASP CRS configurations.
# Include ModSecurity configuration
Include /etc/modsecurity/modsecurity.conf
Include OWASP CRS setup
Include /etc/modsecurity/crs-setup.conf
Include OWASP CRS rules
Include /etc/modsecurity/rules/REQUEST-901-INITIALIZATION.conf
Include /etc/modsecurity/rules/REQUEST-903-IP-REPUTATION.conf
Include /etc/modsecurity/rules/REQUEST-905-COMMON-EXCEPTIONS.conf
Include /etc/modsecurity/rules/REQUEST-910-IP-REPUTATION.conf
Include /etc/modsecurity/rules/REQUEST-911-METHOD-ENFORCEMENT.conf
Include /etc/modsecurity/rules/REQUEST-912-DOS-PROTECTION.conf
Include /etc/modsecurity/rules/REQUEST-913-SCANNER-DETECTION.conf
Include /etc/modsecurity/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf
Include /etc/modsecurity/rules/REQUEST-921-PROTOCOL-ATTACK.conf
Include /etc/modsecurity/rules/REQUEST-930-APPLICATION-ATTACK-LFI.conf
Include /etc/modsecurity/rules/REQUEST-931-APPLICATION-ATTACK-RFI.conf
Include /etc/modsecurity/rules/REQUEST-932-APPLICATION-ATTACK-RCE.conf
Include /etc/modsecurity/rules/REQUEST-933-APPLICATION-ATTACK-PHP.conf
Include /etc/modsecurity/rules/REQUEST-934-APPLICATION-ATTACK-NODEJS.conf
Include /etc/modsecurity/rules/REQUEST-941-APPLICATION-ATTACK-XSS.conf
Include /etc/modsecurity/rules/REQUEST-942-APPLICATION-ATTACK-SQLI.conf
Include /etc/modsecurity/rules/REQUEST-943-APPLICATION-ATTACK-SESSION-FIXATION.conf
Include /etc/modsecurity/rules/REQUEST-944-APPLICATION-ATTACK-JAVA.conf
Include /etc/modsecurity/rules/REQUEST-949-BLOCKING-EVALUATION.conf
Include /etc/modsecurity/rules/RESPONSE-950-DATA-LEAKAGES.conf
Include /etc/modsecurity/rules/RESPONSE-951-DATA-LEAKAGES-SQL.conf
Include /etc/modsecurity/rules/RESPONSE-952-DATA-LEAKAGES-JAVA.conf
Include /etc/modsecurity/rules/RESPONSE-953-DATA-LEAKAGES-PHP.conf
Include /etc/modsecurity/rules/RESPONSE-954-DATA-LEAKAGES-IIS.conf
Include /etc/modsecurity/rules/RESPONSE-959-BLOCKING-EVALUATION.conf
Include /etc/modsecurity/rules/RESPONSE-980-CORRELATION.conf
Enable the module
Activate ModSecurity in Apache and restart the web server to apply the configuration.
sudo a2enmod modsecurity
sudo systemctl restart apache2
sudo systemctl status apache2
Custom rules and whitelisting
Create custom rules file
Set up a custom rules file for application-specific security rules and exceptions that don't fit the standard OWASP CRS.
# Custom ModSecurity Rules
Block common attack patterns
SecRule REQUEST_URI "@detectSQLi" \
"id:1001,\
phase:2,\
block,\
msg:'SQL Injection Attack Detected',\
logdata:'Matched Data: %{MATCHED_VAR} found within %{MATCHED_VAR_NAME}',\
tag:'attack-sqli',\
severity:2"
Block XSS attempts
SecRule ARGS "@detectXSS" \
"id:1002,\
phase:2,\
block,\
msg:'XSS Attack Detected',\
logdata:'Matched Data: %{MATCHED_VAR} found within %{MATCHED_VAR_NAME}',\
tag:'attack-xss',\
severity:2"
Rate limiting per IP
SecRule IP:RATE_LIMITED "@eq 1" \
"id:1003,\
phase:1,\
deny,\
status:429,\
msg:'Rate limit exceeded',\
expirevar:ip.rate_limited=60"
SecRule REQUEST_HEADERS:User-Agent "@streq \"\"" \
"id:1004,\
phase:1,\
deny,\
msg:'Empty User-Agent blocked'"
Geographic IP blocking (example)
SecGeoLookupDB /etc/modsecurity/GeoLite2-Country.mmdb
SecRule GEO:COUNTRY_CODE "@streq CN" \
"id:1005,\
phase:1,\
deny,\
msg:'Access denied from country'"
Create whitelist exceptions
Configure rule exceptions for legitimate application functionality that might trigger false positives.
# ModSecurity Whitelist Rules - Application Exceptions
Allow legitimate admin panel access
SecRule REQUEST_URI "@beginsWith /admin" \
"id:2001,\
phase:1,\
pass,\
ctl:ruleRemoveTargetById=942100;ARGS:query,\
ctl:ruleRemoveTargetById=941160;ARGS:content"
API endpoint exceptions
SecRule REQUEST_URI "@beginsWith /api/v1" \
"id:2002,\
phase:1,\
pass,\
ctl:ruleRemoveById=920230,\
msg:'API endpoint - relax protocol enforcement'"
Upload functionality exceptions
SecRule REQUEST_URI "@beginsWith /upload" \
"id:2003,\
phase:1,\
pass,\
ctl:ruleRemoveTargetById=200003;FILES,\
msg:'File upload - allow multipart'"
CMS-specific exceptions (WordPress example)
SecRule REQUEST_URI "@beginsWith /wp-admin" \
"id:2004,\
phase:1,\
pass,\
ctl:ruleRemoveTargetById=931130;ARGS:action,\
ctl:ruleRemoveTargetById=942100;ARGS:post_content"
Search functionality exceptions
SecRule ARGS:search "@unconditionalMatch" \
"id:2005,\
phase:1,\
pass,\
ctl:ruleRemoveTargetById=942100;ARGS:search,\
msg:'Search query - allow SQL-like syntax'"
Include custom rules in configuration
Update your main ModSecurity configuration to include the custom rules and whitelist exceptions.
echo "Include /etc/modsecurity/custom-rules.conf" | sudo tee -a /etc/nginx/modsecurity.conf
echo "Include /etc/modsecurity/whitelist-rules.conf" | sudo tee -a /etc/nginx/modsecurity.conf
Logging and monitoring configuration
Configure advanced logging
Set up structured logging with JSON format for better integration with log analysis tools and SIEM systems.
# Advanced ModSecurity Logging Configuration
JSON format audit log
SecAuditLogFormat JSON
SecAuditLogStorageDir /var/log/modsecurity/
SecAuditLogFileMode 0644
SecAuditLogDirMode 0755
Detailed audit log parts
SecAuditLogParts ABCDEFGHIJKZ
Error log configuration
SecDebugLog /var/log/modsecurity/debug.log
SecDebugLogLevel 3
Performance logging
SecRule RESPONSE_STATUS "@ge 200" \
"id:9001,\
phase:5,\
pass,\
nolog,\
setvar:tx.perf_modsecrules=%{PERF_RULES},\
setvar:tx.perf_modseccombined=%{PERF_COMBINED}"
Alert on high processing time
SecRule TX:PERF_COMBINED "@gt 1000" \
"id:9002,\
phase:5,\
pass,\
log,\
msg:'ModSecurity processing time exceeded threshold: %{tx.perf_combined}ms'"
Set up log rotation
Configure logrotate to manage ModSecurity log files and prevent disk space issues in production.
/var/log/modsecurity/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 644 www-data www-data
postrotate
/bin/systemctl reload nginx > /dev/null 2>&1 || true
endscript
}
/var/log/modsecurity/audit.log {
daily
missingok
rotate 7
compress
delaycompress
notifempty
create 644 www-data www-data
size 100M
postrotate
/bin/systemctl reload nginx > /dev/null 2>&1 || true
endscript
}
Create monitoring script
Set up automated monitoring to track ModSecurity performance and alert on security events. This complements broader security monitoring setups.
#!/bin/bash
ModSecurity Monitoring Script
LOG_FILE="/var/log/modsecurity/audit.log"
ALERT_EMAIL="admin@example.com"
TEMP_DIR="/tmp/modsec-monitor"
Create temp directory
mkdir -p "$TEMP_DIR"
Get current timestamp
CURRENT_TIME=$(date +"%Y-%m-%d %H:%M:%S")
LAST_HOUR=$(date -d '1 hour ago' +"%Y-%m-%d %H:%M:%S")
Count attacks in last hour
if [ -f "$LOG_FILE" ]; then
ATTACK_COUNT=$(grep -c "severity" "$LOG_FILE" | tail -1000 | wc -l)
SQL_INJECTION=$(grep -c "attack-sqli" "$LOG_FILE" | tail -100 | wc -l)
XSS_ATTACKS=$(grep -c "attack-xss" "$LOG_FILE" | tail -100 | wc -l)
# Alert on high attack volume
if [ "$ATTACK_COUNT" -gt 50 ]; then
echo "High ModSecurity alert volume: $ATTACK_COUNT attacks detected" | \
mail -s "ModSecurity Alert - High Attack Volume" "$ALERT_EMAIL"
fi
# Generate daily report
if [ "$(date +%H)" = "06" ]; then
echo "ModSecurity Daily Report - $CURRENT_TIME
Total Attacks: $ATTACK_COUNT
SQL Injection: $SQL_INJECTION
XSS Attempts: $XSS_ATTACKS" | \
mail -s "ModSecurity Daily Report" "$ALERT_EMAIL"
fi
fi
Check ModSecurity performance
PROC_TIME=$(grep -o 'PERF_COMBINED=[0-9]*' "$LOG_FILE" 2>/dev/null | \
tail -100 | \
awk -F= '{sum+=$2; count++} END {if(count>0) print sum/count; else print 0}')
if (( $(echo "$PROC_TIME > 500" | bc -l) )); then
echo "ModSecurity performance warning: Average processing time ${PROC_TIME}ms" | \
mail -s "ModSecurity Performance Alert" "$ALERT_EMAIL"
fi
sudo chmod +x /usr/local/bin/modsec-monitor.sh
Schedule monitoring with cron
Set up regular monitoring checks to proactively detect security issues and performance problems.
echo "0 /usr/local/bin/modsec-monitor.sh" | sudo crontab -
Performance tuning and optimization
Configure performance optimizations
Optimize ModSecurity for production workloads by tuning memory usage, processing limits, and rule evaluation.
# ModSecurity Performance Configuration
Memory optimization
SecRequestBodyInMemoryLimit 65536
SecRequestBodyLimit 10485760
SecRequestBodyNoFilesLimit 65536
Processing optimization
SecRuleEngine On
SecRequestBodyAccess On
SecResponseBodyAccess Off # Disable for better performance
Sampling for high-traffic sites (inspect 10% of requests)
SecRule REQUEST_HEADERS:Host "@unconditionalMatch" \
"id:9100,\
phase:1,\
pass,\
nolog,\
skipAfter:END_SAMPLING,\
chain"
SecRule TX:SAMPLING_RND "!@eq 1" \
"setvar:tx.sampling_do_sample=0"
SecMarker END_SAMPLING
Skip rules for static content
SecRule REQUEST_FILENAME "@endsWith .jpg" \
"id:9101,phase:1,pass,nolog,ctl:ruleEngine=Off"
SecRule REQUEST_FILENAME "@endsWith .png" \
"id:9102,phase:1,pass,nolog,ctl:ruleEngine=Off"
SecRule REQUEST_FILENAME "@endsWith .gif" \
"id:9103,phase:1,pass,nolog,ctl:ruleEngine=Off"
SecRule REQUEST_FILENAME "@endsWith .css" \
"id:9104,phase:1,pass,nolog,ctl:ruleEngine=Off"
SecRule REQUEST_FILENAME "@endsWith .js" \
"id:9105,phase:1,pass,nolog,ctl:ruleEngine=Off"
Optimize collection timeouts
SecCollectionTimeout 600
Reduced paranoia level for performance
SecAction "id:9110,phase:1,nolog,pass,setvar:tx.paranoia_level=1"
Faster regex engine
SecRule REQUEST_URI "@unconditionalMatch" \
"id:9111,phase:1,pass,nolog,ctl:ruleEngine=DetectionOnly"
Connection pooling optimization
SecRule REMOTE_ADDR "@unconditionalMatch" \
"id:9112,phase:1,pass,nolog,initcol:ip=%{remote_addr},expirevar:ip.counter=300"
Configure rule set optimization
Selectively enable only the OWASP CRS rules needed for your application to reduce processing overhead.
# Optimized OWASP CRS Configuration
Core rules (always include)
Include /etc/modsecurity/rules/REQUEST-901-INITIALIZATION.conf
Include /etc/modsecurity/rules/REQUEST-905-COMMON-EXCEPTIONS.conf
Include /etc/modsecurity/rules/REQUEST-949-BLOCKING-EVALUATION.conf
Essential security rules
Include /etc/modsecurity/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf
Include /etc/modsecurity/rules/REQUEST-921-PROTOCOL-ATTACK.conf
Include /etc/modsecurity/rules/REQUEST-941-APPLICATION-ATTACK-XSS.conf
Include /etc/modsecurity/rules/REQUEST-942-APPLICATION-ATTACK-SQLI.conf
Optional rules - include only if needed
Include /etc/modsecurity/rules/REQUEST-913-SCANNER-DETECTION.conf
Include /etc/modsecurity/rules/REQUEST-930-APPLICATION-ATTACK-LFI.conf
Include /etc/modsecurity/rules/REQUEST-931-APPLICATION-ATTACK-RFI.conf
Include /etc/modsecurity/rules/REQUEST-932-APPLICATION-ATTACK-RCE.conf
Response analysis (disable for performance)
Include /etc/modsecurity/rules/RESPONSE-950-DATA-LEAKAGES.conf
Include /etc/modsecurity/rules/RESPONSE-951-DATA-LEAKAGES-SQL.conf
Correlation rules
Include /etc/modsecurity/rules/RESPONSE-980-CORRELATION.conf
Implement caching optimizations
Configure ModSecurity with caching strategies to improve performance on high-traffic websites.
# ModSecurity Caching Configuration
IP reputation cache
SecRule REMOTE_ADDR "@ipMatch 127.0.0.1,10.0.0.0/8,192.168.0.0/16,172.16.0.0/12" \
"id:9200,\
phase:1,\
pass,\
nolog,\
ctl:ruleEngine=Off,\
msg:'Internal IP - skip processing'"
User-Agent caching
SecRule REQUEST_HEADERS:User-Agent "@pmFromFile /etc/modsecurity/trusted-ua.txt" \
"id:9201,\
phase:1,\
pass,\
nolog,\
setvar:tx.trusted_bot=1"
Trusted bot bypass
SecRule TX:TRUSTED_BOT "@eq 1" \
"id:9202,\
phase:1,\
pass,\
nolog,\
ctl:ruleRemoveById=913100-913120"
Session-based caching
SecRule REQUEST_COOKIES:session_id "@unconditionalMatch" \
"id:9203,\
phase:1,\
pass,\
nolog,\
initcol:session=%{request_cookies.session_id},\
setvar:session.counter=+1"
Rate limiting with session awareness
SecRule SESSION:COUNTER "@gt 100" \
"id:9204,\
phase:1,\
deny,\
status:429,\
msg:'Session rate limit exceeded',\
expirevar:session.counter=300"
Create trusted user agents list
Set up a whitelist of trusted crawlers and monitoring tools to reduce false positives and processing overhead.
Googlebot
Bingbot
YandexBot
facebookexternalhit
Twitterbot
LinkedInBot
PinterestBot
Slackbot
WhatsApp
TelegramBot
UptimeRobot
StatusCake
Pingdom
Datadog Agent
New Relic
Nagios
Verify your setup
Test ModSecurity functionality
Verify that ModSecurity is properly blocking malicious requests and logging security events.
# Test SQL injection detection
curl -X GET "http://example.com/?id=1' OR '1'='1" -H "User-Agent: TestBot"
Test XSS detection
curl -X POST "http://example.com/search" -d "query=" -H "Content-Type: application/x-www-form-urlencoded"
Check ModSecurity status in web server
sudo nginx -t
sudo systemctl status nginx
Verify log file creation
sudo ls -la /var/log/modsecurity/
sudo tail -f /var/log/modsecurity/audit.log
Performance verification
Test the impact of ModSecurity on your web server performance and adjust settings as needed.
# Benchmark with and without ModSecurity
ab -n 1000 -c 10 http://example.com/
Check processing time in logs
grep -o 'PERF_COMBINED=[0-9]*' /var/log/modsecurity/audit.log | tail -20
Monitor system resources
top -p $(pgrep nginx)
htop
Security rule validation
Confirm that OWASP CRS rules are loading correctly and protecting against common attack vectors.
# Check loaded rules count
grep -c "SecRule" /etc/modsecurity/rules/*.conf
Validate configuration syntax
modsec-rules-check /etc/nginx/modsecurity.conf
Test specific attack patterns
echo "Testing SQL injection blocking..."
curl -v "http://example.com/login?user=admin'--&pass=any" 2>&1 | grep -E "(HTTP/|blocked)"
echo "Testing directory traversal blocking..."
curl -v "http://example.com/../../../etc/passwd" 2>&1 | grep -E "(HTTP/|blocked)"
echo "Testing command injection blocking..."
curl -v "http://example.com/cmd?exec=;cat /etc/passwd" 2>&1 | grep -E "(HTTP/|blocked)"
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Nginx fails to start | ModSecurity module not found | sudo nginx -t to check config, verify module path in load_module directive |
| 403 Forbidden on legitimate requests | OWASP CRS false positive | Check audit.log for rule ID, add whitelist exception in custom rules |
| High CPU usage | Too many rules or high paranoia level | Reduce paranoia level to 1, disable response body inspection, optimize rule set |
| Logs not created | Permission issues with log directory | sudo chown www-data:www-data /var/log/modsecurity and chmod 755 |
| Rules not loading | Incorrect file paths in configuration | Verify Include paths match actual file locations, check symbolic links |
| Memory errors | Request body limits too high | Adjust SecRequestBodyLimit and SecRequestBodyInMemoryLimit settings |
Next steps
- Configure advanced rate limiting and DDoS protection with Nginx
- Integrate Fail2ban with ModSecurity for automated IP blocking
- Set up ELK Stack for centralized ModSecurity log analysis
- Configure machine learning-based anomaly detection with ModSecurity
- Integrate ModSecurity with SOAR platforms for automated incident response
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Configuration
MODSEC_VERSION="v3.0.12"
CRS_VERSION="v4.0.0"
INSTALL_DIR="/opt"
CONFIG_DIR="/etc/modsecurity"
LOG_DIR="/var/log/modsecurity"
usage() {
echo "Usage: $0 [OPTIONS]"
echo "Options:"
echo " -w, --webserver WEBSERVER Web server to configure (nginx|apache2) [optional]"
echo " -h, --help Show this help message"
echo ""
echo "Example: $0 --webserver nginx"
}
cleanup() {
if [[ $? -ne 0 ]]; then
echo -e "${RED}[ERROR] Installation failed. Cleaning up...${NC}"
sudo rm -rf ${INSTALL_DIR}/ModSecurity 2>/dev/null || true
sudo rm -rf ${CONFIG_DIR} 2>/dev/null || true
sudo rm -f /etc/ld.so.conf.d/modsecurity.conf 2>/dev/null || true
sudo ldconfig 2>/dev/null || true
fi
}
trap cleanup ERR
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
check_prerequisites() {
if [[ $EUID -eq 0 ]]; then
log_error "This script should not be run as root. Use sudo when needed."
exit 1
fi
if ! command -v sudo >/dev/null 2>&1; then
log_error "sudo is required but not installed."
exit 1
fi
if ! sudo -n true 2>/dev/null; then
log_error "This script requires sudo privileges."
exit 1
fi
}
detect_distro() {
if [[ ! -f /etc/os-release ]]; then
log_error "Cannot detect distribution. /etc/os-release not found."
exit 1
fi
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="apt update && apt upgrade -y"
PKG_INSTALL="apt install -y"
BUILD_DEPS="build-essential git cmake libpcre2-dev libxml2-dev libcurl4-openssl-dev libyajl-dev libgeoip-dev liblua5.3-dev libfuzzy-dev libpcre3-dev zlib1g-dev"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
BUILD_DEPS="git cmake pcre2-devel libxml2-devel libcurl-devel yajl-devel GeoIP-devel lua-devel ssdeep-devel pcre-devel zlib-devel"
DEVTOOLS="dnf groupinstall -y \"Development Tools\""
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum update -y"
PKG_INSTALL="yum install -y"
BUILD_DEPS="git cmake pcre2-devel libxml2-devel libcurl-devel yajl-devel GeoIP-devel lua-devel ssdeep-devel pcre-devel zlib-devel"
DEVTOOLS="yum groupinstall -y \"Development Tools\""
;;
*)
log_error "Unsupported distribution: $ID"
exit 1
;;
esac
log_info "Detected distribution: $PRETTY_NAME"
}
parse_args() {
WEBSERVER=""
while [[ $# -gt 0 ]]; do
case $1 in
-w|--webserver)
WEBSERVER="$2"
if [[ "$WEBSERVER" != "nginx" && "$WEBSERVER" != "apache2" ]]; then
log_error "Unsupported web server: $WEBSERVER"
usage
exit 1
fi
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
log_error "Unknown option: $1"
usage
exit 1
;;
esac
done
}
update_system() {
log_info "[1/8] Updating system packages..."
sudo bash -c "$PKG_UPDATE"
}
install_dependencies() {
log_info "[2/8] Installing build dependencies..."
if [[ -n "${DEVTOOLS:-}" ]]; then
sudo bash -c "$DEVTOOLS"
fi
sudo $PKG_INSTALL $BUILD_DEPS
}
compile_modsecurity() {
log_info "[3/8] Downloading and compiling ModSecurity 3..."
cd $INSTALL_DIR
sudo git clone --depth 1 -b $MODSEC_VERSION https://github.com/owasp-modsecurity/ModSecurity.git
cd ModSecurity
sudo git submodule init
sudo git submodule update
sudo ./build.sh
sudo ./configure --with-pcre2 --with-yajl --with-geoip --with-lua --enable-parser-generation
sudo make -j$(nproc)
sudo make install
}
configure_library_path() {
log_info "[4/8] Configuring library path..."
echo '/usr/local/modsecurity/lib' | sudo tee /etc/ld.so.conf.d/modsecurity.conf >/dev/null
sudo ldconfig
}
download_owasp_crs() {
log_info "[5/8] Downloading OWASP Core Rule Set..."
cd $INSTALL_DIR
sudo wget -O crs.tar.gz "https://github.com/coreruleset/coreruleset/archive/${CRS_VERSION}.tar.gz"
sudo tar -xzf crs.tar.gz
sudo rm -f crs.tar.gz
CRS_DIR=$(sudo find . -name "coreruleset-*" -type d | head -1)
sudo mkdir -p $CONFIG_DIR
sudo mv "$CRS_DIR"/* $CONFIG_DIR/
sudo rmdir "$CRS_DIR"
sudo chown -R root:root $CONFIG_DIR
sudo find $CONFIG_DIR -type d -exec chmod 755 {} \;
sudo find $CONFIG_DIR -type f -exec chmod 644 {} \;
}
create_modsecurity_config() {
log_info "[6/8] Creating ModSecurity configuration..."
sudo mkdir -p $LOG_DIR
sudo chmod 755 $LOG_DIR
sudo tee ${CONFIG_DIR}/modsecurity.conf >/dev/null <<'EOF'
SecRuleEngine On
SecRequestBodyAccess On
SecRule REQUEST_HEADERS:Content-Type "^(?:application(?:/soap\+|/)|text/)xml" "id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"
SecRule REQUEST_HEADERS:Content-Type "^application/json" "id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON"
SecRequestBodyLimit 13107200
SecRequestBodyNoFilesLimit 131072
SecRequestBodyInMemoryLimit 131072
SecRequestBodyLimitAction Reject
SecResponseBodyAccess On
SecResponseBodyMimeType text/plain text/html text/xml
SecResponseBodyLimit 524288
SecResponseBodyLimitAction ProcessPartial
SecTmpDir /tmp/
SecDataDir /tmp/
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
SecAuditLogParts ABIJDEFHZ
SecAuditLogType Serial
SecAuditLog /var/log/modsecurity/audit.log
SecArgumentSeparator &
SecCookieFormat 0
SecStatusEngine On
EOF
sudo chmod 644 ${CONFIG_DIR}/modsecurity.conf
}
configure_owasp_crs() {
log_info "[7/8] Configuring OWASP Core Rule Set..."
sudo cp ${CONFIG_DIR}/crs-setup.conf.example ${CONFIG_DIR}/crs-setup.conf
sudo tee ${CONFIG_DIR}/main.conf >/dev/null <<EOF
Include ${CONFIG_DIR}/modsecurity.conf
Include ${CONFIG_DIR}/crs-setup.conf
Include ${CONFIG_DIR}/rules/*.conf
EOF
sudo chmod 644 ${CONFIG_DIR}/crs-setup.conf ${CONFIG_DIR}/main.conf
}
verify_installation() {
log_info "[8/8] Verifying installation..."
# Check if ModSecurity library exists
if [[ ! -f /usr/local/modsecurity/lib/libmodsecurity.so ]]; then
log_error "ModSecurity library not found"
exit 1
fi
# Check if configuration files exist
if [[ ! -f ${CONFIG_DIR}/main.conf ]]; then
log_error "ModSecurity configuration not found"
exit 1
fi
# Check if CRS rules exist
if [[ ! -d ${CONFIG_DIR}/rules ]]; then
log_error "OWASP CRS rules not found"
exit 1
fi
# Check library path
if ! ldconfig -p | grep -q modsecurity; then
log_error "ModSecurity library not in system path"
exit 1
fi
log_info "ModSecurity 3 with OWASP CRS installation completed successfully!"
echo ""
echo -e "${GREEN}Next steps:${NC}"
echo "1. Configure your web server to use ModSecurity"
echo "2. Test the configuration with: nginx -t (for Nginx) or apache2ctl configtest (for Apache)"
echo "3. Monitor logs in: $LOG_DIR"
echo "4. Customize rules in: ${CONFIG_DIR}/crs-setup.conf"
if [[ -n "$WEBSERVER" ]]; then
log_warn "Web server integration for $WEBSERVER requires manual configuration"
log_warn "Please refer to the ModSecurity documentation for $WEBSERVER integration"
fi
}
main() {
echo -e "${GREEN}ModSecurity 3 with OWASP CRS Installation Script${NC}"
echo "================================================"
echo ""
check_prerequisites
detect_distro
parse_args "$@"
update_system
install_dependencies
compile_modsecurity
configure_library_path
download_owasp_crs
create_modsecurity_config
configure_owasp_crs
verify_installation
}
main "$@"
Review the script before running. Execute with: bash install.sh