Back to Article List

CrowdSec AppSec on nginx: An open source WAF setup

CrowdSec AppSec on nginx: An open source WAF setup - CrowdSec AppSec on nginx: An open source WAF setup

On December 3rd 2025 a critical React Server Components flaw nicknamed React2Shell went public: unauthenticated remote code execution in a framework a huge slice of the web's frontends depend on. CrowdSec shipped vpatch-CVE-2025-55182 to the hub within hours of the disclosure, and their writeup of that response is worth your time. Anyone running the AppSec component was one cscli hub upgrade away from blocking exploitation attempts before most teams had finished reading the advisory.

That's the case for the CrowdSec WAF in one story. Log-based scenarios, the classic CrowdSec mode, see an attack after the web server has already answered. The AppSec component moves inspection inline: nginx forwards each request to a local CrowdSec endpoint before passing it to your app, and a malicious request dies as a 403 without your application ever parsing it.

This guide wires the whole thing on Ubuntu 24.04 with nginx, using the two-layer rule setup I run in production. If you're weighing this against a network IDS, my Suricata vs CrowdSec comparison covers where each one earns its place.

Prerequisites and the nginx bouncer

You need a running Security Engine on the 1.7 line; the CrowdSec install walkthrough gets you there on Debian or Ubuntu in about ten minutes. Then add the bouncer:

sudo apt install crowdsec-nginx-bouncer

It's a Lua bouncer that hooks nginx's access_by_lua phase, checks each client against active ban decisions and, once we switch AppSec on, forwards requests for inspection. The installer registers it with the local API on your behalf. Worth noting for fresh builds: LumaDock offers an nginx + CrowdSec template at ordering time that deploys this exact pairing in seconds, engine and WAF-capable bouncer wired from first boot, so on a new VPS you can jump straight to the rule layers below.

Enable the AppSec component

The AppSec component ships inside the engine; it needs rules and an acquisition to wake up. Install both rule collections:

sudo cscli collections install crowdsecurity/appsec-virtual-patching
sudo cscli collections install crowdsecurity/appsec-crs

Then create the acquisition that starts the listener, exactly as the virtual patching and CRS guide documents:

# /etc/crowdsec/acquis.d/appsec.yaml
appsec_configs:
  - crowdsecurity/appsec-default
  - crowdsecurity/crs
labels:
  type: appsec
listen_addr: 127.0.0.1:7422
source: appsec
sudo systemctl restart crowdsec

The component now listens on 127.0.0.1:7422. Point the bouncer at it by setting APPSEC_URL=http://127.0.0.1:7422 in /etc/crowdsec/bouncers/crowdsec-nginx-bouncer.conf, then reload nginx. The same file carries a failure-action setting that decides what happens when the AppSec endpoint is unreachable, fail open or fail closed. I run fail open on anything user-facing, because a hung WAF taking the whole site down is a worse Tuesday than a brief inspection gap. Fail closed belongs on admin panels and other low-traffic, high-value paths.

How the two rule layers split the work

Layer one is crowdsecurity/appsec-virtual-patching, running in-band. These rules are evaluated synchronously before the request proceeds, and they block on match. They target specific known CVEs plus the permanent background noise of probes for /.env files, exposed .git directories and their cousins. Because each rule matches one narrow exploit pattern, false positives sit near zero, which is what makes inline blocking safe to leave on.

Layer two is crowdsecurity/appsec-crs: the OWASP Core Rule Set, delivered through the Coraza engine, running out-of-band. Requests get analyzed asynchronously after the response has already gone out, so it adds nothing to response time. Matches feed the crowdsecurity/crowdsec-appsec-outofband scenario, which bans an IP after five rule violations. The attacker gets a handful of free probes and then loses access to everything the server runs, which is a trade I'll take every day over inline CRS false positives.

Why CRS ships non-blocking and when I move it in-band

Generic rulesets and false positives are inseparable. CRS will flag a legitimate user pasting an SQL snippet into a support form, a base64 blob in a cookie, all sorts of ordinary weirdness, and a WAF that inline-blocks those on day one gets disabled by day three. CrowdSec's default (detect asynchronously, ban only repeat offenders) is the right one, and the maintainers have been explicit that out-of-band is the intended default for CRS. My rule of thumb: run it out-of-band for two or three weeks, read what fires via cscli alerts inspect, then move CRS in-band only for paths that never receive user-generated content. Admin panels and login endpoints are the usual candidates. The docs cover the blocking variant when you get there.

Test the WAF with a .env probe

curl -I http://YOUR_SERVER_IP/.env

