fail2ban einrichten ist in zehn Minuten erledigt: Paket installieren, eine jail.local anlegen, SSH-Jail einschalten, fertig. Diese zehn Minuten stehen in jeder Anleitung. Was dort fast nie steht: wie viel fail2ban danach tatsächlich abfängt, welche Angreifer es gar nicht sieht und ob eine Sperre überhaupt etwas bewirkt, wenn sie nach einer Stunde wieder aufgehoben wird.
Wir betreiben fail2ban seit Monaten auf unserem eigenen Produktionsserver (Ubuntu 24.04, fail2ban 1.0.2, OpenSSH 9.6). Für diesen Artikel haben wir nicht nacherzählt, sondern das fail2ban-Log der letzten 31 Tage ausgewertet, verschiedene Einstellungen gegen die echten Zeitstempel nachgerechnet und eine Sperre live von einer fremden Maschine aus getestet.
Vier Befunde vorweg, weil sie den Rest bestimmen:
1. In 31 Tagen hat fail2ban 84.213 Fehlversuche von 3.068 verschiedenen IP-Adressen gezählt und 2.527 Sperren gegen 967 Adressen verhängt. 2.101 Adressen wurden kein einziges Mal gesperrt.
2. Nach 65 % aller Entsperrungen war dieselbe Adresse innerhalb von 24 Stunden wieder da, im Median 6 Minuten nach Ablauf der Sperre. Eine Adresse wurde in drei Tagen 26-mal gesperrt.
3. Die Standardeinstellung (5 Versuche in 10 Minuten) erfasst Adressen, die 66 % des Verkehrs verursachen. Mit 5 Versuchen pro Tag wären es 97 %.
4. Unsere Konfiguration hat keine einzige Ausnahme (
ignoreip) eingetragen. Ein Server aus unserem eigenen Umfeld war am 25.09. mit drei Fehlversuchen in drei Sekunden zwei Versuche von der Sperre entfernt.
Zuerst kommt die Anleitung, danach die Messungen. Wer nur die Befehle braucht, findet am Ende eine Checkliste.

Was ist fail2ban und wie funktioniert es?
fail2ban ist ein kleiner Dienst in Python, der Logdateien mitliest, darin nach Mustern für fehlgeschlagene Anmeldungen sucht und die Absenderadresse für eine Weile sperrt, wenn sie zu oft auffällt. Es ist kein Virenscanner, keine Firewall und kein Einbruchserkennungssystem im großen Stil. Es ist ein automatischer Türsteher, der eine Strichliste führt.
Drei Bausteine greifen ineinander:
| Baustein | Was er tut | Datei |
|---|---|---|
| Filter | Reguläre Ausdrücke, die eine Logzeile als Fehlversuch erkennen und die IP herausziehen | /etc/fail2ban/filter.d/sshd.conf |
| Action | Was bei einer Sperre passiert, meist eine Firewall-Regel | /etc/fail2ban/action.d/nftables.conf |
| Jail | Verbindet Filter, Action und die Schwellen (maxretry, findtime, bantime) | /etc/fail2ban/jail.local |
Der Ablauf: Eine Logzeile wie Invalid user wallet from 203.0.113.7 kommt an. Der Filter erkennt sie als Fehlversuch und schreibt Found 203.0.113.7 ins fail2ban-Log. Sammelt dieselbe Adresse innerhalb von findtime mindestens maxretry Treffer, löst die Action aus und die Adresse landet in der Firewall. Nach bantime wird sie wieder entfernt.

