# CrowdSec WAF QuickStart for NPMplus

Protect web applications running behind [NPMplus](https://github.com/ZoeyVid/NPMplus) (an enhanced Nginx Proxy Manager fork with built-in CrowdSec support) with CrowdSec's [AppSec (WAF) Component](https://docs.crowdsec.net/docs/next/appsec/intro.md#introduction).

This flow is mostly Docker Compose work: you download the NPMplus compose file, edit a few values, add an AppSec acquisition, start the stack, and enable AppSec from the NPMplus admin UI.

## Prerequisites[​](#prerequisites "Direct link to Prerequisites")

* **Docker** and **Docker Compose** installed.
* Ports **80/TCP, 443/TCP, 443/UDP** exposed to the internet; **81/TCP** available for the admin interface (can stay internal).
* A text editor and `curl` available on the host.

## 1. Download the NPMplus compose file[​](#1-download-the-npmplus-compose-file "Direct link to 1. Download the NPMplus compose file")

SHCOPY

```
curl -L https://raw.githubusercontent.com/ZoeyVid/NPMplus/refs/heads/develop/compose.yaml \
    -o compose.yaml
```

## 2. Edit `compose.yaml`[​](#2-edit-composeyaml "Direct link to 2-edit-composeyaml")

Open the file and apply the following changes — none of these can be automated because you need to choose values for your environment:

* **NPMplus service** — set the environment variables:

  <!-- -->

  * `TZ` — your timezone (e.g. `Europe/Berlin`).
  * `ACME_EMAIL` — your email for Let's Encrypt (e.g. `admin@example.org`).
  * `LOGROTATE=true` — uncomment this line. Required for CrowdSec to parse NPMplus logs.

* **CrowdSec service** — uncomment the `crowdsec` service block. Leave the `openappsec` line commented (`appsec` and `openappsec` are different things).

## 3. Add the AppSec acquisition[​](#3-add-the-appsec-acquisition "Direct link to 3. Add the AppSec acquisition")

Create the acquisition file on the host; the path must match how you mount the CrowdSec config volume in `compose.yaml` (the default NPMplus compose uses `/opt/crowdsec/conf`):

SHCOPY

```
sudo mkdir -p /opt/crowdsec/conf/acquis.d
sudo tee /opt/crowdsec/conf/acquis.d/npmplus.yaml > /dev/null <<'EOF'
filenames:
  - /opt/npmplus/nginx/*.log
labels:
  type: npmplus
---
filenames:
  - /opt/npmplus/nginx/*.log
labels:
  type: modsecurity
---
listen_addr: 0.0.0.0:7422
appsec_configs:
  - crowdsecurity/appsec-default
name: appsec
source: appsec
labels:
  type: appsec
EOF
```

The first two blocks parse NPMplus access logs; the third turns on the AppSec Component on `0.0.0.0:7422` (needed because CrowdSec is inside a container — exposure is still limited to the Docker network, **not** the internet).

info

The upstream `npmplus.yaml` can evolve; the latest reference is in the [NPMplus repo](https://github.com/ZoeyVid/NPMplus).

## 4. Start the stack[​](#4-start-the-stack "Direct link to 4. Start the stack")

SHCOPY

```
docker compose up -d
```

Install the AppSec collections inside the running CrowdSec container, then restart it so the new collections are picked up:

SHCOPY

```
docker exec crowdsec cscli collections install \
    crowdsecurity/appsec-virtual-patching \
    crowdsecurity/appsec-generic-rules
docker restart crowdsec
```

Retrieve the initial NPMplus admin password from its logs:

SHCOPY

```
sleep 60 && docker logs npmplus 2>&1 | grep -i password
```

Save this password — you'll need it in step 5.

## 5. Enable AppSec in NPMplus[​](#5-enable-appsec-in-npmplus "Direct link to 5. Enable AppSec in NPMplus")

### Generate a bouncer API key[​](#generate-a-bouncer-api-key "Direct link to Generate a bouncer API key")

SHCOPY

```
docker exec crowdsec cscli bouncers add npmplus -o raw
```

Copy the printed key.

### Configure NPMplus[​](#configure-npmplus "Direct link to Configure NPMplus")

Edit the NPMplus CrowdSec configuration file — its location depends on your compose mounts, typically `/opt/npmplus/crowdsec/crowdsec.conf`:

/opt/npmplus/crowdsec/crowdsec.conf

INI/opt/npmplus/crowdsec/crowdsec.confCOPY

```
ENABLED=true
API_KEY=<paste-the-key-from-above>
```

Restart NPMplus:

SHCOPY

```
docker restart npmplus
```

Confirm NPMplus connects to CrowdSec:

SHCOPY

```
docker logs npmplus 2>&1 | grep -i crowdsec
```

## 6. Verify[​](#6-verify "Direct link to 6. Verify")

Hit an endpoint that should trip an AppSec rule (replace `localhost` with your server's address if different):

SHCOPY

```
curl -I http://localhost/.env
```

You should get an `HTTP/1.1 403 Forbidden` response.

Check metrics inside the CrowdSec container:

SHCOPY

```
docker exec crowdsec cscli metrics show appsec
```

Example metrics output

docker exec crowdsec cscli metrics show appsec

SHdocker exec crowdsec cscli metrics show appsecCOPY

```
Appsec Metrics:
╭─────────────────┬───────────┬─────────╮
│  Appsec Engine  │ Processed │ Blocked │
├─────────────────┼───────────┼─────────┤
│ 0.0.0.0:7422/   │ 2         │ 1       │
╰─────────────────┴───────────┴─────────╯

Appsec '0.0.0.0:7422/' Rules Metrics:
╭─────────────────────────────────┬───────────╮
│             Rule ID             │ Triggered │
├─────────────────────────────────┼───────────┤
│ crowdsecurity/vpatch-env-access │ 1         │
╰─────────────────────────────────┴───────────╯
```

What just happened?

1. `curl` hit NPMplus at `/.env`.
2. The NPMplus bouncer forwarded the request to the AppSec Component inside the Docker network (on `crowdsec:7422`).
3. AppSec matched the [`vpatch-env-access`](https://app.crowdsec.net/hub/author/crowdsecurity/appsec-rules/vpatch-env-access) rule and answered `403`.
4. NPMplus served the ban page.

## Log into the NPMplus admin UI[​](#log-into-the-npmplus-admin-ui "Direct link to Log into the NPMplus admin UI")

Open `https://<server-ip>:81` and log in with the `ACME_EMAIL` you set in step 2 and the password you saved in step 4. You'll be prompted to change both on first login.

## Monitor in the Console[​](#monitor-in-the-console "Direct link to Monitor in the Console")

If you haven't enrolled the Security Engine yet, follow [how to enroll in the Console](https://docs.crowdsec.net/u/getting_started/post_installation/console.md). Once enrolled, AppSec alerts appear alongside the rest of your alerts:

![appsec-console](/assets/images/appsec_console-59b5f39cf3f7fc002e61539c0e866f23.png)

## Next steps[​](#next-steps "Direct link to Next steps")

* Monitor WAF alerts with `docker exec crowdsec cscli alerts list` or in the [CrowdSec Console](https://app.crowdsec.net).
* Review the [AppSec troubleshooting guide](https://docs.crowdsec.net/docs/next/appsec/troubleshooting.md) if you need to investigate or refine the deployment.
* Explore [WAF deployment strategies](https://docs.crowdsec.net/docs/next/appsec/advanced_deployments.md), [rules syntax](https://docs.crowdsec.net/docs/next/appsec/rules_syntax.md), [rule creation](https://docs.crowdsec.net/docs/next/appsec/create_rules.md), and [benchmarks](https://docs.crowdsec.net/docs/next/appsec/benchmark.md) to go further.
