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>
This commit is contained in:
schiwagoaandClaude Opus 5.5 committed 2026-10-25 20:41:08 +01:00
commit d7dcd9d6b1
29 files changed
+1163

No files matched your search

@@ -0,0 +1,10 @@
[25/Oct/2026:12:13:14 +0000] - 404 404 - GET https example.com "/.env" [Client 198.51.100.7] [Length 150] [Gzip -] [Sent-to 172.16.1.10] "Mozilla/5.0" "-"
[25/Oct/2026:12:13:15 +0000] - - 404 - GET https example.com "/.git/config" [Client 198.51.100.7] [Length 150] [Gzip -] [Sent-to 172.16.1.10] "Mozilla/5.0" "-"
[25/Oct/2026:12:13:16 +0000] - 403 403 - GET https example.com "/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php" [Client 198.51.100.8] [Length 150] [Gzip -] [Sent-to 172.16.1.10] "curl/8.5.0" "-"
[25/Oct/2026:12:13:17 +0000] - 404 404 - POST http example.com "/cgi-bin/luci" [Client 198.51.100.9] [Length 150] [Gzip -] [Sent-to 172.16.1.10] "-" "-"
[25/Oct/2026:12:13:18 +0000] - 404 404 - GET https example.com "/backup.sql.gz" [Client 2001:db8::7] [Length 150] [Gzip -] [Sent-to 172.16.1.10] "Mozilla/5.0" "-"
[25/Oct/2026:12:13:19 +0000] - 401 401 - GET https example.com "/actuator/env" [Client 198.51.100.10] [Length 150] [Gzip -] [Sent-to 172.16.1.10] "Mozilla/5.0" "-"
198.51.100.11 - - [25/Oct/2026:12:14:01 +0000] "GET / HTTP/1.1" 444 0 "-" "curl/8.5.0"
198.51.100.12 - - [25/Oct/2026:12:14:02 +0000] "\x16\x03\x01\x02\x00\x01\x00" 400 157 "-" "-"
198.51.100.13 - - [25/Oct/2026:12:14:03 +0000] "GET /.env HTTP/1.1" 301 166 "-" "Mozilla/5.0"
198.51.100.14 - - [25/Oct/2026:12:14:04 +0000] "GET /phpmyadmin/index.php HTTP/1.1" 301 166 "-" "Mozilla/5.0"
@@ -0,0 +1,7 @@
[25/Oct/2026:12:13:14 +0000] - 200 200 - GET https example.com "/.env" [Client 198.51.100.7] [Length 150] [Gzip -] [Sent-to 172.16.1.10] "Mozilla/5.0" "-"
[25/Oct/2026:12:13:15 +0000] - 404 404 - GET https example.com "/favicon.ico" [Client 198.51.100.7] [Length 150] [Gzip -] [Sent-to 172.16.1.10] "Mozilla/5.0" "-"
[25/Oct/2026:12:13:16 +0000] - 404 404 - GET https cloud.example.com "/index.php/apps/files/preview" [Client 198.51.100.8] [Length 150] [Gzip -] [Sent-to 172.16.1.10] "Nextcloud-android" "-"
[25/Oct/2026:12:13:17 +0000] - 304 304 - GET https example.com "/assets/app.js" [Client 198.51.100.9] [Length 0] [Gzip -] [Sent-to 172.16.1.10] "Mozilla/5.0" "-"
[25/Oct/2026:12:13:18 +0000] - 404 404 - GET https example.com "/environment-info" [Client 198.51.100.10] [Length 150] [Gzip -] [Sent-to 172.16.1.10] "Mozilla/5.0" "-"
198.51.100.11 - - [25/Oct/2026:12:14:01 +0000] "GET / HTTP/1.1" 301 166 "-" "Mozilla/5.0 (compatible; Googlebot/2.1)"
198.51.100.12 - - [25/Oct/2026:12:14:02 +0000] "GET /robots.txt HTTP/1.1" 301 166 "-" "Mozilla/5.0"
@@ -0,0 +1,4 @@
[25/Oct/2026:12:13:14 +0000] - 200 200 - POST https blog.example.com "/wp-login.php" [Client 198.51.100.7] [Length 4500] [Gzip -] [Sent-to 172.16.1.20] "Mozilla/5.0" "-"
[25/Oct/2026:12:13:15 +0000] - 302 302 - POST https blog.example.com "/wp-login.php?redirect_to=%2Fwp-admin%2F" [Client 198.51.100.7] [Length 0] [Gzip -] [Sent-to 172.16.1.20] "Mozilla/5.0" "-"
[25/Oct/2026:12:13:16 +0000] - 200 200 - POST https blog.example.com "/xmlrpc.php" [Client 198.51.100.8] [Length 300] [Gzip -] [Sent-to 172.16.1.20] "-" "-"
[25/Oct/2026:12:13:17 +0000] - - 403 - POST https blog.example.com "/wp-login.php" [Client 2001:db8::8] [Length 150] [Gzip -] [Sent-to 172.16.1.20] "Mozilla/5.0" "-"
@@ -0,0 +1,3 @@
[25/Oct/2026:12:13:14 +0000] - 200 200 - GET https blog.example.com "/wp-login.php" [Client 198.51.100.7] [Length 4500] [Gzip -] [Sent-to 172.16.1.20] "Mozilla/5.0" "-"
[25/Oct/2026:12:13:15 +0000] - 200 200 - POST https blog.example.com "/wp-admin/admin-ajax.php" [Client 198.51.100.7] [Length 50] [Gzip -] [Sent-to 172.16.1.20] "Mozilla/5.0" "-"
[25/Oct/2026:12:13:16 +0000] - 200 200 - POST https blog.example.com "/wp-comments-post.php" [Client 198.51.100.8] [Length 50] [Gzip -] [Sent-to 172.16.1.20] "Mozilla/5.0" "-"
+25
View File
@@ -0,0 +1,25 @@
#!/bin/sh
# Runs fail2ban-regex against the sample logs:
# <filter>.match.log every line must match
# <filter>.nomatch.log no line may match
set -u
cd "$(dirname "$0")/filter-samples" || exit 1
rc=0
matched() { fail2ban-regex "$1" "/etc/fail2ban/filter.d/$2.conf" | sed -n 's/^Lines: .* \([0-9]*\) matched.*/\1/p'; }
lines() { grep -cv '^#' "$1"; }
for f in *.match.log; do
filter=${f%.match.log}
want=$(lines "$f"); got=$(matched "$f" "$filter")
if [ "$got" = "$want" ]; then echo "ok $f ($got/$want)"; else echo "FAIL $f ($got/$want matched)"; rc=1; fi
done
for f in *.nomatch.log; do
filter=${f%.nomatch.log}
got=$(matched "$f" "$filter")
if [ "$got" = "0" ]; then echo "ok $f (0 matched)"; else echo "FAIL $f ($got matched, expected 0)"; rc=1; fi
done
exit $rc