Expect HTTP/1.1 403 Forbidden. That's the in-band layer answering; the request never touched your application. For the out-of-band layer, the docs ship a set of CRS trigger payloads (script tags and SQL fragments in query strings), and you should fire those from a disposable IP because five of them earn a real four-hour ban. Then look at what got recorded:

sudo cscli alerts list
sudo cscli metrics

Alerts show the offending URIs and matched rule IDs, and metrics grow an appsec section once traffic flows through the component. Two pointers for later: if a legitimate user ever reports hitting a 403 wall, that's a decision to find and lift, covered in fixing the CrowdSec access forbidden page, and if you're nervous about enabling any of this on a production box, my safe rollout guide shows how to watch rules fire in simulation before they're allowed to bite.

WordPress rules and the CVE Explorer

If the box serves WordPress, add the appsec-wordpress collection, virtual patching aimed at the most-exploited WordPress CVEs. WordPress plugins produce vulnerabilities at a pace nginx core never will, and this collection exists because of it.

A related aside I find myself recommending a lot: CrowdSec's CVE Explorer, launched in August 2025, scores 400+ CVEs against real exploitation data observed across the network. When a scary advisory lands, it tells you if anyone is exploiting the thing in the wild yet, which beats triaging from CVSS scores alone. I check it before deciding what gets patched tonight versus this weekend.

Resource cost and the limits of virtual patching

Honesty section. AppSec adds a processing hop: every request makes a loopback round trip to port 7422 before nginx proxies it onward. The in-band rule set is deliberately lean and the CRS work happens off the request path, so on small VPSes with moderate traffic the overhead disappears into the noise; I run this on 2 vCPU machines fronting six-figure daily request counts without it showing on a graph. If you're pushing serious traffic through one box, benchmark before and after like you would with any middleware.

Last thing, and I mean it: a virtual patch is a tourniquet. vpatch-CVE-2025-55182 bought React shops the hours they needed, and the rule shielding your outdated plugin buys you the same, and none of it makes the vulnerable code any less vulnerable. Attackers eventually find encodings and paths rule authors didn't anticipate. Patch the application; let AppSec own the gap between disclosure and your next maintenance window, because that gap is where it's genuinely unbeatable.

Your idea deserves better hosting

24/7 support 30-day money-back guarantee Cancel anytime
Billing Cycle

VPS.S1

56.86 kr Save  17 %
47.37 kr Monthly
  • 2 vCPU AMD EPYC
  • 2 GB RAMMEMORY
  • 30 GB NVMeSTORAGE
  • Unmetered bandwidth
  • IPv4 & IPv6IPv6 is currently unavailable in France, Finland or the Netherlands. included

VPS.S3

141.74 kr Save  33 %
94.47 kr Monthly
  • 4 vCPU AMD EPYC
  • 6 GB RAMMEMORY
  • 70 GB NVMeSTORAGE
  • Unmetered bandwidth
  • IPv4 & IPv6IPv6 is currently unavailable in France, Finland or the Netherlands. included

EPYC VPS.P1

85.01 kr Save  22 %
66.10 kr Monthly
  • 2 vCPU AMD EPYC
  • 4 GB RAMMEMORY
  • 40 GB NVMeSTORAGE
  • Unmetered bandwidth
  • IPv4 & IPv6IPv6 is currently unavailable in France, Finland or the Netherlands. included
  • Free auto backupsIncludes one backup slot you can set to run daily, weekly or monthly.

EPYC VPS.P2

160.66 kr Save  24 %
122.83 kr Monthly
  • 2 vCPU AMD EPYC
  • 8 GB RAMMEMORY
  • 80 GB NVMeSTORAGE
  • Unmetered bandwidth
  • IPv4 & IPv6IPv6 is currently unavailable in France, Finland or the Netherlands. included
  • Free auto backupsIncludes one backup slot you can set to run daily, weekly or monthly.

EPYC VPS.P4

283.58 kr Save  23 %
217.39 kr Monthly
  • 4 vCPU AMD EPYC
  • 16 GB RAMMEMORY
  • 160 GB NVMeSTORAGE
  • Unmetered bandwidth
  • IPv4 & IPv6IPv6 is currently unavailable in France, Finland or the Netherlands. included
  • Free auto backupsIncludes one backup slot you can set to run daily, weekly or monthly.

EPYC VPS.P5

378.14 kr Save  25 %
283.58 kr Monthly
  • 8 vCPU AMD EPYC
  • 16 GB RAMMEMORY
  • 180 GB NVMeSTORAGE
  • Unmetered bandwidth
  • IPv4 & IPv6IPv6 is currently unavailable in France, Finland or the Netherlands. included
  • Free auto backupsIncludes one backup slot you can set to run daily, weekly or monthly.

EPYC VPS.P6