Wichtig für das Verständnis aller Zahlen weiter unten: fail2ban verhindert keinen einzelnen Versuch. Es reagiert erst, nachdem die Schwelle erreicht ist. Bei unserem Server lagen im Median 445 Sekunden zwischen dem ersten gezählten Fehlversuch im Fenster und der Sperre. Ein Bot bekommt also seine fünf Versuche und rund sieben Minuten, bevor die Tür zugeht.
Was sich hinter SSH selbst verbirgt, erklären wir ausführlich in Was ist SSH?.
fail2ban einrichten: Schritt für Schritt
Die folgende Anleitung gilt für Ubuntu 22.04/24.04 und Debian 12/13. Auf anderen Distributionen heißen Pakete und Standardpfade leicht anders, das Prinzip ist gleich.
Schritt 1: Installieren
sudo apt update
sudo apt install fail2ban
Auf Debian und Ubuntu startet der Dienst nach der Installation automatisch. Prüfen:
systemctl status fail2ban
fail2ban-client version
Bei uns meldet das 1.0.2. Ältere Anleitungen beziehen sich oft auf 0.9 oder 0.10. Die Grundkonfiguration ist seitdem gleich geblieben, einige Optionen (etwa bantime.increment) gibt es aber erst ab 0.11.
Schritt 2: Die richtige Datei bearbeiten
fail2ban liest seine Konfiguration in einer festen Reihenfolge:
/etc/fail2ban/jail.conf– Standardwerte des Pakets. Nie bearbeiten, wird bei Updates überschrieben./etc/fail2ban/jail.d/*.conf– Ergänzungen, auf Debian liegt hierdefaults-debian.conf./etc/fail2ban/jail.local– deine eigenen Einstellungen. Gewinnt gegen alles davor.
Auf Debian und Ubuntu steht in defaults-debian.conf bereits:
[DEFAULT]
banaction = nftables
banaction_allports = nftables[type=allports]
backend = systemd
[sshd]
enabled = true
Das heißt: Das SSH-Jail ist nach der Installation schon an, liest aus dem systemd-Journal und sperrt über nftables. Viele Anleitungen lassen dich trotzdem backend = auto und logpath = /var/log/auth.log eintragen. Auf aktuellen Ubuntu- und Debian-Systemen gibt es /var/log/auth.log oft gar nicht mehr, und das Jail startet dann mit einem Fehler oder sieht nichts.
Schritt 3: jail.local anlegen
Eine sinnvolle Startkonfiguration:
[DEFAULT]
# Eigene Adressen, die nie gesperrt werden dürfen
ignoreip = 127.0.0.1/8 ::1 198.51.100.10
bantime = 1h
findtime = 10m
maxretry = 5
[sshd]
enabled = true
port = 22
198.51.100.10 ist hier ein Platzhalter. Trag dort die feste IP ein, von der du dich anmeldest, und jede Maschine, die per SSH automatisch auf den Server zugreift (Backup-Server, Deploy-Pipeline, Monitoring).
Wie wichtig diese Zeile ist, zeigt unser eigener Server. Er hat sie nicht:
$ fail2ban-client get sshd ignoreip
No IP address/network is ignored
Am 25.09. um 06:08 Uhr zählte fail2ban drei Fehlversuche von einem Server aus unserem eigenen Umfeld, im Sekundenabstand. Vermutlich ein Skript, das mehrere Schlüssel nacheinander probiert hat. Zwei weitere Versuche, und dieser Server wäre für zwei Stunden ausgesperrt gewesen. Passiert ist nichts – aber nur, weil das Skript nach drei Versuchen aufgehört hat, nicht weil wir vorgesorgt hätten.
Schritt 4: Konfiguration testen und neu laden
sudo fail2ban-client -t
sudo systemctl reload fail2ban
-t prüft die Syntax, ohne den Dienst anzufassen. Bei uns kommt eine Warnung ('allowipv6' not defined), die harmlos ist, und danach OK: configuration test is successful. Erst dann neu laden.
Schritt 5: Prüfen, was wirklich aktiv ist
Das ist der Schritt, den die meisten Anleitungen auslassen, und der wichtigste. Nicht die Datei gilt, sondern das, was der laufende Dienst meldet:
sudo fail2ban-client status
sudo fail2ban-client status sshd
sudo fail2ban-client get sshd maxretry
sudo fail2ban-client get sshd findtime
sudo fail2ban-client get sshd bantime
sudo fail2ban-client get sshd actions
Bei uns:
Status for the jail: sshd
|- Filter
| |- Currently failed: 9
| |- Total failed: 69550
| `- Journal matches: _SYSTEMD_UNIT=sshd.service + _COMM=sshd
`- Actions
|- Currently banned: 2
|- Total banned: 1977
`- Banned IP list: 129.121.143.111 114.30.86.98
Und get sshd bantime liefert 7200, also zwei Stunden, obwohl im [DEFAULT]-Block 1h steht. Der Grund: Im [sshd]-Abschnitt unserer jail.local steht zusätzlich bantime = 2h, und der Jail-Wert schlägt den Default. Wer nur den Kopf der Datei liest, liegt falsch.
Einen zweiten Fall dieser Art haben wir bei uns selbst gefunden. In unserem Artikel Linux Server einrichten zeigen wir eine jail.local mit banaction = ufw. Auf dem Server steht diese Zeile heute nicht, und get sshd actions meldet nftables. Welche Fassung die ältere ist, lässt sich nicht mehr sagen. Es gilt, was fail2ban-client meldet, nicht was in einem Artikel oder einer Notiz steht.
Schritt 6: Eine Sperre testen, ohne sich auszusperren
Teste nie, indem du dich absichtlich fünfmal falsch anmeldest. Sperr stattdessen eine Adresse aus einem Dokumentationsbereich von Hand und schau, ob sie in der Firewall ankommt:
sudo fail2ban-client set sshd banip 192.0.2.44
sudo nft list set inet f2b-table addr-set-sshd
sudo fail2ban-client set sshd unbanip 192.0.2.44
Bei uns erscheint 192.0.2.44 sofort im Set addr-set-sshd und verschwindet nach dem Entsperren wieder. Die Kette, die daraus entsteht, sieht so aus:
table inet f2b-table {
set addr-set-sshd {
type ipv4_addr
elements = { 114.30.86.98, 129.121.143.111 }
}
chain f2b-chain {
type filter hook input priority filter - 1; policy accept;
tcp dport 22 ip saddr @addr-set-sshd reject with icmp port-unreachable
}
}
Zwei Details stecken darin. Erstens: Die Kette hängt mit Priorität filter - 1 vor den normalen Firewall-Regeln. Eine gesperrte Adresse kommt also auch dann nicht durch, wenn ufw Port 22 freigibt. Zweitens: reject statt drop. Der Angreifer bekommt sofort eine Absage, statt in ein Timeout zu laufen.
Das haben wir von außen nachgeprüft. Wir haben unseren zweiten Server in Helsinki kurz selbst gesperrt und von dort aus verbunden:
| Test von außen | Ergebnis |
|---|---|
| Port 22 vor der Sperre | offen |
| Port 22 während der Sperre | Connection refused nach 54 ms |
| Port 443 während der Sperre | offen |
Port 22 nach unbanip | offen, Set wieder leer |
Die Sperre gilt also nur für den Port des Jails, nicht für den ganzen Server. Ein gesperrter Bot kann weiter deine Website abrufen. Wer die Adresse komplett aussperren will, braucht banaction_allports (dazu weiter unten beim Recidive-Jail).
Video: Thomas-Krenn.AG zeigt die Einrichtung auf Debian Schritt für Schritt. Thomas-Krenn ist ein Serverhersteller; das Video ist aber ein reines Tutorial.
Schritt 7: Prüfen, ob der Filter deine Logs versteht
Ein Jail, dessen Filter nicht zu den Logzeilen passt, läuft fehlerfrei und sperrt nie jemanden. Das merkt man nur, wenn man nachsieht. Dafür gibt es fail2ban-regex:
sudo fail2ban-regex systemd-journal[journalflags=1] /etc/fail2ban/filter.d/sshd.conf
Bei uns über das gesamte verfügbare Journal:
Lines: 27131 lines, 14709 ignored, 12067 matched, 355 missed
12.067 Treffer, 14.709 bewusst ignoriert (vor allem die Connection closed-Zeile, die jeden Fehlversuch begleitet und sonst doppelt zählen würde) und 355 verpasst. Mit --print-all-missed sieht man, was durchrutscht:
| Verpasste Zeile | Anzahl |
|---|---|
kex_exchange_identification: read: Connection reset by peer | 173 |
beginning MaxStartups throttling | 39 |
signature algorithm ssh-rsa not in PubkeyAcceptedAlgorithms | 16 |
banner exchange: ... invalid format | 10 |
Too many authentication failures (Benutzer root) | 6 |
Das sind fast alles Scanner, die die Verbindung abbrechen, bevor sie überhaupt einen Benutzernamen senden. Der Standardfilter läuft im Modus normal und ignoriert diese Zeilen absichtlich. Wer sie mitzählen will, stellt den Filter auf aggressive:
[sshd]
enabled = true
filter = sshd[mode=aggressive]
Ob sich das lohnt, ist Geschmackssache. 355 von rund 12.400 relevanten Zeilen sind knapp 3 %. Bei uns steht der Modus weiter auf normal.
Was fail2ban in 31 Tagen tatsächlich gesehen hat
Das systemd-Journal auf unserem Server reicht für SSH nur knapp 19 Stunden zurück. Das fail2ban-Log dagegen wird wöchentlich rotiert und fünf Generationen aufbewahrt. Für die Frage „was ist in den letzten Wochen passiert“ ist also ausgerechnet fail2ban unser längstes Gedächtnis. Ausgewertet haben wir alle Found-, Ban- und Unban-Zeilen vom 30.08. bis 30.09.2026.
| Kennzahl | Wert |
|---|---|
Gezählte Fehlversuche (Found) | 84.213 |
| Verschiedene Absender | 3.068 |
Sperren (Ban) | 2.527 |
| Davon verschiedene Adressen | 967 |
| Nie gesperrte Adressen | 2.101 (68 %) |
| Anteil ihrer Fehlversuche | 30,8 % |
| IPv6-Absender | 0 |
| Speicherbedarf des Dienstes (PSS) | ca. 32 MB |
Eine Welle ab dem 24. September
Die Tageswerte waren bis zum 23.09. unauffällig, meist zwischen 300 und 900 Fehlversuchen am Tag, mit einzelnen Ausreißern um 3.000. Dann:
| Datum | Fehlversuche | Sperren |
|---|---|---|
| 23.09. | 568 | 20 |
| 24.09. | 2.968 | 32 |
| 25.09. | 7.932 | 575 |
| 26.09. | 16.158 | 891 |
| 27.09. | 10.033 | 84 |
| 28.09. | 13.649 | 163 |
| 29.09. | 9.802 | 39 |
Seit dem 24.09. kamen 66.131 der 84.213 Fehlversuche, also fast 80 % des Monats in einer Woche. Die Spitzenstunde war der 26.09. zwischen 10 und 11 Uhr mit 1.635 Treffern.
Womit die Bots es versuchen, zeigt das Journal der letzten 19 Stunden: 12.059 Anmeldeversuche mit nicht existierendem Benutzernamen. Die zehn häufigsten Namen:
blockchain, wallet, etherscan, solana, usdt, trustvault, vault, crypto, trustwallet, contract – jeweils rund 1.000-mal.
10.426 der 12.059 Versuche (86 %) nutzten Namen aus dem Krypto-Umfeld. Die Kampagne sucht offenbar gezielt nach Servern, auf denen Wallets oder Blockchain-Nodes laufen, in der Hoffnung auf ein schwaches Passwort. Erst dahinter kommen die Klassiker ubuntu (218) und deploy (157).
Parallel standen im selben Zeitraum 815 Versuche als root im Journal. Und exakt 4 erfolgreiche Anmeldungen – alle per Schlüssel, alle von uns.
Warum fail2ban die Welle fängt, die leisen Bots aber nicht
Die Welle hat fail2ban gut erwischt. An den Spitzentagen stieg die Zahl der Sperren von 20–40 auf 575 und 891. Die Bots der Welle waren schnell, sie überschritten die Schwelle von 5 Versuchen in 10 Minuten mühelos.
Anders die Dauergäste. Die vier aktivsten Adressen, die im ganzen Monat nie gesperrt wurden:
| Adresse (gekürzt) | Fehlversuche | Sperren | Medianer Abstand |
|---|---|---|---|
| 79.99.x.x | 616 | 0 | 263 s (4,4 min) |
| 2.57.121.x (A) | 518 | 0 | 3.697 s (62 min) |
| 2.57.121.x (B) | 485 | 0 | 4.934 s (82 min) |
| 193.46.x.x | 410 | 0 | 4.697 s (78 min) |
Die erste Adresse probiert es alle viereinhalb Minuten. In zehn Minuten sind das zwei, selten drei Versuche – nie fünf. Die kürzeste Pause, die wir bei ihr gemessen haben, betrug 93 Sekunden. Sie bleibt zuverlässig unter der Schwelle, 616-mal in vier Tagen.
Die beiden Adressen aus demselben Netz 2.57.121.x kommen etwa einmal pro Stunde, einen ganzen Monat lang. Einzeln unauffällig, zusammen über 1.000 Versuche. Das sieht nicht nach Zufall aus, sondern nach einer Botfarm, die die gängigen fail2ban-Standardwerte kennt und knapp darunter bleibt.

Im August hatten wir auf demselben Server nachgerechnet, dass die Standardeinstellung 70,4 % des Angriffsverkehrs nicht sieht. Diesen Monat sind es 30,8 %. Der Unterschied liegt nicht an fail2ban, sondern am Angreifer-Mix: Im August dominierten langsame Bots, im September eine laute Welle. Eine Aussage wie „fail2ban fängt X Prozent“ ist deshalb immer eine Momentaufnahme. Sie hängt davon ab, wer gerade anklopft.
Welche Einstellung wie viel fängt: die Nachrechnung
Wir haben alle 84.213 Zeitstempel gegen verschiedene Kombinationen aus maxretry und findtime gerechnet. Für jede Adresse haben wir ein gleitendes Fenster geprüft: Hätte sie die Schwelle irgendwann im Monat erreicht?
| maxretry | findtime | Adressen, die ausgelöst hätten | Anteil ihrer Fehlversuche am Gesamtverkehr |
|---|---|---|---|
| 5 | 10 min (Standard) | 894 (29,1 %) | 66,4 % |
| 3 | 10 min | 1.338 (43,6 %) | 83,8 % |
| 5 | 1 h | 1.402 (45,7 %) | 87,9 % |
| 3 | 1 h | 1.652 (53,8 %) | 93,5 % |
| 5 | 1 Tag | 1.784 (58,1 %) | 97,1 % |
| 3 | 1 Tag | 1.999 (65,2 %) | 98,2 % |
| 2 | 1 Tag | 2.236 (72,9 %) | 98,9 % |
Zur Einordnung: Die rechte Spalte ist nicht die Zahl der verhinderten Versuche. Sie sagt nur, welcher Anteil des Verkehrs von Adressen kam, die irgendwann gesperrt worden wären. Die Versuche vor der Sperre und nach deren Ablauf passieren trotzdem. Die Tabelle zeigt also, wen eine Einstellung erwischt, nicht wie viel sie wegfiltert.
Trotzdem ist das Muster klar: Das Zeitfenster ist der stärkere Hebel. findtime von 10 Minuten auf einen Tag zu verlängern bringt mehr als maxretry von 5 auf 3 zu senken. Die langsamen Bots verteilen ihre Versuche über Stunden – ein kurzes Fenster sieht sie nie.
Unser Kompromiss-Vorschlag für SSH mit Schlüssel-Anmeldung:
[sshd]
enabled = true
maxretry = 5
findtime = 1d
bantime = 1d
Mit reiner Schlüssel-Anmeldung ist die Gefahr, sich selbst auszusperren, gering: Ein falscher Schlüssel erzeugt keinen Invalid user-Eintrag, und fünf Fehler an einem Tag passieren einem Menschen kaum. Voraussetzung bleibt die ignoreip-Zeile für eigene Automatisierung.
Wir haben diese Werte auf unserem Server noch nicht gesetzt. Der Artikel beschreibt den Ist-Zustand, und eine Änderung an der Produktion gehört in eine eigene, bewusste Entscheidung – nicht nebenbei in einen Blogartikel.
Die Drehtür: Sperren, die nach einer Stunde nichts mehr wert sind
Der auffälligste Befund dieses Monats betrifft nicht die Schwelle, sondern das Ende der Sperre.
Von 2.525 Entsperrungen im Log war die entsperrte Adresse in 1.641 Fällen (65 %) innerhalb von 24 Stunden wieder da. Der Median: 6,1 Minuten nach dem Entsperren. Die Bots merken nicht einmal, dass sie gesperrt waren – sie versuchen es einfach weiter und laufen zwei Stunden lang in Connection refused, bis die Tür wieder aufgeht.
Die Verteilung, wie oft dieselbe Adresse gesperrt wurde:
| Sperren pro Adresse | Adressen |
|---|---|
| 1 | 571 |
| 2 | 124 |
| 3–5 | 106 |
| 6–10 | 148 |
| mehr als 10 | 18 |
Spitzenreiter: eine Adresse, die zwischen dem 25. und 28.09. 26-mal gesperrt wurde und dabei 321 Fehlversuche absetzte. Jede einzelne Sperre hat funktioniert. In der Summe hat fail2ban diesen Bot drei Tage lang im Zwei-Stunden-Takt beschäftigt, ohne ihn loszuwerden.

Für dieses Problem gibt es zwei eingebaute Lösungen.
Lösung 1: bantime.increment
Seit Version 0.11 kann fail2ban die Sperrdauer für Wiederholungstäter automatisch verlängern:
[DEFAULT]
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 4w
Jede weitere Sperre derselben Adresse dauert dann doppelt so lang wie die vorige: 2 h, 4 h, 8 h, 16 h … bis maximal vier Wochen.
Falle, die wir bei uns gefunden haben: fail2ban merkt sich frühere Sperren in seiner SQLite-Datenbank, und die wird nach dbpurgeage bereinigt. Bei uns:
$ fail2ban-client get dbpurgeage
Current database purge age is:
`- 86400seconds
Ein Tag. Die Datenbank enthielt beim Nachsehen nur 47 Sperren, obwohl im Log 2.527 stehen. Mit dieser Einstellung vergisst bantime.increment jeden Wiederholungstäter nach 24 Stunden. Wer die Option einschaltet, muss auch das Gedächtnis verlängern:
# /etc/fail2ban/fail2ban.local
[DEFAULT]
dbpurgeage = 30d
Lösung 2: das Recidive-Jail
Die ältere, sehr robuste Variante: ein zweites Jail, das nicht die SSH-Logs liest, sondern das fail2ban-Log selbst. Wer dort oft genug als Ban auftaucht, wird für lange Zeit auf allen Ports gesperrt:
[recidive]
enabled = true
logpath = /var/log/fail2ban.log
banaction = %(banaction_allports)s
bantime = 1w
findtime = 1d
maxretry = 5
Die Werte für bantime, findtime und banaction sind bereits so in jail.conf vorgegeben, nur enabled fehlt. Wir haben nachgerechnet, was es bei uns bewirkt hätte:
- 185 Adressen hätten im Monat mindestens fünf Sperren an einem Tag gesammelt und wären für eine Woche komplett ausgesperrt worden.
- Genau diese 185 Adressen haben in der Woche nach diesem Zeitpunkt 26.337 weitere Fehlversuche abgesetzt – 31 % des gesamten Monatsverkehrs.
Ein Drittel des Lärms stammt also von einer kleinen Gruppe, die schon fünfmal aufgefallen ist. Mit maxretry = 3 im Recidive-Jail wären es 221 Adressen.

Auch das Recidive-Jail ist bei uns aktuell nicht eingeschaltet. Es steht, zusammen mit findtime = 1d und dbpurgeage, auf unserer Liste für eine bewusste Änderung.
fail2ban und die Firewall: ufw, nftables, iptables
Eine häufige Frage ist, ob fail2ban mit ufw zusammenarbeitet. Die Antwort: Ja, auf zwei Arten.
Variante A (Standard auf Debian/Ubuntu): fail2ban legt eine eigene nftables-Tabelle f2b-table an und hängt sie vor ufw. ufw bleibt davon unberührt, ufw status zeigt die fail2ban-Sperren nicht an. Das ist unser Setup. Man muss nur wissen, wo man nachsieht: nft list table inet f2b-table.
Variante B: banaction = ufw. Dann fügt fail2ban jede Sperre als ufw-Regel ein (ufw insert 1 deny from ...). Vorteil: Alles steht an einer Stelle. Nachteil: Bei Wellen wie der vom 26.09. entstehen Hunderte Regeln, und jede Änderung läuft durch ufw.
Wer ufw noch nicht eingerichtet hat, findet das in unserer ufw-Anleitung. Dort steht auch, warum eine Sperre, die in der falschen Reihenfolge eingefügt wird, wirkungslos bleiben kann – ein Problem, das fail2ban mit insert 1 bewusst umgeht.
Weitere Jails: Nginx, Caddy und Co.
SSH ist das Standard-Jail, aber fail2ban liefert bei uns 95 Filter mit, von apache-auth über nginx-http-auth bis postfix. Ein Jail für die Basic-Auth von Nginx:
[nginx-http-auth]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
Zwei Hinweise dazu:
- Hinter einem Reverse Proxy oder Cloudflare steht im Log oft nicht die Adresse des Besuchers, sondern die des Proxys. fail2ban sperrt dann den Proxy – und damit alle Besucher. Vorher sicherstellen, dass die echte Client-IP im Log landet. Wie Proxys Adressen weiterreichen, erklären wir in Was ist ein Reverse Proxy?.
- Für Caddy bringt fail2ban keinen fertigen Filter mit. Caddy schreibt JSON-Logs; ein Filter muss selbst gebaut und mit
fail2ban-regexgegen echte Zeilen geprüft werden.
Video (englisch): Akamai Developers erklären die Konfiguration inklusive eigener Jails. Das Video ist älter, die Grundlagen stimmen aber weiterhin; backend = systemd ist auf aktuellen Systemen die bessere Wahl als die dort gezeigten Logdateien.
Reicht fail2ban als Schutz für SSH?
Nein, und das ist keine Kritik an fail2ban. Es ist die Einordnung.
Auf unserem Server sieht die SSH-Konfiguration so aus (sshd -T):
passwordauthentication no
kbdinteractiveauthentication no
permitrootlogin without-password
maxauthtries 6
Damit gibt es schlicht kein Passwort zu erraten. Die 12.059 Versuche mit wallet, solana und ubuntu sind vollkommen chancenlos, ob fail2ban sie sperrt oder nicht. fail2ban ändert an der Sicherheit dieses Servers praktisch nichts. Was es ändert:
- Weniger Lärm in den Logs. Gesperrte Adressen erzeugen keine Logzeilen mehr, echte Auffälligkeiten fallen eher auf.
- Weniger Last. Jeder SSH-Handshake kostet Rechenzeit. Bei 16.000 Versuchen am Tag ist das messbar, wenn auch nicht dramatisch.
- Ein Frühwarnsystem. Die Kurve der Sperren zeigt eine Welle wie die vom 24.09. auf einen Blick.
Wo fail2ban dagegen wirklich schützt: überall, wo es Passwörter gibt. Login-Masken von Webanwendungen, Mailserver mit SMTP-AUTH, FTP, ein Admin-Bereich mit Basic-Auth. Dort ist fail2ban oft die einzige Bremse gegen massenhaftes Raten.
Die richtige Reihenfolge für SSH:
- Passwort-Anmeldung abschalten, nur Schlüssel (Anleitung in Was ist SSH?).
- Firewall mit „alles zu, nur das Nötige auf“ (ufw einrichten).
- fail2ban als dritte Linie, gegen den Lärm.
Mehr zur Reihenfolge und zu allen anderen Schritten der Grundhärtung steht in unserem Artikel Linux Server einrichten.
fail2ban vs. CrowdSec vs. sshguard
| fail2ban | CrowdSec | sshguard | |
|---|---|---|---|
| Sprache | Python | Go | C |
| Arbeitsweise | Liest Logs, sperrt lokal | Liest Logs, sperrt lokal und teilt Sperrlisten mit einer Community | Liest Logs, sperrt lokal |
| Konfiguration | INI-Dateien, sehr flexibel | YAML, Szenarien aus einem Hub | Minimal |
| Speicher bei uns | ca. 32 MB | nicht gemessen | nicht gemessen |
| Vorwissen über Angreifer | keins, lernt nur lokal | gemeinsame Blockliste | keins |
| Datenschutz | nichts verlässt den Server | Signale werden geteilt | nichts verlässt den Server |
CrowdSec ist der interessanteste Konkurrent: Eine Adresse, die bei tausend anderen Servern schon aufgefallen ist, kann gesperrt werden, bevor sie bei dir den ersten Versuch macht. Gegen die langsamen Bots aus unserer Tabelle wäre das vermutlich wirksamer als jede findtime-Einstellung. Der Preis: Man teilt Daten über Angriffe mit einem externen Dienst. Wir haben CrowdSec für diesen Artikel nicht getestet und machen dazu keine Messaussagen.
sshguard ist die schlanke Alternative für Leute, die wirklich nur SSH schützen wollen und keine Konfiguration anfassen möchten.
Nützliche Befehle im Alltag
# Übersicht aller Jails
sudo fail2ban-client status
# Details eines Jails inkl. gesperrter Adressen
sudo fail2ban-client status sshd
# Adresse von Hand sperren / entsperren
sudo fail2ban-client set sshd banip 203.0.113.7
sudo fail2ban-client set sshd unbanip 203.0.113.7
# Eigene Adresse entsperren, wenn du dich ausgesperrt hast (über die Konsole des Anbieters)
sudo fail2ban-client unban --all
# Welche Werte gelten wirklich?
sudo fail2ban-client get sshd maxretry
sudo fail2ban-client get sshd findtime
sudo fail2ban-client get sshd bantime
sudo fail2ban-client get sshd ignoreip
# Die letzten 20 Sperren im Log
sudo grep " Ban " /var/log/fail2ban.log | tail -20
# Die Firewall-Seite ansehen
sudo nft list table inet f2b-table
Wenn du dich ausgesperrt hast: Fast jeder VPS-Anbieter bietet eine Web-Konsole, die nicht über SSH läuft. Dort anmelden, fail2ban-client unban --all, dann die eigene Adresse in ignoreip eintragen.
Checkliste: fail2ban einrichten
apt install fail2ban/etc/fail2ban/jail.localanlegen, nichtjail.confbearbeitenignoreipmit eigener Adresse und allen automatisierten Zugängen füllen- Schwellen festlegen; für SSH mit Schlüsseln:
findtime = 1dstatt10m fail2ban-client -t, dannsystemctl reload fail2ban- Mit
fail2ban-client get …prüfen, welche Werte wirklich gelten - Test-Sperre mit
banip 192.0.2.44, innft list table inet f2b-tablenachsehen, wiederunbanip fail2ban-regexgegen die echten Logs laufen lassen: gibt esmatched-Treffer?- Wiederholungstäter behandeln: Recidive-Jail oder
bantime.incrementmit längeremdbpurgeage - Passwort-Anmeldung für SSH abschalten – das ist der eigentliche Schutz
Was wir nicht gemessen haben
- Die Nachrechnung ist eine Simulation über die Zeitstempel des fail2ban-Logs. Wie sich Bots verhalten hätten, wenn sie früher gesperrt worden wären, lässt sich daraus nicht ableiten. Manche hätten vielleicht aufgegeben, andere die Adresse gewechselt.
- Wir sehen nur, was der Filter erkennt. Die 355 verpassten Zeilen und alle Verbindungen, die ohne Logeintrag enden, fehlen in den 84.213.
- Ein Server, ein Monat. Ein Server mit anderem Standort, anderem Anbieter oder einem bekannteren Namen sieht andere Angreifer. Unsere eigene Messung vom August kam auf ein ganz anderes Verhältnis.
- CrowdSec und sshguard haben wir nicht parallel betrieben.
- Wir haben nichts dauerhaft geändert. Die beiden Test-Sperren (Dokumentations-Adresse und unser eigener Helsinki-Server) wurden sofort aufgehoben, das Set war danach wieder im Ausgangszustand.
Häufige Fragen
Wie richte ich fail2ban ein?
Mit apt install fail2ban installieren, eine Datei /etc/fail2ban/jail.local mit ignoreip, maxretry, findtime, bantime und einem [sshd]-Abschnitt mit enabled = true anlegen, per fail2ban-client -t prüfen und mit systemctl reload fail2ban neu laden. Auf Debian und Ubuntu ist das SSH-Jail nach der Installation bereits aktiv.
Wo liegt die Konfiguration von fail2ban?
Unter /etc/fail2ban/. Die Standardwerte stehen in jail.conf, eigene Einstellungen gehören in jail.local oder in eine Datei unter jail.d/. Allgemeine Dienst-Einstellungen wie dbpurgeage gehören in fail2ban.local.
Warum sperrt fail2ban niemanden?
Die drei häufigsten Gründe: Das Jail liest die falsche Quelle (logpath = /var/log/auth.log auf einem System ohne diese Datei), der Filter passt nicht zu den Logzeilen (mit fail2ban-regex prüfen) oder die Angreifer bleiben unter der Schwelle, weil findtime zu kurz ist. Bei uns gab es Bots mit über 600 Versuchen im Monat, die nie gesperrt wurden, weil sie nur alle vier Minuten kamen.
Wie entsperre ich eine IP-Adresse in fail2ban?
sudo fail2ban-client set sshd unbanip 203.0.113.7 für ein bestimmtes Jail oder sudo fail2ban-client unban 203.0.113.7 für alle Jails. unban --all hebt sämtliche Sperren auf.
Wie lange sperrt fail2ban standardmäßig?
In jail.conf sind 10 Minuten voreingestellt, maxretry 5 und findtime 10 Minuten. Viele setzen bantime auf eine Stunde oder mehr. Bei uns sind es zwei Stunden – und 65 % der entsperrten Adressen kamen innerhalb eines Tages wieder, im Median nach sechs Minuten.
Funktioniert fail2ban mit ufw?
Ja. Auf Debian und Ubuntu sperrt fail2ban standardmäßig über eine eigene nftables-Tabelle, die vor ufw greift; ufw status zeigt die Sperren dann nicht an. Alternativ trägt banaction = ufw jede Sperre direkt als ufw-Regel ein.
Sperrt fail2ban den ganzen Server oder nur SSH?
Nur die Ports des Jails. Wir haben es getestet: Während der Sperre war Port 22 mit Connection refused zu, Port 443 blieb erreichbar. Für eine komplette Sperre braucht man banaction_allports, wie es das Recidive-Jail verwendet.
Brauche ich fail2ban, wenn SSH nur Schlüssel erlaubt?
Für die Sicherheit von SSH kaum – ohne Passwort gibt es nichts zu erraten. fail2ban reduziert dann vor allem den Lärm in den Logs und etwas Last. Wirklich wichtig wird es für Dienste mit Passwort-Anmeldung, etwa Web-Logins oder Mailserver.
Was ist das Recidive-Jail?
Ein zweites Jail, das das fail2ban-Log selbst liest und Adressen, die innerhalb eines Tages mehrfach gesperrt wurden, für eine Woche auf allen Ports aussperrt. In unseren Daten hätte es 185 Adressen erfasst, die danach noch 31 % des Monatsverkehrs verursachten.
Was ist besser, fail2ban oder CrowdSec?
fail2ban arbeitet komplett lokal und ist sehr flexibel. CrowdSec teilt Sperrlisten mit anderen Nutzern und kann bekannte Angreifer sperren, bevor sie den ersten Versuch machen – dafür verlassen Daten den Server. Wir setzen fail2ban ein und haben CrowdSec nicht selbst gemessen.
Schützt fail2ban auch vor IPv6-Angreifern?
Ja, fail2ban unterstützt IPv6 seit Version 0.10. In unseren 31 Tagen kam allerdings kein einziger Fehlversuch über IPv6 – alle 3.068 Absender nutzten IPv4.
Fazit
fail2ban einrichten ist leicht, und es funktioniert: Jede der 2.527 Sperren in unserem Monat hat gegriffen, die Test-Sperre war in 54 Millisekunden an der Firewall. Die spannenden Fragen liegen woanders.
Die Standardwerte sind für schnelle Bots gemacht. Die Welle vom 26. September hat fail2ban mit fast 900 Sperren an einem Tag gut abgefangen. Die leisen Dauergäste, die alle vier Minuten oder einmal pro Stunde klopfen, sieht es mit einem Zehn-Minuten-Fenster nie. Der wirksamste Hebel ist findtime, nicht maxretry.
Und eine Sperre, die nach zwei Stunden abläuft, ist für die meisten Bots nur eine Pause. Zwei Drittel waren innerhalb eines Tages zurück. Wer fail2ban ernst nimmt, braucht eine zweite Stufe: das Recidive-Jail oder bantime.increment – und dann auch eine Datenbank, die sich länger als einen Tag erinnert.
Das Wichtigste bleibt aber die Reihenfolge. fail2ban ist die dritte Verteidigungslinie. Die erste ist, dass es für Angreifer nichts zu erraten gibt. Auf unserem Server stehen 84.213 Fehlversuche und 0 Treffer – und das liegt an einer Zeile in der sshd_config, nicht an fail2ban.