Fail2ban wird als Erstes installiert, und dabei bleibt es meistens: Das Paket ist da, der Dienst läuft, sshd ist offenbar abgesichert. Ein halbes Jahr später stellt sich heraus, dass das Jail eine Datei liest, die es auf diesem System gar nicht gibt — und dass alles Übrige, also Mail, Verwaltungsoberfläche und das Anmeldeformular der Website, nie abgesichert war.
Sehen wir uns an, was auf einem gewöhnlichen VPS mit Website wirklich zu aktivieren ist, welche Zahlen dort hingehören und wie Sie sich vergewissern, dass ein Jail arbeitet und nicht bloß in der Konfiguration steht.
Prüfen Sie zuerst, ob sshd überhaupt etwas fängt
Ein Befehl:
sudo fail2ban-client status sshd
In der Ausgabe stehen die Zeilen Currently failed, Total failed und Total banned. Ist Total failed auf einem Server, der mindestens einen Tag im Internet steht, gleich null, arbeitet das Jail nicht. Gleichen Sie mit der Wirklichkeit ab:
sudo lastb | wc -l
Tausende Fehlversuche in lastb bei Nullen in Fail2ban bedeuten genau eines: Der Filter schaut an der falschen Stelle.
Die häufigste Ursache ist Debian 12. Dort wird rsyslog nicht mehr standardmäßig installiert, die Datei /var/log/auth.log existiert schlicht nicht, und das mitgelieferte sshd-Jail ist auf diese Datei eingestellt. Eine Fehlermeldung gibt es dabei nicht: Der Dienst startet, der Status wird angezeigt, die Zähler bleiben auf null. Abhilfe schafft der Wechsel auf das systemd-Journal:
[sshd]
enabled = true
backend = systemd
Die zweite Möglichkeit ist, rsyslog als Paket zurückzuholen, falls Ihnen ein textuelles auth.log für andere Werkzeuge wichtig ist. Ubuntu 24.04 verhält sich genauso.
Wohin die Einstellungen gehören
/etc/fail2ban/jail.conf bleibt unangetastet — sie wird bei einem Paket-Update überschrieben, und alle dort vorgenommenen Änderungen verschwinden eines Tages stillschweigend. Ihre eigenen Einstellungen kommen in /etc/fail2ban/jail.local; diese Datei wird zuletzt gelesen und überschreibt die gemeinsame.
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 203.0.113.25
bantime = 1h
findtime = 10m
maxretry = 5
backend = systemd
ignoreip mit Ihrer eigenen Adresse ist kein Luxus, sondern eine Absicherung: Sich mit einem Tippfehler selbst auszusperren geht schneller, als man denkt. Haben Sie keine feste Adresse, halten Sie einen zweiten Weg hinein bereit — die Konsole oder VNC beim Hoster.
Das Jail, das die Lage verändert: recidive
Ein gewöhnliches Jail hat ein kurzes Gedächtnis: fünf Versuche in zehn Minuten, eine Stunde Sperre, und eine Stunde später beginnt alles von vorn. Ein Bot lebt damit ausgezeichnet und kommt morgen und übermorgen wieder. recidive schließt genau diese Lücke: Es liest nicht das Systemprotokoll, sondern das eigene von Fail2ban — sperrt also jene, die Fail2ban bereits gesperrt hat.
[recidive]
enabled = true
bantime = 1w
findtime = 1d
maxretry = 5
Zu lesen ist das so: „fünfmal an einem Tag gesperrt — für eine Woche weg“. Das Jail braucht die Datei /var/log/fail2ban.log; haben Sie Fail2bans eigene Protokollierung auf syslog umgestellt, benötigt auch recidive ein backend = systemd.
Der praktische Effekt dieses einen Jails ist meist deutlicher als das Feintuning aller übrigen: Die Stammgäste fallen weg, und in den Protokollen bleibt nur frischer Hintergrund.
Was sonst noch, wenn auf dem Server eine Website läuft
Nach abnehmendem Nutzen:
nginx-http-authoderapache-auth— Passwortraten gegen die Basic-Authentifizierung. Nötig, wenn ein Verwaltungsbereich oder eine Staging-Umgebung hinter einem Webserver-Passwort liegt;nginx-botsearch— das Abklappern bekannter Pfade:/wp-login.php,/phpmyadmin,/.env. Das ist kein Einbruch, sondern Aufklärung — und genau sie geht allem Weiteren voraus;nginx-limit-req— funktioniert nur, wenn in Nginx selbst einelimit_req_zonedefiniert ist; ohne sie ist das Jail aktiviert und nutzlos;postfix-saslunddovecot— unverzichtbar, wenn Sie eigene Mail betreiben. Das Erraten von Postfach-Passwörtern läuft ununterbrochen und wird üblicherweise von niemandem beobachtet.
[nginx-botsearch]
enabled = true
logpath = /var/log/nginx/access.log
Eine eigene Geschichte ist das Anmeldeformular der Website selbst. Die Anwendung führt kein eigenes Protokoll fehlgeschlagener Anmeldungen, und im access.log sieht ein Fehlversuch aus wie ein gewöhnlicher POST mit Status 200 oder 302 — von einem erfolgreichen durch keinen allgemeinen Filter zu unterscheiden. Es gibt zwei Wege: die Anwendung dazu bringen, Fehlversuche nach syslog zu schreiben (für die meisten Content-Management-Systeme gibt es dafür ein Plugin), oder die Anfragefrequenz zur Anmeldeseite begrenzen. Das Zweite ist ein Begrenzer, kein Detektor, und das sollte man vorher wissen.
Die Zahlen
bantime = 10m ist die Voreinstellung, wegen der Fail2ban oft für nutzlos gehalten wird: Zehn Minuten genügen einem Bot, um zurückzukehren. Eine Stunde für die erste Sperre plus recidive für eine Woche wirkt weit besser als dauerhafte Sperren, die sich mit der Zeit in eine kilometerlange Regelliste verwandeln.
maxretry = 3 für SSH ist ein zuverlässiger Weg, sich selbst auszusperren. Fünf Versuche in zehn Minuten schneiden das Passwortraten genauso gut ab.
Langsames Raten — ein Versuch alle fünf Minuten — fällt niemals in das findtime-Fenster. Das ist kein Grund, das Fenster auf einen Tag zu strecken: Sie bekommen Fehlalarme gegen die eigenen Mitarbeiter. Gegen langsames Raten wirkt kein Schwellenwert, sondern deaktivierte Passwortanmeldung.
Vergewissern Sie sich, dass die Sperre bei den Paketen ankommt
Fail2ban ruft lediglich einen externen Befehl auf. Passt banaction nicht zu dem, was den Datenverkehr tatsächlich filtert, füllt sich das Protokoll mit munteren Ban 198.51.100.7-Zeilen, während die Pakete weiter eintreffen. Debian 12 verwendet standardmäßig nftables, bei aktivem UFW ist banaction = ufw richtig. Zur Prüfung:
sudo nft list ruleset | grep -c f2b
sudo iptables -S | grep f2b
Mindestens einer der beiden Befehle muss Regeln zeigen. Und den Filter selbst können Sie prüfen, ohne auf einen Angriff zu warten:
sudo fail2ban-regex systemd-journal /etc/fail2ban/filter.d/sshd.conf
Unten in der Ausgabe steht, wie viele Zeilen übereingestimmt haben. Null bedeutet, dass Filter und Protokoll nicht zueinander finden — weiter zu konfigurieren ist dann sinnlos.
Was Fail2ban nicht leistet
Es schützt nicht vor verteiltem Passwortraten: Tausend Adressen mit je einem Versuch erreichen unter keinen Einstellungen einen Schwellenwert. Es behebt die Ursache nicht — eine gesperrte Adresse macht ein schwaches Passwort nicht besser. Und es weiß nichts über Reputation: Eine Adresse, die gestern fremde Server angegriffen hat, ist für es sauber, bis sie sich Ihrem zuwendet. Daher die Kombination aus der Praxis: Schlüssel statt Passwörter, Fail2ban als Lärmbegrenzer und eine gemeinsame Sperrliste (CrowdSec) als Wissen aus fremder Erfahrung.
Ein eigenes Problem ist, dass man all das gelegentlich ansehen muss. Niemand tippt wochenlang fail2ban-client status für jedes Jail einzeln, und eine steigende Zahl von Sperren fällt auf, wenn schon etwas kaputt ist. Auf den Demo-Seiten unten liegen dieselben Daten auf einer Seite: die Liste der Jails, wer gerade gesperrt ist und woher die Versuche kommen.