567.26 kr Save  25 %
425.42 kr Monthly
  • 8 vCPU AMD EPYC
  • 32 GB RAMMEMORY
  • 200 GB NVMeSTORAGE
  • Unmetered bandwidth
  • IPv4 & IPv6IPv6 is currently unavailable in France, Finland or the Netherlands. included
  • Free auto backupsIncludes one backup slot you can set to run daily, weekly or monthly.

EPYC VPS.P7

661.82 kr Save  29 %
472.70 kr Monthly
  • 16 vCPU AMD EPYC
  • 32 GB RAMMEMORY
  • 240 GB NVMeSTORAGE
  • Unmetered bandwidth
  • IPv4 & IPv6IPv6 is currently unavailable in France, Finland or the Netherlands. included
  • Free auto backupsIncludes one backup slot you can set to run daily, weekly or monthly.

Genoa VPS.G2

237.20 kr Save  20 %
189.74 kr Monthly
  • 2 vCPUAMD EPYC Genoa 4th generation 9xx4 with 3.25 GHz or similar, on Zen 4 architecture. AMD EPYC G4
  • 4 GB DDR5MEMORY
  • 50 GB NVMeSTORAGE
  • Unmetered bandwidth
  • IPv4 & IPv6IPv6 is currently unavailable in France, Finland or the Netherlands. included
  • Free auto backupsIncludes one backup slot you can set to run daily, weekly or monthly.

Genoa VPS.G4

427.04 kr Save  22 %
332.12 kr Monthly
  • 4 vCPUAMD EPYC processor with dedicated vCPU cores, on enterprise server hardware. AMD EPYC G4
  • 8 GB DDR5MEMORY
  • 100 GB NVMeSTORAGE
  • Unmetered bandwidth
  • IPv4 & IPv6IPv6 is currently unavailable in France, Finland or the Netherlands. included
  • Free auto backupsIncludes one backup slot you can set to run daily, weekly or monthly.

Genoa VPS.G6

854.18 kr Save  22 %
664.34 kr Monthly
  • 8 vCPUAMD EPYC processor with dedicated vCPU cores, on enterprise server hardware. AMD EPYC G4
  • 16 GB DDR5MEMORY
  • 200 GB NVMeSTORAGE
  • Unmetered bandwidth
  • IPv4 & IPv6IPv6 is currently unavailable in France, Finland or the Netherlands. included
  • Free auto backupsIncludes one backup slot you can set to run daily, weekly or monthly.

Genoa VPS.G7

1518.61 kr Save  22 %
1186.39 kr Monthly
  • 8 vCPUAMD EPYC processor with dedicated vCPU cores, on enterprise server hardware. AMD EPYC G4
  • 32 GB DDR5MEMORY
  • 250 GB NVMeSTORAGE
  • Unmetered bandwidth
  • IPv4 & IPv6IPv6 is currently unavailable in France, Finland or the Netherlands. included
  • Free auto backupsIncludes one backup slot you can set to run daily, weekly or monthly.

AMD Ryzen VPS.R1

161.27 kr Save  18 %
132.79 kr Monthly
  • 1 dedicated CPU AMD Ryzen 9 7950X with 4.5 GHz or similar, on Zen 4 architecture. vCPU
  • 4 GB DDR5MEMORY
  • 50 GB NVMeSTORAGE
  • Unmetered bandwidth
  • IPv4 & IPv6 included IPv6 support is currently unavailable in France, Finland or the Netherlands.
  • Auto backup included

AMD Ryzen VPS.R2

284.66 kr Save  17 %
237.20 kr Monthly
  • 2 dedicated CPUs AMD Ryzen 9 7950X with 4.5 GHz or similar, on Zen 4 architecture. vCPU
  • 8 GB DDR5MEMORY
  • 100 GB NVMeSTORAGE
  • Unmetered bandwidth
  • IPv4 & IPv6 included IPv6 support is currently unavailable in France, Finland or the Netherlands.
  • Auto backup included

AMD Ryzen VPS.R4

1044.02 kr Save  18 %
854.18 kr Monthly
  • 8 dedicated CPUs AMD Ryzen 9 7950X with 4.5 GHz or similar, on Zen 4 architecture. vCPU
  • 32 GB DDR5MEMORY
  • 400 GB NVMeSTORAGE
  • Unmetered bandwidth
  • IPv4 & IPv6 included IPv6 support is currently unavailable in France, Finland or the Netherlands.
  • Auto backup included

My answers to other questions

Does AppSec inspect HTTPS traffic?

Yes. Inspection happens inside nginx after TLS termination, so the AppSec component sees the decrypted request without ever needing your certificates or keys. Nothing about the TLS setup changes, and there's no man-in-the-middle arrangement to maintain.