nginx-waf

April 4, 2026 · View on GitHub

A dynamic nginx module for IP/CIDR-based access control with named lists and tag-based organization.

⚠️ Experimental Project

╔══════════════════════════════════════════════════════════════════╗
║  🧪 THIS PROJECT IS EXPERIMENTAL - NOT PRODUCTION READY         ║
║                                                                  ║
║  • Early development stage                                       ║
║  • API and features may change                                   ║
║  • Use at your own risk                                          ║
║  • Contributions and ideas welcome!                              ║
╚══════════════════════════════════════════════════════════════════╝

📅 Started: December 2025
🎯 Target: v1.0.0 stable release
📊 Current: v0.2.1 - Core Complete, Testing Phase


What is nginx-waf?

nginx-waf is a simple, focused nginx module that provides IP-based access control. Think of it as a flexible IP blocklist/allowlist manager.

Core Features

FeatureDescription
🏷️ Named ListsDefine lists with meaningful names (tor, botnets, trusted)
🔖 Tag OrganizationGroup lists with tags for bulk management (tag:anonymizers)
Blacklist ModeBlock IPs that match any active list
Whitelist ModeAllow only IPs that match active lists
🎯 Flexible ScopeConfigure at http, server, or location level
🌐 IPv4 & IPv6Full support with CIDR ranges

What nginx-waf is NOT

  • Not a full WAF - No request body inspection, SQL injection detection, etc.
  • Not a rate limiter - Use nginx's limit_req module
  • Not a bot detector - IP lists only, no behavior analysis
  • Not a CDN - Just access control

Why Another Module?

  • Simpler than ModSecurity - Focused on IP-based control only
  • Works with vanilla nginx - No OpenResty required
  • Named lists with tags - Organize dozens of lists easily
  • Per-location configuration - Fine-grained control

Quick Example

http {
    # Define IP lists with tags
    waf_list tor "/etc/nginx/waf/tor-exits.txt" "anonymizers,privacy";
    waf_list botnets "/etc/nginx/waf/botnets.txt" "security";
    waf_list trusted "/etc/nginx/waf/trusted.txt" "internal";

    server {
        server_name api.example.com;

        # Block all anonymizers by default
        waf on;
        waf_mode blacklist;
        waf_enable_lists tag:anonymizers;

        location /admin {
            # Strict whitelist for admin
            waf on;
            waf_mode whitelist;
            waf_enable_lists trusted;
        }

        location /public {
            # No restrictions on public endpoints
            waf off;
        }
    }
}

Configuration Reference

DirectiveContextArgumentsDescription
wafhttp, server, locationon|offEnable/disable WAF
waf_modehttp, server, locationblacklist|whitelistOperation mode
waf_listhttpname path [tags]Define an IP list
waf_enable_listshttp, server, locationname,...|tag:name|allActivate lists
waf_disable_listshttp, server, locationname,...|tag:nameDeactivate lists
waf_log_prefixhttp, server, locationstringCustom log prefix

IP List Format

Lists are plain text files with one entry per line:

# Comments start with #
# IPv4 addresses
192.168.1.100
10.0.0.50

# IPv4 CIDR ranges
192.168.0.0/24
10.0.0.0/8

# IPv6 addresses
2001:db8::1
::ffff:192.168.1.1

# IPv6 CIDR ranges
2001:db8::/32

Installation

🚧 Packages coming soon via openSUSE Build Service (OBS)

Planned distribution support:

DistributionVersions
Debian11, 12, 13
Ubuntu22.04, 24.04, 25.04
Fedora41, 42
openSUSETumbleweed, Leap 15.6, 16.0
RHEL/Rocky/Alma8, 9

Building from Source

Requirements:

  • nginx source code (matching your nginx version)
  • GCC and make
  • PCRE and zlib development libraries
# Download nginx source
wget https://nginx.org/download/nginx-1.27.4.tar.gz
tar xzf nginx-1.27.4.tar.gz
cd nginx-1.27.4

# Configure with the module
./configure --add-dynamic-module=/path/to/nginx-waf/src

# Build the module
make modules

# Install (as root)
cp objs/ngx_http_waf_module.so /usr/lib64/nginx/modules/

Works Well With

nginx-waf is designed to complement existing nginx modules:

ModuleUse Case
ngx_http_realip_moduleGet real client IP behind proxies/CDN
ngx_http_limit_req_moduleRate limiting
ngx_http_geo_moduleGeographic restrictions
ngx_http_access_moduleSimple allow/deny rules

