- 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>
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-managerundjlesage/nginx-proxy-manager - Sperrt in der Kette
DOCKER-USERauf allen Ports (Docker leitet veröffentlichte Ports anINPUTvorbei) - 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 amd64undarm64, Basis crazymax/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
docker ps --format '{{.Names}}\t{{.Image}}' | grep -i proxy
Den Containernamen einsetzen:
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:
ls /home/docker-projekte/nginx/data/log | grep proxy-host | head
2. Projektordner anlegen
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
nano .env
Mindestens NPM_LOG_DIR, NPM_LOG_DIR2 und WHITELIST (eigene öffentliche IP, LAN, VPN,
Monitoring) setzen. Alle Variablen: docs/configuration.md.
4. Konfiguration prüfen (startet nichts)
docker compose run --rm npm-scanner check
Erwartet: die erzeugte jail.local und am Ende OK: configuration test is successful.
5. Starten
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
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:
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.
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 | alle Variablen der .env, eigene Jails und Filter |
| Betrieb | Logs, Updates, Backup, Fehlerbehebung, Rückbau |
| Sicherheit | Rechte des Containers, Melden von Schwachstellen |
Lizenz
MIT. Basiert auf crazymax/fail2ban (MIT) und fail2ban (GPL-2.0).
🏰 Website · 🐘 Mastodon · 🔒 Datenschutz · 💬 Support
© Thomas Werner Schwaighofer · retronerd.AT · MIT Lizenz
