Skip to content

Nginx Integration

This guide explains how to wire the generated rules into an Nginx configuration.

Quick start

  1. Download nginx_waf.zip from the latest release and extract it (e.g. into /etc/nginx/waf_patterns/nginx/).
  2. Include waf_maps.conf from the http block.
  3. Include waf_rules.conf from each server (or location) you want to protect.
  4. Reload Nginx.

Files in the archive

FilePurposeWhere to include
waf_maps.confDefines map variables for every attack categoryhttp block
waf_rules.confif (...) { return 403; } rules that consume those mapsserver or location block
bots.confmap $http_user_agent $bad_bot for User-Agent filteringhttp block
sqli.conf, xss.conf, rce.conf, lfi.conf, …Per-category files for inspection onlyDo not include directly

Use only the two main files

The per-category .conf files (attack.conf, xss.conf, sqli.conf, …) are emitted for inspection. They contain both map and if directives, which Nginx does not allow in the same context. Always include waf_maps.conf + waf_rules.conf instead.

Step 1 — Include the maps

The map directives must live in the http context:

nginx
http {
    include /etc/nginx/waf_patterns/nginx/waf_maps.conf;
    include /etc/nginx/waf_patterns/nginx/bots.conf;

    # …rest of your http config
}

Step 2 — Include the rules

Place the blocking rules inside any server block you want to protect:

nginx
server {
    listen 443 ssl http2;
    server_name example.com;

    include /etc/nginx/waf_patterns/nginx/waf_rules.conf;

    if ($bad_bot) { return 403; }

    # …your locations
}

Step 3 — Validate and reload

bash
sudo nginx -t && sudo systemctl reload nginx

How it works

The converter rewrites every OWASP regex into a map lookup, which Nginx evaluates with O(1) overhead per request:

nginx
map $request_uri $waf_block_sqli {
    default 0;
    "~*union[\s\S]+select"  1;
    "~*insert[\s\S]+into"   1;
}

# …elsewhere, in a server block:
if ($waf_block_sqli) { return 403; }

The full set of map variables is $waf_block_<category> — one per attack family the OWASP CRS defines.

Customization

Log blocked requests

Add a dedicated access log next to the deny:

nginx
log_format waf_block '$remote_addr - [$time_local] "$request" '
                     'blocked=$waf_block_sqli ua="$http_user_agent"';

server {
    access_log /var/log/nginx/waf_blocked.log waf_block if=$waf_block_sqli;
    include /etc/nginx/waf_patterns/nginx/waf_rules.conf;
}

Whitelist a path

Skip the WAF inside specific routes by branching before the include:

nginx
location = /api/webhook {
    proxy_pass http://upstream;
    # waf_rules.conf intentionally not included here
}

location / {
    include /etc/nginx/waf_patterns/nginx/waf_rules.conf;
    proxy_pass http://upstream;
}

Testing

Probe the deployment with known-bad payloads — both should return 403:

bash
curl -I "https://example.com/?id=1' OR '1'='1"
curl -I "https://example.com/?q=<script>alert(1)</script>"

Troubleshooting

  • nginx: configuration file test failed — you likely included a per-category file. Switch to waf_maps.conf + waf_rules.conf.
  • False positives — check /var/log/nginx/error.log, identify the matching $waf_block_* variable, then add a location-scoped exemption.
  • High traffic — the map-based design is already the fastest option Nginx offers; no further tuning is normally needed.

Released under the MIT License.