Example with Real IP:

http {
    # Trust Cloudflare IPs
    set_real_ip_from 103.21.244.0/22;
    set_real_ip_from 103.22.200.0/22;
    real_ip_header CF-Connecting-IP;
    
    # WAF checks real client IP
    waf_list threats "/etc/nginx/waf/threats.txt";
    waf on;
    waf_mode blacklist;
    waf_enable_lists threats;
}

Roadmap

v0.2.1 - Core Module ✅ (Current)

  • Project setup and documentation
  • Basic module with waf on|off
  • Single IP list support
  • Multiple named lists with tags
  • Blacklist and whitelist modes
  • IPv4 and IPv6 with CIDR
  • waf_enable_lists and waf_disable_lists directives
  • Tag-based list selection (tag:name)
  • Context inheritance (http → server → location)
  • GitHub Actions CI/CD (x86_64 + ARM64)
  • OBS packages (in progress)

v1.0.0 - Stable Release (Target: Q2 2026)

  • Community testing and feedback
  • Performance benchmarks
  • OBS packages for major distributions
  • Security review

v2.0.0 - Extensions (Future)

See Planned Extensions section below for details on future companion projects.


Ecosystem

Companion projects that extend nginx-waf with management, automation, and integration capabilities:

ProjectLanguageDescription
nginx-waf-apiGoREST API daemon for dynamic IP list management without nginx reloads
nginx-waf-uiGoWeb-based dashboard for managing lists, viewing stats, and configuration
nginx-waf-feedsGoAutomatic threat feed updater (Cloudflare, Tor exits, Spamhaus, etc.)
nginx-waf-luaLuaOpenResty/Lua integration for scripted WAF logic and custom responses

Architecture Overview

                                ┌─────────────────┐
                                │  nginx-waf-ui   │
                                │  (Web Dashboard)│
                                └────────┬────────┘

┌─────────────────┐            ┌─────────▼────────┐            ┌─────────────────┐
│ nginx-waf-feeds │───────────▶│  nginx-waf-api   │◀───────────│   CLI / Scripts │
│ (Feed Updater)  │            │   (REST API)     │            │                 │
└─────────────────┘            └─────────┬────────┘            └─────────────────┘

                               ┌─────────▼────────┐
                               │   IP List Files  │
                               │ /etc/nginx/waf/  │
                               └─────────┬────────┘

                               ┌─────────▼────────┐
                               │    nginx-waf     │◀──── nginx-waf-lua
                               │   (C Module)     │      (Lua bindings)
                               └──────────────────┘

Status

ProjectStatus
nginx-waf🟡 In Development (v0.2.1)
nginx-waf-api🟢 v0.1.0 Released
nginx-waf-ui🟢 v0.1.0 Released
nginx-waf-feeds🟢 v0.1.0 Released
nginx-waf-lua🟢 v0.1.0 Released

Contributing

We welcome contributions! This is an experimental project and community input is valuable.

How to Contribute

  1. Check Issues for good first issue labels
  2. Read CONTRIBUTING.md for guidelines
  3. Open a discussion for ideas or questions
  4. Submit focused, well-tested PRs

What We Need

  • Testing on different nginx versions and distributions
  • Documentation improvements
  • Example configurations
  • Code review and security feedback

See CONTRIBUTING.md for details.


Other nginx dynamic modules we maintain:

ModuleDescription
nginx-torblockerControl access from Tor exit nodes — block, allow, or Tor-only mode
nginx-cf-realipAutomatic Cloudflare edge IP list fetcher for real client IP restoration
nginx-goneReturn HTTP 410 Gone for permanently removed URIs

Apache HTTP Server Versions

All modules are also available for Apache httpd:

ModuleDescription
apache-wafIP/CIDR-based access control with named lists
apache-waf-apiREST API for dynamic WAF IP list management
apache-waf-feedsAutomatic threat feed updater for apache-waf
apache-waf-uiWeb management interface for apache-waf
apache-torblockerControl access from Tor exit nodes
apache-cf-realipCloudflare real IP restoration via mod_remoteip
apache-goneReturn HTTP 410 Gone for permanently removed URIs

Support the Project

If you find this project interesting:

See FUNDING.md for more options.


License

BSD 3-Clause License


Security

Found a security issue? Please see our Security Policy for responsible disclosure.


⚠️ Experimental - Use at Your Own Risk
Contributions and ideas welcome!