Follow-up to review feedback on the privacy/CSP change already merged here:
- The comment inserted alongside the CSP was written in Italian while these
configs are in English. It came from the script used to apply the change
across many repositories. Rewritten in English.
- The meta CSP was emitted unconditionally, so it also applied under
'vitepress dev'. Testing showed HMR still connects there, because the dev
server is same-origin and connect-src 'self' covers its websocket - but it
would break as soon as the dev server is not same-origin ('--host', or a
custom server.hmr.port). It is now emitted for production builds only.
- Where footer.message had been left as two concatenated literals (an artefact
of the mechanical rollout) it is collapsed into one.
Nothing changes for visitors: the built site still carries the CSP and the
privacy link.
Signed-off-by: Fabrizio Salmi <fabrizio.salmi@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Patterns
Production-grade WAF rules, on autopilot.
Automated OWASP Core Rule Set and bad-bot patterns, converted into native configurations for Nginx, Apache, Traefik, and HAProxy — refreshed every day.
Why Patterns
The OWASP Core Rule Set (CRS) is the de-facto open-source rule base behind ModSecurity, but plugging it into anything other than Apache is non-trivial. Patterns automates the whole pipeline:
- Pull the latest CRS rules straight from upstream.
- Convert them into the native syntax of each web server — not a generic shim.
- Package the output as ready-to-deploy archives, refreshed every day by GitHub Actions.
You get equivalent protection across SQL injection, XSS, RCE, LFI, and bad-bot traffic, regardless of which proxy you run.
Highlights
| OWASP CRS coverage | SQLi, XSS, RCE, LFI, RFI, plus generic anomaly and protocol-violation rules. |
| Native output | Nginx map/if, Apache SecRule, Traefik middleware TOML, HAProxy ACL files. |
| Bad-bot blocking | Curated User-Agent lists from public sources, with safe defaults that do not block major search engines. |
| Daily refresh | A scheduled GitHub Actions workflow rebuilds every backend and publishes a fresh release. |
| Pre-built archives | Skip the toolchain — download nginx_waf.zip, apache_waf.zip, traefik_waf.zip, or haproxy_waf.zip. |
| Composable | Each backend is a small Python converter on top of one JSON intermediate. Adding a new platform is a few hundred lines. |
Using Caddy? See the dedicated
caddy-wafproject.
Quick start
Option 1 — download a pre-built release
# Pick the archive that matches your stack
curl -LO https://github.com/fabriziosalmi/patterns/releases/latest/download/nginx_waf.zip
unzip nginx_waf.zip -d /etc/nginx/waf_patterns
Then follow the Nginx, Apache, Traefik, or HAProxy integration guide.
Option 2 — build from source
Requires Python 3.9+, pip, and git.
git clone https://github.com/fabriziosalmi/patterns.git
cd patterns
pip install -r requirements.txt
python owasp2json.py # 1. Fetch the latest OWASP CRS into owasp_rules.json
python json2nginx.py # 2. Convert into Nginx WAF config
python json2apache.py # …or Apache (ModSecurity)
python json2traefik.py # …or Traefik middleware
python json2haproxy.py # …or HAProxy ACL files
python badbots.py # 3. Generate bad-bot blocklists
Generated files land in waf_patterns/<platform>/.
Architecture
┌─────────────────────┐ daily cron ┌──────────────────────┐
│ coreruleset/ │ ───────────────▶ │ owasp2json.py │
│ coreruleset (GH) │ │ → owasp_rules.json │
└─────────────────────┘ └──────────┬───────────┘
│
┌─────────────────┬──────────────────┬──────┴──────────┐
▼ ▼ ▼ ▼
json2nginx.py json2apache.py json2traefik.py json2haproxy.py
│ │ │ │
▼ ▼ ▼ ▼
nginx_waf.zip apache_waf.zip traefik_waf.zip haproxy_waf.zip
(published as a GitHub Release)
Each converter is independent, idempotent, and configured exclusively through environment variables (INPUT_FILE, OUTPUT_DIR). Full reference at docs/api.
Repository layout
patterns/
├── owasp2json.py # Pull and parse OWASP CRS into a JSON intermediate
├── json2nginx.py # JSON → Nginx (map + if directives)
├── json2apache.py # JSON → Apache (ModSecurity SecRule)
├── json2traefik.py # JSON → Traefik (middleware TOML)
├── json2haproxy.py # JSON → HAProxy (ACL files)
├── badbots.py # Public bot lists → per-platform blocklists
├── import_*_waf.py # Optional installers for each platform
├── waf_patterns/ # Generated outputs
│ ├── nginx/
│ ├── apache/
│ ├── traefik/
│ └── haproxy/
├── docs/ # VitePress documentation site
├── tests/ # Validation tests for each backend
└── .github/workflows/ # Daily build + release automation
Integration in 60 seconds
Nginx
http {
include /etc/nginx/waf_patterns/nginx/waf_maps.conf;
include /etc/nginx/waf_patterns/nginx/bots.conf;
}
server {
include /etc/nginx/waf_patterns/nginx/waf_rules.conf;
if ($bad_bot) { return 403; }
}
Apache (ModSecurity)
<IfModule security2_module>
SecRuleEngine On
Include /etc/apache2/waf_patterns/apache/*.conf
</IfModule>
Traefik
http:
routers:
app:
rule: "Host(`example.com`)"
service: app
middlewares: [waf-protection@file, bot-blocker@file]
HAProxy
frontend http-in
bind *:80
acl waf_match path,url_dec -m reg -i -f /etc/haproxy/waf.acl
acl bad_bot hdr(User-Agent) -m reg -i -f /etc/haproxy/bots.acl
http-request deny deny_status 403 if waf_match || bad_bot
Full guides — with logging, whitelists, and tuning — live in the docs.
Bad-bot example output (Nginx)
map $http_user_agent $bad_bot {
default 0;
"~*AhrefsBot" 1;
"~*SemrushBot" 1;
"~*MJ12bot" 1;
"~*GPTBot" 1;
}
if ($bad_bot) { return 403; }
The default list blocks SEO crawlers, AI training bots, and known scanners while explicitly allowing major search engines (Google, Bing, DuckDuckGo, Yandex, Baidu).
Automation
| Workflow | Schedule | Purpose |
|---|---|---|
update_patterns.yml |
Daily + manual | Re-fetch CRS, regenerate every backend, publish a release |
test_nginx.yml |
On PR | Validate generated Nginx rules against a live container |
test_apache_docker.yml |
On PR | Validate generated Apache rules against ModSecurity in Docker |
docs.yml |
On docs/ change |
Build and deploy the VitePress docs to GitHub Pages |
All workflows run on GitHub-hosted runners (ubuntu-latest).
Documentation
The full documentation lives at fabriziosalmi.github.io/patterns — built with VitePress and deployed automatically.
Commercial support & consulting
Running these WAF rules in production? I offer paid support, custom rule development, and security consulting - WAF tuning, hardening, TLS automation, and cloud detection & alerting. Reach out: fabrizio.salmi@gmail.com.
Contributing
- Fork the repository.
- Create a feature branch:
git checkout -b feature/your-change. - Commit and push.
- Open a pull request — the test workflows will run automatically.
See CONTRIBUTING.md for details and SECURITY.md for the disclosure policy.
License
The original code of this project — the Python converters, the documentation, and the tests — is released under the MIT License (Copyright © Fabrizio Salmi).
The generated data is not covered by that MIT grant. owasp_rules.json and
everything under waf_patterns/** are derived/converted from third-party
sources — chiefly the OWASP Core Rule Set
(Apache-2.0), plus public bad-bot and referrer-spam lists — and are
redistributed under those upstream licenses, not under MIT. See
THIRD_PARTY_NOTICES.md for the source-by-source
breakdown and LICENSES/ for the required license texts.
Resources
- OWASP Core Rule Set
- ModSecurity
- Nginx · Apache HTTPD · Traefik · HAProxy
- Bad-bot & referrer-spam sources — Crawler-Detect, nginx-ultimate-bad-bot-blocker, referrer-spam-blacklist