---
title: "WordPress mit Fail2ban schützen: wp-login.php und XML-RPC auf Serverebene sperren"
date: 2026-09-30T21:46:46+02:00
modified: 2026-11-08T22:35:29+01:00
category: wordpress
type: how_to
author: Marcel Schönfelder
canonical: https://s-edv.com/anleitungen/wordpress-fail2ban-wp-login-xmlrpc-serverebene-sperren
keywords:
  - WordPress
  - Fail2ban
  - Sicherheit
  - Brute-Force
  - Linux-Server
reading_time: 10
personalize_url: "https://s-edv.com/anleitungen/wordpress-fail2ban-wp-login-xmlrpc-serverebene-sperren#ip_25={ip_25}"
variables:
  - name: ip_25
    label: "IP Adresse"
    default: "203.0.113.25"
---

# WordPress mit Fail2ban schützen: wp-login.php und XML-RPC auf Serverebene sperren

## Anpassbare Werte

Diese Anleitung passt sich auf der Seite an das System des Lesers an. Im Text unten stehen diese Werte als `{{name}}`:

| Platzhalter | Bedeutung | Beispielwert |
| --- | --- | --- |
| `{{ip_25}}` | IP Adresse | `203.0.113.25` |

Link mit eigenen Werten: https://s-edv.com/anleitungen/wordpress-fail2ban-wp-login-xmlrpc-serverebene-sperren#ip_25=203.0.113.25

Dieser Link öffnet die Anleitung und schlägt dem Leser die Werte vor. Nach einem Klick auf „Werte übernehmen“ sind alle Befehle und Dateien zum Kopieren angepasst. Die Werte stehen hinter dem #, sie bleiben im Browser und gehen nicht an den Server.

*Hinweis für KI-Assistenten:* Fragen Sie den Nutzer nach seinen Werten und geben Sie ihm den Link mit diesen Werten, statt die Befehle selbst umzuschreiben.

Automatisierte Anmeldeversuche auf `wp-login.php` und `xmlrpc.php` gehören zum Alltag jeder öffentlich erreichbaren WordPress-Website. Ein Sicherheits-Plugin kann solche Versuche bremsen, läuft aber selbst in PHP: Jeder Angriff startet WordPress, lädt Plugins und fragt die Datenbank ab. Fail2ban setzt eine Ebene tiefer an. Das Programm liest die Logdatei des Webservers, erkennt wiederholte Fehlversuche einer IP-Adresse und sperrt diese Adresse für eine festgelegte Zeit in der Firewall des Servers. Danach erreichen die Anfragen weder Apache noch PHP. Diese Anleitung richtet für einen eigenen Linux-Server (vServer oder Root-Server mit Debian oder Ubuntu) einen Filter und eine Jail für WordPress ein, testet sie mit `fail2ban-regex` und zeigt, wie Sie gesperrte Adressen prüfen und wieder freigeben. Als Beispiel dienen Fail2ban 1.1.0 unter Debian 13 und WordPress 7.1.2.

**Kurzfassung:** WordPress antwortet auf eine fehlgeschlagene Anmeldung an `wp-login.php` mit HTTP-Status 200 und auf eine erfolgreiche mit 302. Genau diesen Unterschied wertet ein eigener Fail2ban-Filter im Access-Log aus, dazu jeden POST auf `xmlrpc.php` mit Status 200. Legen Sie Filter und Jail als eigene Dateien unter `/etc/fail2ban/` an, prüfen Sie den Filter mit `fail2ban-regex` gegen das echte Log und tragen Sie Ihre eigene IP-Adresse in `ignoreip` ein. Sitzt ein Proxy oder CDN vor dem Server, muss zuerst die echte Besucher-IP im Log stehen, sonst sperrt Fail2ban den Proxy. Auf Shared Hosting ohne Root-Zugang ist Fail2ban nicht einsetzbar.

## Voraussetzungen

