Deploy ModSecurity 3 as an Apache module with OWASP Core Rule Set to protect web applications from common attacks. Configure real-time logging, custom rules, and automated threat detection for production environments.
Prerequisites
- Apache HTTP server
- Root or sudo access
- Basic knowledge of web server configuration
What this solves
ModSecurity 3 provides web application firewall (WAF) capabilities that protect your applications from SQL injection, cross-site scripting (XSS), and other OWASP Top 10 vulnerabilities. This tutorial sets up ModSecurity with Apache and deploys the OWASP Core Rule Set for comprehensive threat detection and blocking.
Step-by-step installation
Update system packages
Start by updating your package manager to ensure you have the latest security updates.
sudo apt update && sudo apt upgrade -y
sudo dnf update -y
Install Apache and development tools
Install Apache web server and the development tools required for building ModSecurity.
sudo apt install -y apache2 apache2-dev build-essential git libcurl4-openssl-dev libgeoip-dev libyajl-dev libpcre2-dev libxml2-dev pkgconf libmaxminddb-dev
sudo dnf install -y httpd httpd-devel gcc gcc-c++ git libcurl-devel GeoIP-devel yajl-devel pcre2-devel libxml2-devel pkgconfig libmaxminddb-devel
Download and compile libmodsecurity
Clone the ModSecurity v3 library source code and compile it with optimizations for production use.
cd /opt
sudo git clone --depth 1 -b v3/master --single-branch https://github.com/SpiderLabs/ModSecurity.git
cd ModSecurity
sudo git submodule init
sudo git submodule update
sudo ./build.sh
sudo ./configure --with-yajl --with-geoip --with-pcre2
sudo make -j$(nproc)
sudo make install
Download and compile ModSecurity Apache connector
Install the connector that integrates ModSecurity library with Apache HTTP server.
cd /opt
sudo git clone --depth 1 https://github.com/SpiderLabs/ModSecurity-apache.git
cd ModSecurity-apache
sudo ./configure --with-libmodsecurity=/usr/local/modsecurity/
sudo make -j$(nproc)
sudo make install
Configure dynamic library loading
Update the library path so Apache can find the ModSecurity libraries at runtime.
echo '/usr/local/modsecurity/lib' | sudo tee /etc/ld.so.conf.d/modsecurity.conf
sudo ldconfig
Load ModSecurity Apache module
Enable the ModSecurity module in Apache configuration.
echo 'LoadModule security3_module /usr/lib/apache2/modules/mod_security3.so' | sudo tee /etc/apache2/mods-available/security3.load
sudo a2enmod security3
echo 'LoadModule security3_module modules/mod_security3.so' | sudo tee /etc/httpd/conf.modules.d/00-security3.conf
Create ModSecurity configuration directory
Set up the directory structure for ModSecurity configuration files with proper permissions.
sudo mkdir -p /etc/apache2/modsecurity.d
sudo chown root:root /etc/apache2/modsecurity.d
sudo chmod 755 /etc/apache2/modsecurity.d
sudo mkdir -p /etc/httpd/modsecurity.d
sudo chown root:root /etc/httpd/modsecurity.d
sudo chmod 755 /etc/httpd/modsecurity.d
Download OWASP Core Rule Set
Clone the latest OWASP Core Rule Set which contains rules for detecting common web application attacks.
cd /etc/apache2/modsecurity.d
sudo git clone https://github.com/coreruleset/coreruleset.git
sudo mv coreruleset/crs-setup.conf.example coreruleset/crs-setup.conf
cd /etc/httpd/modsecurity.d
sudo git clone https://github.com/coreruleset/coreruleset.git
sudo mv coreruleset/crs-setup.conf.example coreruleset/crs-setup.conf
Create main ModSecurity configuration
Configure ModSecurity with logging, rule processing, and security settings optimized for production.
# ModSecurity v3 Configuration
SecRuleEngine On
SecRequestBodyAccess On
SecRule REQUEST_HEADERS:Content-Type "^(?:application(?:/soap\+|/)|text/)xml" \n "id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"
SecRule REQUEST_HEADERS:Content-Type "^application/json" \n "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" \n"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" \n"id:200003,phase:2,t:none,log,deny,status:400, \nmsg:'Multipart request body failed strict validation: \nPE %{REQBODY_PROCESSOR_ERROR}, \nBQ %{MULTIPART_BOUNDARY_QUOTED}, \nBW %{MULTIPART_BOUNDARY_WHITESPACE}, \nDB %{MULTIPART_DATA_BEFORE}, \nDA %{MULTIPART_DATA_AFTER}, \nHF %{MULTIPART_HEADER_FOLDING}, \nLF %{MULTIPART_LF_LINE}, \nSM %{MULTIPART_MISSING_SEMICOLON}, \nIQ %{MULTIPART_INVALID_QUOTING}, \nIP %{MULTIPART_INVALID_PART}, \nIH %{MULTIPART_INVALID_HEADER_FOLDING}, \nFL %{MULTIPART_FILE_LIMIT_EXCEEDED}'"
SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" \n"id:200004,phase:2,t:none,log,deny,status:44,msg:'Multipart parser detected a possible unmatched boundary.'"
SecPcreMatchLimit 1000
SecPcreMatchLimitRecursion 1000
SecResponseBodyAccess On
SecResponseBodyMimeType text/plain text/html text/xml
SecResponseBodyLimit 524288
SecResponseBodyLimitAction ProcessPartial
SecTmpDir /tmp/
SecDataDir /tmp/
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
SecAuditLogParts ABDEFHIJZ
SecAuditLogType Serial
SecAuditLog /var/log/apache2/modsec_audit.log
SecArgumentSeparator &
SecCookieFormat 0
SecUnicodeMapFile unicode.mapping 20127
SecStatusEngine On
# ModSecurity v3 Configuration
SecRuleEngine On
SecRequestBodyAccess On
SecRule REQUEST_HEADERS:Content-Type "^(?:application(?:/soap\+|/)|text/)xml" \n "id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"
SecRule REQUEST_HEADERS:Content-Type "^application/json" \n "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" \n"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" \n"id:200003,phase:2,t:none,log,deny,status:400, \nmsg:'Multipart request body failed strict validation: \nPE %{REQBODY_PROCESSOR_ERROR}, \nBQ %{MULTIPART_BOUNDARY_QUOTED}, \nBW %{MULTIPART_BOUNDARY_WHITESPACE}, \nDB %{MULTIPART_DATA_BEFORE}, \nDA %{MULTIPART_DATA_AFTER}, \nHF %{MULTIPART_HEADER_FOLDING}, \nLF %{MULTIPART_LF_LINE}, \nSM %{MULTIPART_MISSING_SEMICOLON}, \nIQ %{MULTIPART_INVALID_QUOTING}, \nIP %{MULTIPART_INVALID_PART}, \nIH %{MULTIPART_INVALID_HEADER_FOLDING}, \nFL %{MULTIPART_FILE_LIMIT_EXCEEDED}'"
SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" \n"id:200004,phase:2,t:none,log,deny,status:44,msg:'Multipart parser detected a possible unmatched boundary.'"
SecPcreMatchLimit 1000
SecPcreMatchLimitRecursion 1000
SecResponseBodyAccess On
SecResponseBodyMimeType text/plain text/html text/xml
SecResponseBodyLimit 524288
SecResponseBodyLimitAction ProcessPartial
SecTmpDir /tmp/
SecDataDir /tmp/
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
SecAuditLogParts ABDEFHIJZ
SecAuditLogType Serial
SecAuditLog /var/log/httpd/modsec_audit.log
SecArgumentSeparator &
SecCookieFormat 0
SecUnicodeMapFile unicode.mapping 20127
SecStatusEngine On
Create custom rules file
Set up a custom rules file for application-specific security rules and exceptions.
# Custom ModSecurity Rules
# Block requests with suspicious user agents
SecRule REQUEST_HEADERS:User-Agent "@contains sqlmap" \n "id:1001,phase:1,block,msg:'SQL injection tool detected',logdata:'Matched Data: %{MATCHED_VAR} found within %{MATCHED_VAR_NAME}',severity:2,tag:'attack-sqli',tag:'OWASP_CRS'"
# Rate limiting rule - max 100 requests per minute per IP
SecAction "id:1002,phase:1,initcol:ip=%{REMOTE_ADDR},pass,nolog"
SecRule IP:REQUEST_COUNT "@gt 100" \n "id:1003,phase:1,deny,status:429,msg:'Rate limit exceeded',logdata:'IP: %{REMOTE_ADDR}',setvar:ip.request_count=+1"
SecAction "id:1004,phase:5,pass,nolog,setvar:ip.request_count=+1,expirevar:ip.request_count=60"
# Block known bad IPs (example - customize for your needs)
SecRule REMOTE_ADDR "@ipMatch 198.51.100.0/24" \n "id:1005,phase:1,deny,status:403,msg:'Blocked IP range',logdata:'IP: %{REMOTE_ADDR}'"
# Enhanced logging for security events
SecRule TX:ANOMALY_SCORE "@gt 0" \n "id:1006,phase:5,pass,msg:'Inbound Anomaly Score Exceeded',logdata:'Total Score: %{TX.ANOMALY_SCORE}'"
# Whitelist legitimate traffic patterns (customize as needed)
SecRule REQUEST_URI "@beginsWith /api/health" \n "id:1007,phase:1,pass,ctl:ruleRemoveById=920350,msg:'Allow health check endpoint'"
# Block file upload to sensitive directories
SecRule FILES_NAMES "@rx \.(php|jsp|asp|aspx|sh|py|pl|rb)$" \n "id:1008,phase:2,deny,status:403,msg:'Executable file upload attempt',logdata:'File: %{MATCHED_VAR}'"
# Geographic IP filtering (requires GeoIP database)
# SecRule REMOTE_ADDR "@geoLookup" "id:1009,phase:1,pass,nolog,setvar:tx.country_code=%{GEO.COUNTRY_CODE}"
# SecRule TX:COUNTRY_CODE "@in CN RU" "id:1010,phase:1,deny,status:403,msg:'Blocked country'"
# Custom ModSecurity Rules
# Block requests with suspicious user agents
SecRule REQUEST_HEADERS:User-Agent "@contains sqlmap" \n "id:1001,phase:1,block,msg:'SQL injection tool detected',logdata:'Matched Data: %{MATCHED_VAR} found within %{MATCHED_VAR_NAME}',severity:2,tag:'attack-sqli',tag:'OWASP_CRS'"
# Rate limiting rule - max 100 requests per minute per IP
SecAction "id:1002,phase:1,initcol:ip=%{REMOTE_ADDR},pass,nolog"
SecRule IP:REQUEST_COUNT "@gt 100" \n "id:1003,phase:1,deny,status:429,msg:'Rate limit exceeded',logdata:'IP: %{REMOTE_ADDR}',setvar:ip.request_count=+1"
SecAction "id:1004,phase:5,pass,nolog,setvar:ip.request_count=+1,expirevar:ip.request_count=60"
# Block known bad IPs (example - customize for your needs)
SecRule REMOTE_ADDR "@ipMatch 198.51.100.0/24" \n "id:1005,phase:1,deny,status:403,msg:'Blocked IP range',logdata:'IP: %{REMOTE_ADDR}'"
# Enhanced logging for security events
SecRule TX:ANOMALY_SCORE "@gt 0" \n "id:1006,phase:5,pass,msg:'Inbound Anomaly Score Exceeded',logdata:'Total Score: %{TX.ANOMALY_SCORE}'"
# Whitelist legitimate traffic patterns (customize as needed)
SecRule REQUEST_URI "@beginsWith /api/health" \n "id:1007,phase:1,pass,ctl:ruleRemoveById=920350,msg:'Allow health check endpoint'"
# Block file upload to sensitive directories
SecRule FILES_NAMES "@rx \.(php|jsp|asp|aspx|sh|py|pl|rb)$" \n "id:1008,phase:2,deny,status:403,msg:'Executable file upload attempt',logdata:'File: %{MATCHED_VAR}'"
# Geographic IP filtering (requires GeoIP database)
# SecRule REMOTE_ADDR "@geoLookup" "id:1009,phase:1,pass,nolog,setvar:tx.country_code=%{GEO.COUNTRY_CODE}"
# SecRule TX:COUNTRY_CODE "@in CN RU" "id:1010,phase:1,deny,status:403,msg:'Blocked country'"
Configure Apache virtual host with ModSecurity
Enable ModSecurity for your website by adding directives to Apache virtual host configuration.
<VirtualHost *:80>
ServerAdmin webmaster@example.com
DocumentRoot /var/www/html
ServerName example.com
# ModSecurity Configuration
SecRuleEngine On
modsecurity_rules_file /etc/apache2/modsecurity.d/modsecurity.conf
modsecurity_rules_file /etc/apache2/modsecurity.d/coreruleset/crs-setup.conf
modsecurity_rules_file /etc/apache2/modsecurity.d/coreruleset/rules/*.conf
modsecurity_rules_file /etc/apache2/modsecurity.d/custom-rules.conf
# Security headers
Header always set X-Frame-Options DENY
Header always set X-Content-Type-Options nosniff
Header always set X-XSS-Protection "1; mode=block"
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Content-Security-Policy "default-src 'self'"
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
<VirtualHost *:80>
ServerAdmin webmaster@example.com
DocumentRoot /var/www/html
ServerName example.com
# ModSecurity Configuration
SecRuleEngine On
modsecurity_rules_file /etc/httpd/modsecurity.d/modsecurity.conf
modsecurity_rules_file /etc/httpd/modsecurity.d/coreruleset/crs-setup.conf
modsecurity_rules_file /etc/httpd/modsecurity.d/coreruleset/rules/*.conf
modsecurity_rules_file /etc/httpd/modsecurity.d/custom-rules.conf
# Security headers
Header always set X-Frame-Options DENY
Header always set X-Content-Type-Options nosniff
Header always set X-XSS-Protection "1; mode=block"
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Content-Security-Policy "default-src 'self'"
ErrorLog /var/log/httpd/error.log
CustomLog /var/log/httpd/access.log combined
</VirtualHost>
Enable required Apache modules
Enable Apache modules needed for security headers and ModSecurity functionality.
sudo a2enmod headers
sudo a2enmod rewrite
echo 'LoadModule headers_module modules/mod_headers.so' | sudo tee -a /etc/httpd/conf.modules.d/00-base.conf
echo 'LoadModule rewrite_module modules/mod_rewrite.so' | sudo tee -a /etc/httpd/conf.modules.d/00-base.conf
Set up log rotation for ModSecurity logs
Configure logrotate to manage ModSecurity audit logs and prevent disk space issues.
/var/log/apache2/modsec_audit.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
create 640 www-data adm
postrotate
/bin/systemctl reload apache2 > /dev/null 2>&1 || true
endscript
}
/var/log/httpd/modsec_audit.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
create 640 apache apache
postrotate
/bin/systemctl reload httpd > /dev/null 2>&1 || true
endscript
}
Create ModSecurity monitoring script
Set up a monitoring script that checks for blocked attacks and sends alerts.
#!/bin/bash
# ModSecurity Monitoring Script
LOG_FILE="/var/log/apache2/modsec_audit.log"
if [ -f "/var/log/httpd/modsec_audit.log" ]; then
LOG_FILE="/var/log/httpd/modsec_audit.log"
fi
ALERT_EMAIL="admin@example.com"
THRESHOLD=10
TIME_WINDOW=5
# Get current timestamp
CURRENT_TIME=$(date +%s)
START_TIME=$((CURRENT_TIME - (TIME_WINDOW * 60)))
# Count blocked requests in the last 5 minutes
BLOCKED_COUNT=$(awk -v start="$START_TIME" '
/^--[a-f0-9]+-A--/ {
getline;
date_line = $0;
if (match(date_line, /\[([0-9]{2}\/[A-Za-z]{3}\/[0-9]{4}:[0-9]{2}:[0-9]{2}:[0-9]{2})/, arr))Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# ModSecurity 3 + OWASP Core Rule Set Installation Script
# Supports Ubuntu/Debian and RHEL-based distributions
# Colors for output
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly NC='\033[0m'
# Global variables
PKG_MGR=""
PKG_INSTALL=""
APACHE_SERVICE=""
APACHE_CONFIG_DIR=""
APACHE_MODULES_DIR=""
MODSEC_CONFIG_DIR=""
print_status() {
echo -e "${GREEN}[INFO]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
cleanup_on_error() {
print_error "Installation failed. Cleaning up..."
systemctl stop "$APACHE_SERVICE" 2>/dev/null || true
rm -rf /opt/ModSecurity /opt/ModSecurity-apache 2>/dev/null || true
exit 1
}
trap cleanup_on_error ERR
check_prerequisites() {
if [[ $EUID -ne 0 ]]; then
print_error "This script must be run as root or with sudo"
exit 1
fi
if ! command -v git >/dev/null 2>&1; then
print_error "Git is required but not installed"
exit 1
fi
}
detect_distro() {
if [[ ! -f /etc/os-release ]]; then
print_error "Cannot detect distribution - /etc/os-release not found"
exit 1
fi
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_INSTALL="apt install -y"
APACHE_SERVICE="apache2"
APACHE_CONFIG_DIR="/etc/apache2"
APACHE_MODULES_DIR="/usr/lib/apache2/modules"
MODSEC_CONFIG_DIR="/etc/apache2/modsecurity.d"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_INSTALL="dnf install -y"
APACHE_SERVICE="httpd"
APACHE_CONFIG_DIR="/etc/httpd"
APACHE_MODULES_DIR="/etc/httpd/modules"
MODSEC_CONFIG_DIR="/etc/httpd/modsecurity.d"
;;
amzn)
PKG_MGR="yum"
PKG_INSTALL="yum install -y"
APACHE_SERVICE="httpd"
APACHE_CONFIG_DIR="/etc/httpd"
APACHE_MODULES_DIR="/etc/httpd/modules"
MODSEC_CONFIG_DIR="/etc/httpd/modsecurity.d"
;;
*)
print_error "Unsupported distribution: $ID"
exit 1
;;
esac
}
update_system() {
print_status "[1/10] Updating system packages..."
case "$PKG_MGR" in
apt)
apt update && apt upgrade -y
;;
dnf|yum)
$PKG_MGR update -y
;;
esac
}
install_dependencies() {
print_status "[2/10] Installing Apache and development tools..."
case "$PKG_MGR" in
apt)
$PKG_INSTALL apache2 apache2-dev build-essential git libcurl4-openssl-dev \
libgeoip-dev libyajl-dev libpcre2-dev libxml2-dev pkgconf libmaxminddb-dev
;;
dnf|yum)
$PKG_INSTALL httpd httpd-devel gcc gcc-c++ git libcurl-devel GeoIP-devel \
yajl-devel pcre2-devel libxml2-devel pkgconfig libmaxminddb-devel
;;
esac
}
compile_modsecurity() {
print_status "[3/10] Downloading and compiling ModSecurity v3..."
cd /opt
if [[ -d ModSecurity ]]; then
rm -rf ModSecurity
fi
git clone --depth 1 -b v3/master --single-branch https://github.com/SpiderLabs/ModSecurity.git
cd ModSecurity
git submodule init
git submodule update
./build.sh
./configure --with-yajl --with-geoip --with-pcre2
make -j"$(nproc)"
make install
}
compile_apache_connector() {
print_status "[4/10] Downloading and compiling ModSecurity Apache connector..."
cd /opt
if [[ -d ModSecurity-apache ]]; then
rm -rf ModSecurity-apache
fi
git clone --depth 1 https://github.com/SpiderLabs/ModSecurity-apache.git
cd ModSecurity-apache
./configure --with-libmodsecurity=/usr/local/modsecurity/
make -j"$(nproc)"
make install
}
configure_library_path() {
print_status "[5/10] Configuring dynamic library loading..."
echo '/usr/local/modsecurity/lib' > /etc/ld.so.conf.d/modsecurity.conf
ldconfig
}
enable_modsecurity_module() {
print_status "[6/10] Enabling ModSecurity Apache module..."
case "$PKG_MGR" in
apt)
echo 'LoadModule security3_module /usr/lib/apache2/modules/mod_security3.so' > "$APACHE_CONFIG_DIR/mods-available/security3.load"
a2enmod security3
;;
dnf|yum)
echo 'LoadModule security3_module modules/mod_security3.so' > "$APACHE_CONFIG_DIR/conf.modules.d/00-security3.conf"
;;
esac
}
create_modsecurity_dirs() {
print_status "[7/10] Creating ModSecurity configuration directory..."
mkdir -p "$MODSEC_CONFIG_DIR"
chown root:root "$MODSEC_CONFIG_DIR"
chmod 755 "$MODSEC_CONFIG_DIR"
}
install_owasp_rules() {
print_status "[8/10] Installing OWASP Core Rule Set..."
cd "$MODSEC_CONFIG_DIR"
if [[ -d coreruleset ]]; then
rm -rf coreruleset
fi
git clone https://github.com/coreruleset/coreruleset.git
cp coreruleset/crs-setup.conf.example coreruleset/crs-setup.conf
chown -R root:root coreruleset
chmod -R 644 coreruleset/*
find coreruleset -type d -exec chmod 755 {} \;
}
create_modsecurity_config() {
print_status "[9/10] Creating ModSecurity configuration..."
cat > "$MODSEC_CONFIG_DIR/modsecurity.conf" << 'EOF'
# ModSecurity v3 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
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: \
PE %{REQBODY_PROCESSOR_ERROR}, \
BQ %{MULTIPART_BOUNDARY_QUOTED}, \
BW %{MULTIPART_BOUNDARY_WHITESPACE}, \
DB %{MULTIPART_DATA_BEFORE}, \
DA %{MULTIPART_DATA_AFTER}, \
HF %{MULTIPART_HEADER_FOLDING}, \
LF %{MULTIPART_LF_LINE}, \
SM %{MULTIPART_MISSING_SEMICOLON}, \
IQ %{MULTIPART_INVALID_QUOTING}, \
IP %{MULTIPART_INVALID_PART}, \
IH %{MULTIPART_INVALID_HEADER_FOLDING}, \
FL %{MULTIPART_FILE_LIMIT_EXCEEDED}'"
SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" \
"id:200004,phase:2,t:none,log,deny,msg:'Multipart parser detected a possible unmatched boundary.'"
SecPcreMatchLimit 1000
SecPcreMatchLimitRecursion 1000
SecResponseBodyAccess Off
SecDebugLog /var/log/apache2/modsec_debug.log
SecDebugLogLevel 0
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
SecAuditLogParts ABDEFHIJZ
SecAuditLogType Serial
SecAuditLog /var/log/apache2/modsec_audit.log
SecArgumentSeparator &
SecCookieFormat 0
SecTmpDir /tmp/
SecDataDir /tmp/
Include ${MODSEC_CONFIG_DIR}/coreruleset/crs-setup.conf
Include ${MODSEC_CONFIG_DIR}/coreruleset/rules/*.conf
EOF
if [[ "$APACHE_SERVICE" == "httpd" ]]; then
sed -i 's|/var/log/apache2/|/var/log/httpd/|g' "$MODSEC_CONFIG_DIR/modsecurity.conf"
fi
chown root:root "$MODSEC_CONFIG_DIR/modsecurity.conf"
chmod 644 "$MODSEC_CONFIG_DIR/modsecurity.conf"
}
configure_apache_vhost() {
print_status "[10/10] Configuring Apache virtual host..."
if [[ "$PKG_MGR" == "apt" ]]; then
VHOST_DIR="$APACHE_CONFIG_DIR/sites-available"
VHOST_FILE="$VHOST_DIR/000-default.conf"
else
VHOST_DIR="$APACHE_CONFIG_DIR/conf.d"
VHOST_FILE="$VHOST_DIR/modsecurity.conf"
fi
cat > "$VHOST_FILE" << EOF
<VirtualHost *:80>
DocumentRoot /var/www/html
ModSecurityEnabled on
ModSecurityConfig $MODSEC_CONFIG_DIR/modsecurity.conf
LogLevel warn
ErrorLog \${APACHE_LOG_DIR}/error.log
CustomLog \${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
EOF
if [[ "$PKG_MGR" == "apt" ]]; then
a2ensite 000-default
fi
chown root:root "$VHOST_FILE"
chmod 644 "$VHOST_FILE"
}
verify_installation() {
print_status "Verifying installation..."
systemctl enable "$APACHE_SERVICE"
systemctl restart "$APACHE_SERVICE"
if systemctl is-active --quiet "$APACHE_SERVICE"; then
print_status "Apache is running successfully"
else
print_error "Apache failed to start. Check logs: journalctl -u $APACHE_SERVICE"
exit 1
fi
if apache2ctl -M 2>/dev/null | grep -q security3 || httpd -M 2>/dev/null | grep -q security3; then
print_status "ModSecurity module loaded successfully"
else
print_warning "ModSecurity module may not be loaded properly"
fi
}
main() {
print_status "Starting ModSecurity 3 + OWASP Core Rule Set installation"
check_prerequisites
detect_distro
print_status "Detected distribution: $ID"
print_status "Package manager: $PKG_MGR"
update_system
install_dependencies
compile_modsecurity
compile_apache_connector
configure_library_path
enable_modsecurity_module
create_modsecurity_dirs
install_owasp_rules
create_modsecurity_config
configure_apache_vhost
verify_installation
print_status "Installation completed successfully!"
print_status "ModSecurity is now protecting your web applications"
print_status "Check logs at: /var/log/apache2/modsec_audit.log (Debian) or /var/log/httpd/modsec_audit.log (RHEL)"
}
main "$@"
Review the script before running. Execute with: bash install.sh