Files
npm-scanner/README.md
T
schiwagoaandClaude Opus 5.5 d7dcd9d6b1 Initial version: npm-scanner image, filters, entrypoint, watcher, testbed
- Image based on crazymax/fail2ban:1.1.1 with inotify-tools
- Filters npm-scanner and npm-wplogin, tested with fail2ban-regex in the build
- jail.local generated from .env, optional npm-wplogin and recidive
- Watcher reloads the jails when NPM creates a new proxy host log
- check command, docs, testbed for LXC

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 20:41:08 +01:00

170 lines
6.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# npm-scanner
fail2ban als Docker-Container für den **Nginx Proxy Manager (NPM)**: sperrt IPs, die nach
Schwachstellen scannen (`/.env`, `/.git/`, `phpinfo`, `/vendor/phpunit` …), direkt in der
Firewall des Hosts.
- Liest die Access-Logs des NPM nur lesend – für `jc21/nginx-proxy-manager` und `jlesage/nginx-proxy-manager`
- Sperrt in der Kette **`DOCKER-USER`** auf allen Ports (Docker leitet veröffentlichte Ports an `INPUT` vorbei)
- **3 Treffer in 1 Stunde → 24 h**, bei Wiederholung steigend bis **4 Wochen**
- Optional: WordPress-Login-Schutz (`npm-wplogin`) und Wiederholungstäter (`recidive`)
- Neue Proxy-Hosts im NPM werden automatisch überwacht, ohne Neustart
- Alle Einstellungen in einer `.env`, Filter werden beim Image-Build getestet
- `amd64` und `arm64`, Basis [crazymax/fail2ban](https://github.com/crazy-max/docker-fail2ban)
```
Internet ──▶ Host-Firewall ──DOCKER-USER──▶ NPM (Docker) ──▶ Dienste
▲ │ schreibt
│ sperrt ▼
npm-scanner ◀──── liest ──── proxy-host-*_access.log
(fail2ban, network_mode: host)
```
Bewusst **nicht** gezählt: reine 404 (Nextcloud-/Matrix-Clients erzeugen legitim viele davon)
und Weiterleitungen am Default-Host ohne Scanner-Pfad (Suchmaschinen).
## Quellen
| | |
|---|---|
| Repository | https://git.retronerd.at/schiwagoa/npm-scanner |
| Image | `git.retronerd.at/schiwagoa/npm-scanner` |
| Basis-Image | https://github.com/crazy-max/docker-fail2ban · https://hub.docker.com/r/crazymax/fail2ban |
| fail2ban | https://github.com/fail2ban/fail2ban |
| Nginx Proxy Manager | https://nginxproxymanager.com · https://github.com/jlesage/docker-nginx-proxy-manager |
## Voraussetzungen
- Linux-Host mit Docker Engine und Compose-Plugin (`docker compose version`)
- NPM läuft auf **demselben Host** als Container
- **Kein** fail2ban direkt auf dem Host, das dieselben NPM-Logs liest – sonst wird doppelt gesperrt
- Im LXC-Container: auf dem Proxmox-Host `pct set <id> --features nesting=1,keyctl=1`
## Installation
Alle Befehle als root.
### 1. Log-Ordner des NPM ermitteln
```bash
docker ps --format '{{.Names}}\t{{.Image}}' | grep -i proxy
```
Den Containernamen einsetzen:
```bash
docker inspect <npm-container> --format '{{range .Mounts}}{{.Source}} -> {{.Destination}}{{println}}{{end}}'
```
| Image | Container-Pfad | `NPM_LOG_DIR` | `NPM_LOG_DIR2` |
|---|---|---|---|
| `jc21/nginx-proxy-manager` | `/data` | `<Quelle von /data>/logs` | leer |
| `jlesage/nginx-proxy-manager` | `/config` | `<Quelle von /config>/log` | `<Quelle von /config>/logs` |
Bei jlesage schreiben neu gespeicherte Hosts nach `logs/`, ältere nach `log/` – deshalb beide.
Kontrolle – es müssen `proxy-host-*_access.log` erscheinen:
```bash
ls /home/docker-projekte/nginx/data/log | grep proxy-host | head
```
### 2. Projektordner anlegen
```bash
mkdir -p /home/docker-projekte/npm-scanner
cd /home/docker-projekte/npm-scanner
curl -fsSLO https://git.retronerd.at/schiwagoa/npm-scanner/raw/branch/main/docker-compose.yaml
curl -fsSL -o .env https://git.retronerd.at/schiwagoa/npm-scanner/raw/branch/main/.env.example
chmod 600 .env
```
### 3. `.env` anpassen
```bash
nano .env
```
Mindestens `NPM_LOG_DIR`, `NPM_LOG_DIR2` und **`WHITELIST`** (eigene öffentliche IP, LAN, VPN,
Monitoring) setzen. Alle Variablen: [docs/configuration.md](docs/configuration.md).
### 4. Konfiguration prüfen (startet nichts)
```bash
docker compose run --rm npm-scanner check
```
Erwartet: die erzeugte `jail.local` und am Ende `OK: configuration test is successful`.
### 5. Starten
```bash
docker compose up -d
docker compose ps
docker logs npm-scanner
```
Erwartet im Log: `[npm-scanner] log directories: …`, `[npm-newlog] watching …` und
`Jail 'npm-scanner' started`. Nach etwa 30 Sekunden steht der Container auf `healthy`.
### 6. Prüfen
```bash
docker exec npm-scanner fail2ban-client status npm-scanner
docker exec npm-scanner fail2ban-client get npm-scanner logpath
```
Nach der **ersten** Sperre hängt die Regel in `DOCKER-USER`:
```bash
iptables -S DOCKER-USER
iptables -S f2b-npm-scan
```
## Betrieb
| | |
|---|---|
| Gesperrte IPs | `docker exec npm-scanner fail2ban-client get npm-scanner banip --with-time` |
| Entsperren | `docker exec npm-scanner fail2ban-client set npm-scanner unbanip <ip>` |
| Von Hand sperren | `docker exec npm-scanner fail2ban-client set npm-scanner banip <ip>` |
| Letzte Sperren | `docker logs npm-scanner 2>&1 \| grep ' Ban ' \| tail -20` |
| Update | `docker compose pull && docker compose up -d` |
Mehr – Backup, eigene Jails, Fehlersuche, Rückbau: [docs/operations.md](docs/operations.md).
## Warum kein eigenes Docker-Netzwerk?
fail2ban muss Regeln in der Firewall **des Hosts** setzen. Deshalb läuft der Container mit
`network_mode: host` und den Capabilities `NET_ADMIN` und `NET_RAW`. In einem Bridge-Netz
würde er nur die Firewall seines eigenen Netz-Namespaces ändern. Der Container öffnet keine
Ports und liest die NPM-Logs nur lesend.
## Dokumentation
| | |
|---|---|
| [Konfiguration](docs/configuration.md) | alle Variablen der `.env`, eigene Jails und Filter |
| [Betrieb](docs/operations.md) | Logs, Updates, Backup, Fehlerbehebung, Rückbau |
| [Sicherheit](SECURITY.md) | Rechte des Containers, Melden von Schwachstellen |
## Lizenz
[MIT](LICENSE). Basiert auf [crazymax/fail2ban](https://github.com/crazy-max/docker-fail2ban) (MIT)
und [fail2ban](https://github.com/fail2ban/fail2ban) (GPL-2.0).
---
<p align="center">
🏰 <a href="https://retronerd.at">Website</a> ·
🐘 <a href="https://social.retronerd.at/@schiwagoa">Mastodon</a> ·
🔒 <a href="https://retronerd.at/datenschutzerklaerung/">Datenschutz</a> ·
💬 <a href="https://helpdesk.retronerd.at/open.php">Support</a>
</p>
<p align="center">
<img src="https://dl.retronerd.at/Bilder/cat-footer.png" alt="" width="100%">
</p>
<p align="center">© Thomas Werner Schwaighofer · retronerd.AT · <a href="LICENSE">MIT Lizenz</a></p>