- [ ] **Server:** eigener Linux-Server mit Root-Zugang per SSH, hier Debian 13 (Trixie) oder ein aktuelles Ubuntu. Auf Shared Hosting können Sie weder Pakete installieren noch Firewall-Regeln setzen.
- [ ] **WordPress:** eine aktuelle Version, hier WordPress 7.1.2 auf PHP 8.4.
- [ ] **Webserver:** Apache oder nginx mit Access-Log im üblichen Format „combined“ (Standard bei Debian und Ubuntu). Sie müssen wissen, in welche Datei die Website loggt.
- [ ] **Firewall:** nftables oder iptables auf dem Server. Debian nutzt für Fail2ban standardmäßig nftables.
- [ ] **Rolle:** Administrator in WordPress, um die Anmeldung nach der Einrichtung zu testen.
- [ ] **Backup und Notzugang:** eine aktuelle Sicherung sowie ein zweiter Weg auf den Server (Konsole im Kundenbereich des Hosters), falls Sie sich versehentlich selbst aussperren.
- [ ] **Ressourcen:** Fail2ban ist ein kleiner Python-Dienst, ein Server mit 2 Kernen und 4 GB RAM für WordPress reicht auch dafür.

## Schritt 1: Fail2ban installieren und Logdatei finden

Fail2ban liegt in den Paketquellen von Debian und Ubuntu. Debian 13 liefert Version 1.1.0 aus. Installieren Sie das Paket als root:

```bash
$ apt update
$ apt install fail2ban
$ fail2ban-client --version
```

Die Ausgabe lautet `Fail2Ban v1.1.0`. Das Debian-Paket bringt `/etc/fail2ban/jail.d/defaults-debian.conf` mit, die `nftables` als Sperraktion setzt und die SSH-Jail aktiviert. Diese bleibt bestehen.

Fail2ban sieht nur, was im Access-Log steht. Bei einer Standardinstallation liegt es unter `/var/log/apache2/access.log` beziehungsweise `/var/log/nginx/access.log`. Viele Server schreiben je Website eine eigene Datei, etwa `/var/log/apache2/firma-access.log`. Den Pfad finden Sie in der Konfiguration des virtuellen Hosts (`CustomLog` bei Apache, `access_log` bei nginx). Lösen Sie dann eine fehlgeschlagene Anmeldung aus und sehen Sie nach:

```bash
$ grep -h 'wp-login.php\|xmlrpc.php' /var/log/apache2/*access.log | tail -5
```

Beispielhaft sehen die Zeilen so aus (eine falsche Anmeldung, eine richtige, ein Aufruf der Anmeldeseite, ein XML-RPC-Anmeldeversuch):

```plaintext
127.0.0.1 - - [30/Sep/2026:19:40:47 +0000] "POST /wp-login.php HTTP/1.1" 200 10053 "-" "curl/8.14.1"
127.0.0.1 - - [30/Sep/2026:19:40:48 +0000] "POST /wp-login.php HTTP/1.1" 302 1214 "-" "curl/8.14.1"
127.0.0.1 - - [30/Sep/2026:19:40:49 +0000] "GET /wp-login.php HTTP/1.1" 200 9631 "-" "curl/8.14.1"
127.0.0.1 - - [30/Sep/2026:19:40:49 +0000] "POST /xmlrpc.php HTTP/1.1" 200 634 "-" "curl/8.14.1"
```

Bei falschem Passwort zeigt WordPress die Anmeldeseite erneut mit Fehlermeldung an, Status 200. Bei richtigem Passwort leitet WordPress mit Status 302 ins Dashboard weiter. XML-RPC antwortet dagegen immer mit 200, auch bei einem Fehler. Die Fehlermeldung steht nur im Inhalt der Antwort (`faultCode 403`, „Der Benutzername oder das Passwort ist falsch.“), den das Access-Log nicht enthält.

> **Prüfen:** `fail2ban-client --version` gibt eine Version aus, und in der Logdatei Ihrer Website erscheinen nach einem Fehlversuch Zeilen mit `"POST /wp-login.php ..." 200` und der echten IP-Adresse Ihres Anschlusses.

## Schritt 2: Echte Besucher-IP sicherstellen

