Guides 11792 Published by

The guide walks you through installing ModSecurity 3 on a fresh Ubuntu 22.04 system by first updating the OS, installing required build tools, cloning the ModSecurity source, and compiling it into /usr/local/modsecurity. It then shows how to download Nginx’s source, add the ModSecurity‑nginx connector as a dynamic module during configuration, compile Nginx, and install it with the appropriate paths. After installation you create a small module‑loading snippet, place the core ModSecurity configuration (including SecRuleEngine On), and enable the WAF in any server block via modsecurity on; modsecurity_rules_file directives. Finally, you restart Nginx, verify operation by checking error and audit logs, and optionally tune performance, rule sets, or set up automatic CRS updates.



Install Nginx with ModSecurity 3 on Ubuntu 22.04 LTS

You’ll get a working Nginx that talks to the latest ModSecurity 3 WAF, ready for custom rule sets and basic protection. The guide assumes a fresh Ubuntu 22.04 install but works just as well on an existing server.

Prerequisites

First make sure your system is up‑to‑date and you have the build tools Nginx needs.

sudo apt update && sudo apt upgrade -y
sudo apt install -y git gcc make libpcre3-dev zlib1g-dev \
libssl-dev wget curl gnupg2 ca-certificates lsb-release

Updating packages prevents weird compile errors later, and the dev libraries are required to build Nginx modules.

Grab ModSecurity 3 (Libmodsecurity)

Ubuntu’s repositories still ship an old 2.x branch, so we’ll pull the current source.

cd /usr/local/src
sudo git clone --depth 1 -b v3/master https://github.com/SpiderLabs/ModSecurity
cd ModSecurity
git submodule init && git submodule update
sudo ./build.sh
sudo ./configure
sudo make
sudo make install

make install puts the library files in /usr/local/modsecurity. I’ve seen people skip submodule update and end up with a broken build; don’t do that.

Compile Nginx with the ModSecurity module

We need a version of Nginx that includes the dynamic module. Using the official Ubuntu package won’t work because it’s compiled without ModSecurity support.

cd /usr/local/src
sudo wget http://nginx.org/download/nginx-1.24.0.tar.gz
sudo tar xf nginx-1.24.0.tar.gz
cd nginx-1.24.0

# Pull the connector that bridges Nginx and ModSecurity
sudo git clone https://github.com/SpiderLabs/ModSecurity-nginx.git

# Build Nginx with the dynamic module enabled
sudo ./configure \
--prefix=/etc/nginx \
--sbin-path=/usr/sbin/nginx \
--conf-path=/etc/nginx/nginx.conf \
--modules-path=/usr/lib/nginx/modules \
--with-http_ssl_module \
--add-dynamic-module=./ModSecurity-nginx

sudo make
sudo make install

The --add-dynamic-module flag tells the compiler to create a separate .so file you can enable or disable without recompiling Nginx later. If you skip this and try to load the module statically, you’ll get “module not found” errors.

Enable the ModSecurity module in Nginx

Create a small config snippet that loads the module and points it at the library we built earlier.

sudo mkdir -p /etc/nginx/modules-enabled
echo "load_module modules/ngx_http_modsecurity_module.so;" | sudo tee /etc/nginx/modules-enabled/modsecurity.conf

Now tell ModSecurity where its configuration lives.

sudo mkdir -p /etc/nginx/modsec
sudo cp /usr/local/modsecurity/include/modsecurity.h /etc/nginx/modsec/

Create the core ModSecurity config file:

sudo tee /etc/nginx/modsec/modsecurity.conf > /dev/null <<'EOF'
SecRuleEngine On
SecDefaultAction "phase:1,log,auditlog,pass"
Include /usr/local/modsecurity/etc/modsecurity/*.conf
EOF

I usually copy the example rules that come with ModSecurity into /usr/local/modsecurity/etc/modsecurity/. The default rule set is decent for getting started, but you’ll want to trim it down later – the out‑of‑the‑box list can cause false positives on a busy site.

Hook ModSecurity into your server block

Edit any virtual host you want protected and add the directive right after listen.

server {
listen 80;
server_name example.com;

modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;

location / {
proxy_pass http://127.0.0.1:8080;
}
}

The modsecurity on; line turns the WAF on for that host only, which is handy when you’re testing changes.

Test the installation

Restart Nginx and watch the logs.

sudo systemctl restart nginx
sudo tail -f /var/log/nginx/error.log /var/log/modsec_audit.log

Try a simple attack string:

curl "http://example.com/?id=1' or '1'='1"

You should see an entry in the audit log and a 403 response if the rule set caught it. If Nginx refuses to start, double‑check that the load_module line points at the correct .so file; I’ve seen mismatched paths cause cryptic “invalid module” errors.

Optional tweaks

  • Performance: Turn on caching for ModSecurity by adding SecCacheTransformations On in the config.
  • Rule management: The free Core Rule Set (CRS) is a good baseline, but you’ll probably want to disable rules that trip on legitimate traffic. Use SecRuleRemoveById to silence noisy IDs.
  • Automatic updates: Set up a cron job that pulls the latest CRS from GitHub and reloads Nginx.

That’s it – Nginx now talks to ModSecurity 3, and you have a basic WAF in place. Feel free to experiment with custom rules; the more you tinker, the better your site will defend itself.