Configure Nginx with ModSecurity 3 and OWASP Core Rule Set to protect web applications against SQL injection, XSS, and other common attacks. This tutorial covers complete WAF setup with security rules, performance optimization, and threat testing.
Prerequisites
- Root or sudo access
- Basic Linux command line knowledge
- Understanding of web server concepts
What this solves
A web application firewall (WAF) protects your applications from common attacks like SQL injection, cross-site scripting (XSS), and malicious bots by filtering HTTP traffic before it reaches your server. ModSecurity 3 provides advanced threat detection capabilities that complement traditional network firewalls. This setup is essential for production web applications that handle user data or face public internet traffic.
Step-by-step configuration
Update system packages
Start by updating your package manager to ensure you get the latest security patches and package versions.
sudo apt update && sudo apt upgrade -yInstall Nginx and development tools
Install Nginx web server along with development packages needed to compile ModSecurity from source.
sudo apt install -y nginx build-essential libpcre3-dev libssl-dev zlib1g-dev libxml2-dev libgeoip-dev liblmdb-dev libyajl-dev libcurl4-openssl-dev libpcre2-dev doxygen gitDownload and compile ModSecurity 3
Clone the ModSecurity repository and compile the library with optimizations for production use.
cd /tmp
git clone --depth 1 -b v3/master --single-branch https://github.com/SpiderLabs/ModSecurity
cd ModSecurity
git submodule init
git submodule updateConfigure and compile ModSecurity with all required features enabled.
./build.sh
./configure --enable-pcre2 --enable-static --disable-shared
make -j$(nproc)
sudo make installDownload and compile ModSecurity-nginx connector
The connector module integrates ModSecurity 3 with Nginx using the dynamic module system.
cd /tmp
git clone --depth 1 https://github.com/SpiderLabs/ModSecurity-nginx.gitGet the Nginx version and download matching source code for module compilation.
nginx -v
NGINX_VERSION=$(nginx -v 2>&1 | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+')
wget http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz
tar zxvf nginx-${NGINX_VERSION}.tar.gzCompile the ModSecurity-nginx module as a dynamic module.
cd nginx-${NGINX_VERSION}
./configure --with-compat --add-dynamic-module=../ModSecurity-nginx
make modules
sudo cp objs/ngx_http_modsecurity_module.so /etc/nginx/modules/Configure Nginx to load ModSecurity module
Add the ModSecurity module to Nginx main configuration and verify it loads correctly.
load_module modules/ngx_http_modsecurity_module.so;
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
use epoll;
multi_accept on;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
server_tokens off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Logging Configuration
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;
error_log /var/log/nginx/error.log warn;
# Gzip Settings
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/json;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}Download OWASP Core Rule Set
The OWASP CRS provides comprehensive protection rules against common web application attacks.
sudo mkdir -p /etc/nginx/modsec
cd /tmp
wget https://github.com/coreruleset/coreruleset/archive/v4.0.0.tar.gz
tar -xzf v4.0.0.tar.gz
sudo cp -R coreruleset-4.0.0/* /etc/nginx/modsec/
sudo mv /etc/nginx/modsec/crs-setup.conf.example /etc/nginx/modsec/crs-setup.confCreate ModSecurity main configuration
Configure ModSecurity with recommended settings for production use including audit logging and rule engine.
# ModSecurity Core Rules Set configuration file
Enable ModSecurity, attaching it to every transaction
SecRuleEngine On
Request body handling
SecRequestBodyAccess On
SecRequestBodyLimit 13107200
SecRequestBodyNoFilesLimit 131072
SecRequestBodyLimitAction Reject
SecRequestBodyJsonDepthLimit 512
SecRequestBodyInMemoryLimit 131072
Response body handling
SecResponseBodyAccess On
SecResponseBodyMimeType text/plain text/html text/xml
SecResponseBodyLimit 524288
SecResponseBodyLimitAction ProcessPartial
Filesystem configuration
SecTmpDir /tmp/
SecDataDir /tmp/
Debug log
SecDebugLog /var/log/nginx/modsec_debug.log
SecDebugLogLevel 0
Audit log
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
SecAuditLogParts ABIJDEFHZ
SecAuditLogType Serial
SecAuditLog /var/log/nginx/modsec_audit.log
Upload handling
SecUploadDir /tmp/
SecUploadKeepFiles Off
Generic attack detection rules
SecRule ARGS "@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:'CRITICAL',\
setvar:'tx.anomaly_score=+%{tx.critical_anomaly_score}'"
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:'CRITICAL',\
setvar:'tx.anomaly_score=+%{tx.critical_anomaly_score}'"
Collaborative detection variables
SecAction \
"id:900000,\
phase:1,\
nolog,\
pass,\
t:none,\
setvar:tx.critical_anomaly_score=5,\
setvar:tx.error_anomaly_score=4,\
setvar:tx.warning_anomaly_score=3,\
setvar:tx.notice_anomaly_score=2,\
setvar:tx.anomaly_score_threshold=5"
Blocking based on anomaly scores
SecRule TX:ANOMALY_SCORE "@ge %{tx.anomaly_score_threshold}" \
"id:949110,\
phase:2,\
deny,\
status:403,\
msg:'Inbound Anomaly Score Exceeded (Total Score: %{TX.ANOMALY_SCORE})',\
tag:'application-multi',\
tag:'language-multi',\
tag:'platform-multi',\
tag:'attack-generic'"
Include /etc/nginx/modsec/crs-setup.conf
Include /etc/nginx/modsec/rules/*.confCreate ModSecurity include file
Create a simple include file that enables ModSecurity for virtual hosts.
Include /etc/nginx/modsec/modsecurity.confConfigure virtual host with ModSecurity
Create a sample virtual host configuration that demonstrates ModSecurity integration with proper security headers.
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
# Enable ModSecurity
modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/main.conf;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# Rate limiting zone
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
limit_req_zone $binary_remote_addr zone=global:10m rate=10r/s;
location / {
limit_req zone=global burst=20 nodelay;
try_files $uri $uri/ =404;
}
location /login {
limit_req zone=login burst=5 nodelay;
try_files $uri $uri/ =404;
}
# Deny access to sensitive files
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
location ~ \.(htaccess|htpasswd|ini|log|sh|sql|conf)$ {
deny all;
access_log off;
log_not_found off;
}
# Cache static assets
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
# Error pages
error_page 403 /403.html;
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /var/www/html;
}
}Create log directories and set permissions
Set up proper log directories with correct ownership for the Nginx user to write ModSecurity logs.
sudo mkdir -p /var/log/nginx
sudo chown www-data:www-data /var/log/nginx
sudo chmod 755 /var/log/nginx
sudo touch /var/log/nginx/modsec_debug.log /var/log/nginx/modsec_audit.log
sudo chown www-data:www-data /var/log/nginx/modsec_*.log
sudo chmod 644 /var/log/nginx/modsec_*.logTest configuration and restart Nginx
Verify the Nginx configuration is valid and restart the service to apply ModSecurity settings.
sudo nginx -t
sudo systemctl restart nginx
sudo systemctl enable nginxConfigure log rotation
Set up automatic log rotation for ModSecurity logs to prevent disk space issues in production.
/var/log/nginx/modsec_*.log {
daily
missingok
rotate 52
compress
delaycompress
notifempty
create 644 www-data www-data
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 cat /var/run/nginx.pid
fi
endscript
}Test WAF functionality
Create test web pages
Create simple test pages to verify ModSecurity is blocking malicious requests.
ModSecurity Test Page
Web Application Firewall Active
This server is protected by ModSecurity 3 with OWASP Core Rule Set.
Data received: " . htmlspecialchars($_POST['data']) . "";
} else {
echo "No data submitted
";
}
?>Test SQL injection protection
Attempt a basic SQL injection attack to verify ModSecurity blocks malicious requests.
curl -X POST -d "data=' OR '1'='1" http://localhost/test.phpYou should see a 403 Forbidden response indicating the WAF blocked the request.
Test XSS protection
Test cross-site scripting protection with a simple XSS payload.
curl -X POST -d "data=" http://localhost/test.phpThis should also result in a 403 Forbidden response from ModSecurity.
Performance optimization
Tune ModSecurity for performance
Optimize ModSecurity settings for production workloads by adjusting buffer sizes and processing limits.
# Performance tuning for ModSecurity
SecRequestBodyInMemoryLimit 262144
SecRequestBodyLimit 52428800
SecResponseBodyLimit 1048576
Reduce rule processing overhead
SecRuleEngine DetectionOnly
SecAuditEngine Off
Optimize rule exclusions for known good traffic
SecRuleRemoveById 920100 # Host header missing
SecRuleRemoveById 920230 # Multiple URL encoding detected
Custom performance rules
SecRule REQUEST_FILENAME "@beginsWith /static/" \
"id:1100,\
phase:1,\
pass,\
nolog,\
ctl:ruleEngine=off"
SecRule REQUEST_FILENAME "@beginsWith /api/health" \
"id:1101,\
phase:1,\
pass,\
nolog,\
ctl:ruleEngine=off"Include this performance configuration in your main ModSecurity config.
Include /etc/nginx/modsec/modsecurity.conf
Include /etc/nginx/modsec/performance.confConfigure Nginx worker optimization
Optimize Nginx worker processes and connections for better performance with ModSecurity enabled.
worker_processes auto;
worker_cpu_affinity auto;
worker_rlimit_nofile 65535;
events {
worker_connections 2048;
use epoll;
multi_accept on;
accept_mutex off;
}
http {
# Connection and timeout optimization
keepalive_timeout 30;
keepalive_requests 100;
send_timeout 10;
client_body_timeout 12;
client_header_timeout 12;
# Buffer optimization for ModSecurity
client_body_buffer_size 16k;
client_header_buffer_size 4k;
client_max_body_size 50m;
large_client_header_buffers 4 8k;
}Monitor WAF activity
Set up real-time monitoring
Monitor ModSecurity activity and blocked requests using log analysis tools.
# View recent blocked requests
sudo tail -f /var/log/nginx/modsec_audit.log
Count blocked requests by rule ID
sudo grep -o '\[id "[0-9]*"\]' /var/log/nginx/modsec_audit.log | sort | uniq -c | sort -nr
Monitor error log for ModSecurity issues
sudo tail -f /var/log/nginx/error.log | grep -i modsecCreate monitoring script
Set up automated monitoring for ModSecurity blocking activity and performance metrics.
#!/bin/bash
ModSecurity monitoring script
LOGFILE="/var/log/nginx/modsec_audit.log"
ALERT_EMAIL="admin@example.com"
THRESHOLD=100
Count blocks in last hour
BLOCKS=$(grep "$(date -d '1 hour ago' '+%d/%b/%Y:%H')" $LOGFILE | wc -l)
if [ $BLOCKS -gt $THRESHOLD ]; then
echo "ModSecurity Alert: $BLOCKS requests blocked in the last hour" | \
mail -s "High WAF Activity Alert" $ALERT_EMAIL
fi
Log summary statistics
echo "$(date): $BLOCKS requests blocked in last hour" >> /var/log/modsec-stats.logsudo chmod +x /usr/local/bin/modsec-monitor.sh
Add to crontab for hourly monitoring
echo "0 /usr/local/bin/modsec-monitor.sh" | sudo crontab -Verify your setup
# Check Nginx is running with ModSecurity
sudo systemctl status nginx
nginx -V 2>&1 | grep -o with-compat
Verify ModSecurity module is loaded
sudo nginx -T | grep modsecurity
Test basic functionality
curl -I http://localhost/
Check logs for initialization
sudo grep -i modsecurity /var/log/nginx/error.log
Verify rule loading
sudo grep -c "Rule" /etc/nginx/modsec/rules/*.confCommon issues
| Symptom | Cause | Fix |
|---|---|---|
| 502 Bad Gateway error | ModSecurity compilation issue | Recompile module: make clean && make modules |
| 403 errors for legitimate requests | Overly strict rules | Review audit log and whitelist rules: SecRuleRemoveById |
| High memory usage | Large request body limits | Reduce SecRequestBodyLimit and SecRequestBodyInMemoryLimit |
| Rules not loading | Permission issues | sudo chown -R www-data:www-data /etc/nginx/modsec |
| Slow response times | Full rule processing on static files | Disable rules for static content with ctl:ruleEngine=off |
Next steps
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly NC='\033[0m'
# Global variables
NGINX_VERSION=""
PKG_MGR=""
PKG_INSTALL=""
NGINX_CONF_DIR=""
NGINX_MODULES_DIR=""
SITE_DOMAIN="${1:-example.com}"
# Cleanup function for rollback
cleanup() {
echo -e "${RED}[ERROR] Installation failed. Cleaning up...${NC}"
systemctl stop nginx 2>/dev/null || true
rm -rf /tmp/ModSecurity /tmp/ModSecurity-nginx /tmp/nginx-* /tmp/coreruleset-* /tmp/v4.0.0.tar.gz
echo -e "${YELLOW}Cleanup completed.${NC}"
}
trap cleanup ERR
usage() {
echo "Usage: $0 [domain_name]"
echo "Example: $0 example.com"
exit 1
}
log_step() {
echo -e "${GREEN}[$1] $2${NC}"
}
log_warning() {
echo -e "${YELLOW}[WARNING] $1${NC}"
}
check_prerequisites() {
if [[ $EUID -ne 0 ]]; then
echo -e "${RED}This script must be run as root${NC}"
exit 1
fi
if ! command -v git >/dev/null 2>&1; then
echo -e "${RED}Git is required but not installed${NC}"
exit 1
fi
}
detect_distro() {
if [[ ! -f /etc/os-release ]]; then
echo -e "${RED}Cannot detect distribution. /etc/os-release not found.${NC}"
exit 1
fi
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_INSTALL="apt install -y"
NGINX_CONF_DIR="/etc/nginx"
NGINX_MODULES_DIR="/etc/nginx/modules"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_INSTALL="dnf install -y"
NGINX_CONF_DIR="/etc/nginx"
NGINX_MODULES_DIR="/etc/nginx/modules"
;;
amzn)
PKG_MGR="yum"
PKG_INSTALL="yum install -y"
NGINX_CONF_DIR="/etc/nginx"
NGINX_MODULES_DIR="/etc/nginx/modules"
;;
*)
echo -e "${RED}Unsupported distribution: $ID${NC}"
exit 1
;;
esac
}
update_system() {
log_step "1/10" "Updating system packages"
case "$PKG_MGR" in
apt)
apt update && apt upgrade -y
;;
dnf|yum)
$PKG_MGR update -y
;;
esac
}
install_dependencies() {
log_step "2/10" "Installing Nginx and development tools"
case "$ID" in
ubuntu|debian)
$PKG_INSTALL nginx build-essential libpcre3-dev libssl-dev zlib1g-dev libxml2-dev libgeoip-dev liblmdb-dev libyajl-dev libcurl4-openssl-dev libpcre2-dev doxygen wget
;;
*)
$PKG_INSTALL nginx gcc gcc-c++ make pcre-devel openssl-devel zlib-devel libxml2-devel GeoIP-devel lmdb-devel yajl-devel libcurl-devel pcre2-devel doxygen wget
;;
esac
}
compile_modsecurity() {
log_step "3/10" "Downloading and compiling ModSecurity 3"
cd /tmp
rm -rf ModSecurity
git clone --depth 1 -b v3/master --single-branch https://github.com/SpiderLabs/ModSecurity
cd ModSecurity
git submodule init
git submodule update
./build.sh
./configure --enable-pcre2 --enable-static --disable-shared
make -j$(nproc)
make install
ldconfig
}
compile_nginx_module() {
log_step "4/10" "Compiling ModSecurity-nginx connector"
cd /tmp
rm -rf ModSecurity-nginx
git clone --depth 1 https://github.com/SpiderLabs/ModSecurity-nginx.git
NGINX_VERSION=$(nginx -v 2>&1 | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+')
rm -f nginx-${NGINX_VERSION}.tar.gz
wget http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz
tar zxf nginx-${NGINX_VERSION}.tar.gz
cd nginx-${NGINX_VERSION}
./configure --with-compat --add-dynamic-module=../ModSecurity-nginx
make modules
mkdir -p ${NGINX_MODULES_DIR}
cp objs/ngx_http_modsecurity_module.so ${NGINX_MODULES_DIR}/
chown root:root ${NGINX_MODULES_DIR}/ngx_http_modsecurity_module.so
chmod 644 ${NGINX_MODULES_DIR}/ngx_http_modsecurity_module.so
}
configure_nginx() {
log_step "5/10" "Configuring Nginx with ModSecurity"
cat > ${NGINX_CONF_DIR}/nginx.conf << 'EOF'
load_module modules/ngx_http_modsecurity_module.so;
user nginx;
worker_processes auto;
pid /run/nginx.pid;
events {
worker_connections 1024;
use epoll;
multi_accept on;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
server_tokens off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
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;
error_log /var/log/nginx/error.log warn;
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/json;
include /etc/nginx/conf.d/*.conf;
EOF
# Add sites-enabled for Debian-based systems
if [[ "$ID" == "ubuntu" || "$ID" == "debian" ]]; then
echo " include /etc/nginx/sites-enabled/*;" >> ${NGINX_CONF_DIR}/nginx.conf
mkdir -p ${NGINX_CONF_DIR}/sites-available ${NGINX_CONF_DIR}/sites-enabled
usermod -s /bin/false nginx 2>/dev/null || useradd -r -s /bin/false nginx
sed -i 's/user nginx;/user www-data;/' ${NGINX_CONF_DIR}/nginx.conf
fi
echo "}" >> ${NGINX_CONF_DIR}/nginx.conf
}
install_owasp_crs() {
log_step "6/10" "Installing OWASP Core Rule Set"
mkdir -p ${NGINX_CONF_DIR}/modsec
cd /tmp
rm -f v4.0.0.tar.gz
wget https://github.com/coreruleset/coreruleset/archive/v4.0.0.tar.gz
tar -xzf v4.0.0.tar.gz
cp -R coreruleset-4.0.0/* ${NGINX_CONF_DIR}/modsec/
mv ${NGINX_CONF_DIR}/modsec/crs-setup.conf.example ${NGINX_CONF_DIR}/modsec/crs-setup.conf
chown -R root:root ${NGINX_CONF_DIR}/modsec
find ${NGINX_CONF_DIR}/modsec -type d -exec chmod 755 {} \;
find ${NGINX_CONF_DIR}/modsec -type f -exec chmod 644 {} \;
}
configure_modsecurity() {
log_step "7/10" "Configuring ModSecurity"
cat > ${NGINX_CONF_DIR}/modsec/modsecurity.conf << 'EOF'
SecRuleEngine On
SecRequestBodyAccess On
SecRequestBodyLimit 13107200
SecRequestBodyNoFilesLimit 131072
SecRequestBodyInMemoryLimit 131072
SecRequestBodyLimitAction Reject
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 ABIJDEFHZ
SecAuditLogType Serial
SecAuditLog /var/log/nginx/modsec_audit.log
SecArgumentSeparator &
SecCookieFormat 0
SecUnicodeMapFile unicode.mapping 20127
SecStatusEngine On
Include /etc/nginx/modsec/crs-setup.conf
Include /etc/nginx/modsec/rules/*.conf
EOF
cat > ${NGINX_CONF_DIR}/modsec/main.conf << 'EOF'
Include /etc/nginx/modsec/modsecurity.conf
EOF
chown root:root ${NGINX_CONF_DIR}/modsec/*.conf
chmod 644 ${NGINX_CONF_DIR}/modsec/*.conf
}
create_test_site() {
log_step "8/10" "Creating test site configuration"
local site_conf="${NGINX_CONF_DIR}/conf.d/${SITE_DOMAIN}.conf"
if [[ "$ID" == "ubuntu" || "$ID" == "debian" ]]; then
site_conf="${NGINX_CONF_DIR}/sites-available/${SITE_DOMAIN}"
fi
cat > "$site_conf" << EOF
server {
listen 80;
server_name ${SITE_DOMAIN} www.${SITE_DOMAIN};
modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/main.conf;
root /var/www/html;
index index.html index.htm;
location / {
try_files \$uri \$uri/ =404;
}
location = /test-xss {
return 200 "XSS test endpoint - should be blocked by ModSecurity";
add_header Content-Type text/plain;
}
error_page 403 /403.html;
location = /403.html {
root /var/www/html;
internal;
}
}
EOF
if [[ "$ID" == "ubuntu" || "$ID" == "debian" ]]; then
ln -sf ${NGINX_CONF_DIR}/sites-available/${SITE_DOMAIN} ${NGINX_CONF_DIR}/sites-enabled/
rm -f ${NGINX_CONF_DIR}/sites-enabled/default
fi
mkdir -p /var/www/html
echo "<h1>Welcome to ${SITE_DOMAIN}</h1><p>ModSecurity is active!</p>" > /var/www/html/index.html
echo "<h1>Access Forbidden</h1><p>This request was blocked by ModSecurity WAF.</p>" > /var/www/html/403.html
chown -R www-data:www-data /var/www/html 2>/dev/null || chown -R nginx:nginx /var/www/html
chmod -R 644 /var/www/html/*
}
start_services() {
log_step "9/10" "Starting and enabling services"
systemctl enable nginx
systemctl restart nginx
}
verify_installation() {
log_step "10/10" "Verifying installation"
if ! systemctl is-active --quiet nginx; then
echo -e "${RED}Nginx is not running${NC}"
exit 1
fi
if ! nginx -t; then
echo -e "${RED}Nginx configuration test failed${NC}"
exit 1
fi
if ! nginx -T 2>&1 | grep -q "ngx_http_modsecurity_module"; then
echo -e "${RED}ModSecurity module not loaded${NC}"
exit 1
fi
echo -e "${GREEN}Installation completed successfully!${NC}"
echo -e "${YELLOW}Test ModSecurity with: curl 'http://${SITE_DOMAIN}/test-xss?param=<script>alert(1)</script>'${NC}"
echo -e "${YELLOW}Check logs: tail -f /var/log/nginx/modsec_audit.log${NC}"
}
main() {
if [[ $# -gt 1 ]]; then
usage
fi
check_prerequisites
detect_distro
update_system
install_dependencies
compile_modsecurity
compile_nginx_module
configure_nginx
install_owasp_crs
configure_modsecurity
create_test_site
start_services
verify_installation
}
main "$@"
Review the script before running. Execute with: bash install.sh