- 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>
170 lines
6.0 KiB
Markdown
170 lines
6.0 KiB
Markdown
# 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>
|