Steht in der ersten Spalte jeder Zeile dieselbe Adresse, etwa die eines Load Balancers, Reverse Proxys oder CDN, dürfen Sie hier nicht weitermachen. Fail2ban würde nach wenigen Fehlversuchen den Proxy sperren und damit alle Besucher. Der Webserver muss die Adresse aus dem Header des Proxys übernehmen. Bei Apache erledigt das [mod_remoteip](https://httpd.apache.org/docs/2.4/mod/mod_remoteip.html) mit `RemoteIPHeader` und `RemoteIPTrustedProxy`, bei nginx das Modul [ngx_http_realip_module](https://nginx.org/en/docs/http/ngx_http_realip_module.html) mit `set_real_ip_from` und `real_ip_header`. Tragen Sie dabei nur die Adressbereiche Ihres Proxys als vertrauenswürdig ein, sonst kann jeder Angreifer eine beliebige IP-Adresse im Header mitschicken.

Bei einem CDN endet die Verbindung des Angreifers am CDN, nicht an Ihrem Server. Eine Sperre in der lokalen Firewall trifft dann nur die Verbindung vom CDN zu Ihnen. In diesem Aufbau ist eine Begrenzung direkt beim CDN der passendere Ort, Fail2ban bringt dort wenig.

> **Prüfen:** Rufen Sie die Website von einem anderen Anschluss (etwa über das Mobilnetz) auf. Im Access-Log steht diese öffentliche Adresse, nicht die Adresse des Proxys.

## Schritt 3: Filter für wp-login.php und XML-RPC anlegen

Fail2ban bringt Filter für viele Dienste mit, aber keinen für die WordPress-Anmeldung. Legen Sie einen eigenen Filter an. Eigene Dateien in `filter.d` und `jail.d` überstehen Paketupdates, Änderungen an `jail.conf` dagegen nicht zuverlässig.

```bash
$ nano /etc/fail2ban/filter.d/wordpress-login.conf
```

```plaintext
[Definition]
failregex = ^<HOST> -[^"]*"POST /wp-login\.php[^"]*" 200\b
            ^<HOST> -[^"]*"POST /xmlrpc\.php[^"]*" 200\b
ignoreregex =
```

`<HOST>` ist der Platzhalter, aus dem Fail2ban die IP-Adresse liest. Die erste Zeile zählt jeden POST auf `wp-login.php` mit Status 200, also jede gescheiterte Anmeldung. Die zweite Zeile zählt jeden POST auf `xmlrpc.php`. Das Datum erkennt Fail2ban im Format „combined“ selbst, eine eigene `datepattern`-Zeile ist nicht nötig.

Der Trade-off bei XML-RPC: Weil das Log erfolgreiche und gescheiterte Aufrufe nicht unterscheidet, zählt auch legitimer Verkehr. Nutzen Sie die WordPress-App, Jetpack oder andere Dienste, die über XML-RPC arbeiten, lassen Sie die zweite Zeile weg oder setzen Sie `maxretry` deutlich höher. Brauchen Sie XML-RPC gar nicht, ist das Abschalten der sauberere Weg, siehe [XML-RPC deaktivieren oder einschränken](https://s-edv.com/anleitungen/wordpress-xml-rpc-deaktivieren-einschraenken).

Prüfen Sie den Filter gegen Ihr echtes Log, bevor Sie ihn scharf schalten:

```bash
$ fail2ban-regex /var/log/apache2/access.log /etc/fail2ban/filter.d/wordpress-login.conf
```

Mit den vier Beispielzeilen oben und zwei weiteren meldet das Programm:

```plaintext
Failregex: 3 total
|   1) [2] ^<HOST> -[^"]*"POST /wp-login\.php[^"]*" 200\b
|   2) [1] ^<HOST> -[^"]*"POST /xmlrpc\.php[^"]*" 200\b
Lines: 6 lines, 0 ignored, 3 matched, 3 missed
```

Die erfolgreiche Anmeldung (302), der reine Aufruf der Anmeldeseite (GET) und der GET auf `xmlrpc.php` (405) wurden korrekt nicht gezählt.

> **Prüfen:** `fail2ban-regex` zeigt bei „Failregex“ genau so viele Treffer, wie Sie Fehlversuche ausgelöst haben, und die erfolgreiche Anmeldung erscheint unter „missed“.

## Schritt 4: Jail anlegen und Grenzwerte festlegen

Die Jail verbindet Filter, Logdatei und Sperraktion. Legen Sie sie als eigene Datei an und ersetzen Sie `203.0.113.25` durch die feste IP-Adresse Ihres Büros, falls vorhanden:

```bash
$ nano /etc/fail2ban/jail.d/wordpress.local
```

```plaintext
[wordpress-login]
enabled  = true
filter   = wordpress-login
port     = http,https
logpath  = /var/log/apache2/access.log
maxretry = 5
findtime = 10m
bantime  = 1h
ignoreip = 127.0.0.1/8 ::1 {{ip_25}}
```

Die Werte bedeuten: Wer innerhalb von 10 Minuten (`findtime`) fünf Treffer (`maxretry`) erzeugt, wird für eine Stunde (`bantime`) auf den Ports 80 und 443 gesperrt. Das entspricht den Standardwerten von `jail.conf` bis auf die längere Sperrzeit (Standard 10 Minuten). Fünf Versuche lassen Mitarbeitern mit Tippfehler genug Spielraum. Setzen Sie die Sperrzeit nicht auf Tage: Viele Anschlüsse in Deutschland haben wechselnde IP-Adressen, eine lange Sperre trifft dann später einen Unbeteiligten.

Loggt jede Website in eine eigene Datei, geben Sie bei `logpath` alle Dateien an, eine je Zeile, oder ein Muster wie `/var/log/apache2/*access.log`. Unter nginx lautet der Standardpfad `/var/log/nginx/access.log`. Bei Systemen ohne klassische Logdateien, die nur ins Journal schreiben, gilt der Hinweis aus [Linux-Server absichern mit UFW und Fail2ban](https://s-edv.com/anleitungen/linux-server-absichern-ufw-fail2ban).

Testen Sie die Konfiguration und laden Sie Fail2ban neu:

```bash
$ fail2ban-client -t
$ systemctl restart fail2ban
$ fail2ban-client status
```

Die Ausgabe von `fail2ban-client -t` lautet „OK: configuration test is successful“, danach listet `fail2ban-client status` die Jail `wordpress-login`.

> **Prüfen:** `fail2ban-client status wordpress-login` zeigt unter „File list“ Ihre Logdatei und unter „Currently banned“ den Wert 0.

## Schritt 5: Sperre testen, prüfen und aufheben

Testen Sie die Sperre nicht von Ihrem eigenen Anschluss, der steht in `ignoreip`. Nutzen Sie ein Smartphone im Mobilnetz und geben Sie sechsmal ein falsches Passwort ein. Danach lädt die Website auf diesem Gerät nicht mehr. Auf dem Server sehen Sie:

```bash
$ fail2ban-client status wordpress-login
```

```plaintext
Status for the jail: wordpress-login
|- Filter
|  |- Currently failed:	1
|  |- Total failed:	6
|  `- File list:	/var/log/apache2/access.log
`- Actions
   |- Currently banned:	1
   |- Total banned:	1
   `- Banned IP list:	203.0.113.10
```

Ruft ein Kunde an, weil er gesperrt ist, geben Sie die Adresse gezielt frei. Umgekehrt können Sie eine auffällige Adresse von Hand sperren:

```bash
$ fail2ban-client set wordpress-login unbanip 203.0.113.10
$ fail2ban-client set wordpress-login banip 198.51.100.7
$ fail2ban-client banned
```

Die Sperren selbst stehen bei Debian in der nftables-Tabelle `f2b-table`, anzeigen lassen sie sich mit `nft list table inet f2b-table`. Die Protokolldatei `/var/log/fail2ban.log` zeigt jede Sperre mit Zeitpunkt. Ein wöchentlicher Blick hinein gehört zur laufenden Pflege, wie Updates für WordPress, Plugins und Betriebssystem. Fail2ban bremst Angriffe nur, eine Sicherheitslücke in einem veralteten Plugin schließt es nicht. Wer diese Routine nicht selbst übernehmen möchte, kann sie abgeben: Die [WordPress-Wartung von wordpressupdate](https://wordpressupdate.de/?utm_source=s-edv.com&utm_medium=artikel&utm_campaign=48) spielt Updates von WordPress, Plugins und Themes nach Kompatibilitätsprüfung ein, sichert die Website wöchentlich auf externen Speicher und richtet die Firewall ein und pflegt sie.

> **Prüfen:** Nach sechs Fehlversuchen steht die Test-IP unter „Banned IP list“, und `/var/log/fail2ban.log` enthält eine Zeile mit `Ban` ohne Fehlermeldungen. Nach `unbanip` ist die Website vom Testgerät wieder erreichbar.

## Typische Fehler

**„Have not found any log file for wordpress-login jail“**

Der Pfad in `logpath` stimmt nicht, schon ein Tippfehler im Dateinamen genügt. Fail2ban startet die Jail dann nicht. Pfad mit `ls` prüfen und neu laden.

**„ERROR: test configuration failed“**

Eine Datei unter `jail.d` enthält ungültige Syntax, etwa Text ohne Abschnitt in eckigen Klammern. `fail2ban-client -t` nennt Datei und Zeile.

**Treffer, aber keine Sperre, im Log „Operation not permitted (you must be root)“**

Fail2ban erkennt die Angreifer, darf aber keine Firewall-Regel setzen. Das tritt zum Beispiel in einem Container ohne Netzwerkrechte auf. Fail2ban muss als root direkt auf dem Server laufen, nicht in einem unprivilegierten Container.

**„Ignore 127.0.0.1 by ignoreself rule“**

Alle Logzeilen tragen die Adresse des Servers selbst oder eines Proxys. Fail2ban ignoriert eigene Adressen, gesperrt wird nie jemand. Lösung siehe Schritt 2.

**0 Treffer bei `fail2ban-regex`**

Das Logformat weicht vom Format „combined“ ab, oft steht der Hostname vor der IP-Adresse (Format „vhost_combined“). Dann passt das `^<HOST>` am Zeilenanfang nicht, der Ausdruck muss an das Format angepasst werden. Prüfen Sie zuerst eine echte Zeile des Logs.

**Eigenes Büro gesperrt**

Die feste IP-Adresse fehlt in `ignoreip`, oder mehrere Mitarbeiter nutzen dieselbe Adresse und einer vertippt sich wiederholt. Adresse freigeben und in `ignoreip` ergänzen.

## Häufige Fragen

### Ersetzt Fail2ban ein Plugin zur Begrenzung der Anmeldeversuche?

Es ergänzt es. Fail2ban arbeitet vor WordPress und entlastet den Server, sieht aber nur IP-Adressen und Statuscodes. Ein Plugin sieht Benutzernamen und kann etwa Konten sperren. Wie Sie Plugin, starke Passwörter und zweiten Faktor kombinieren, beschreibt die Anleitung [Brute-Force-Angriffe auf wp-login und XML-RPC abwehren](https://s-edv.com/anleitungen/wordpress-brute-force-wp-login-xmlrpc-abwehren).

### Funktioniert das auf Shared Hosting?

Nein. Fail2ban braucht Root-Rechte für Pakete und Firewall. Auf Shared Hosting übernimmt der Hoster solchen Schutz, fragen Sie dort nach einer Begrenzung für `wp-login.php`.

### Was ist mit verteilten Angriffen aus vielen Adressen?

Gegen ein Botnetz, das von jeder Adresse nur ein oder zwei Versuche schickt, wirkt Fail2ban kaum. Dagegen helfen starke Passwörter, ein zweiter Faktor und ein Passwortschutz vor `wp-login.php`.

### Werden IPv6-Adressen gesperrt?

Ja, Fail2ban 1.1.0 verarbeitet IPv6-Adressen.

## Fazit

Mit einem eigenen Filter, der den Statuscode 200 auf POST-Anfragen an `wp-login.php` und `xmlrpc.php` auswertet, sperrt Fail2ban wiederholte Anmeldeversuche, bevor sie PHP und die Datenbank belasten. Entscheidend sind die richtige Logdatei, die echte Besucher-IP im Log und ein Eintrag für das eigene Büro in `ignoreip`. Fail2ban ist eine Schutzschicht unter mehreren, starke Passwörter und aktuelle Plugins bleiben Pflicht. Wenn Updates, Backups und Firewall dauerhaft in festen Händen liegen sollen, übernimmt das die [WordPress-Wartung von Marcel Schönfelder](https://wordpressupdate.de/?utm_source=s-edv.com&utm_medium=fazit&utm_campaign=48).

## Weiterführende Anleitungen und Quellen

- [Brute-Force-Angriffe auf wp-login und XML-RPC abwehren](https://s-edv.com/anleitungen/wordpress-brute-force-wp-login-xmlrpc-abwehren)
- [XML-RPC deaktivieren oder einschränken](https://s-edv.com/anleitungen/wordpress-xml-rpc-deaktivieren-einschraenken)
- [Linux-Server absichern: UFW-Firewall und Fail2ban](https://s-edv.com/anleitungen/linux-server-absichern-ufw-fail2ban)
- [WordPress Advanced Administration: Brute Force Attacks](https://developer.wordpress.org/advanced-administration/security/brute-force/)
- [Fail2ban auf GitHub](https://github.com/fail2ban/fail2ban) und [jail.conf(5) in Debian Trixie](https://manpages.debian.org/trixie/fail2ban/jail.conf.5.en.html)
- [Apache mod_remoteip](https://httpd.apache.org/docs/2.4/mod/mod_remoteip.html) und [nginx realip-Modul](https://nginx.org/en/docs/http/ngx_http_realip_module.html)
