WordPress-Logs auswerten: Zugriffe, Fehler und Angriffe erkennen
So führen Sie Zugriffsprotokoll des Webservers und WordPress-Fehlerprotokoll zusammen, schützen debug.log vor fremdem Zugriff, erkennen Passwort-Angriffe und PHP-Fehler mit Standardbefehlen und erzeugen einen täglichen Kurzbericht.
Mit KI erstellt – redaktionelle Prüfung ausstehend
WerbelinksMit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Mehr dazu

Wenn eine WordPress-Website langsam wird, eine weiße Seite zeigt oder nachts tausende Anmeldeversuche abbekommt, steht die Antwort fast immer in einer Protokolldatei. Meist liegen die Protokolle aber an verschiedenen Stellen, und niemand schaut hinein. Diese Anleitung zeigt, wie Sie die Protokolle an einem festen Ort zusammenführen, sie mit wenigen Standardbefehlen lesen und daraus einen kurzen Bericht machen, der Zugriffe, Fehler und Angriffsmuster auf einen Blick zeigt.
Voraussetzungen
Die Befehle setzen einen Server voraus, auf dem Sie selbst Dateien lesen dürfen.
- WordPress: eine aktuelle Version, getestet mit WordPress 7.1.2.
- PHP: 7.4 oder neuer, empfohlen 8.3 oder 8.4.
- Webserver: Apache oder nginx unter Linux mit dem üblichen Protokollformat „combined“.
- Zugriff: SSH mit Leserechten auf die Logverzeichnisse, dazu Schreibzugriff auf die
wp-config.phpper SSH oder SFTP. - Rolle: Administrator der WordPress-Installation und Verantwortung für den Server.
- Backup: eine aktuelle Sicherung der
wp-config.php. Ein Tippfehler in dieser Datei legt die Website sofort lahm.
Schritt 1: Wissen, welches Protokoll was enthält
Jede Quelle beantwortet eine andere Frage:
| Protokoll | Typischer Ort | Beantwortet |
|---|---|---|
| Zugriffsprotokoll | /var/log/apache2/access.log bzw. /var/log/nginx/access.log | Wer hat wann welche Adresse aufgerufen, mit welchem Ergebnis? |
| Fehlerprotokoll Webserver | error.log im selben Ordner | Probleme des Webservers selbst |
| WordPress-Fehlerprotokoll | wp-content/debug.log oder eigener Pfad | PHP-Warnungen und schwere Fehler aus Core, Plugins und Themes |
| Aktivitätsprotokoll | Datenbank, per Plugin | Welcher Benutzer hat im Backend was geändert? |
Die Pfade gelten für Debian und Ubuntu. Anderswo verraten die Direktiven CustomLog (Apache) bzw. access_log (nginx) den Ort. Im offiziellen Docker-Image schreibt Apache auf die Standardausgabe, dort lesen Sie mit docker compose logs.
Das Aktivitätsprotokoll behandelt die Anleitung Aktivitätsprotokoll in WordPress einrichten.
Verifizieren: Führen Sie ls -la /var/log/apache2/ (bzw. /var/log/nginx/) aus. Sie sollten access.log und error.log sehen, dazu ältere, rotierte Dateien wie access.log.1 und access.log.2.gz.
Schritt 2: WordPress-Fehler in eine sichere Datei schreiben
Mit den Standardeinstellungen protokolliert WordPress keine eigenen Fehler. Die Konstante WP_DEBUG_LOG schaltet das ein, setzt aber WP_DEBUG voraus. Mit true landet es in wp-content/debug.log. Diese Datei ist über den Browser erreichbar: Im Test lieferte der Aufruf von /wp-content/debug.log ohne weitere Maßnahmen den Status 200 und den vollständigen Inhalt mit Dateipfaden des Servers. Laut WordPress-Dokumentation dürfen Sie statt true einen eigenen Dateipfad angeben. Nutzen Sie das und legen Sie die Datei außerhalb des Webverzeichnisses ab.
Ordner anlegen und dem PHP-Benutzer übergeben (auf Debian www-data):
sudo mkdir -p /var/log/wordpress
sudo chown www-data:www-data /var/log/wordpress
sudo chmod 750 /var/log/wordpress
Tragen Sie dann in die wp-config.php oberhalb der Zeile /* That's all, stop editing! */ ein:
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', '/var/log/wordpress/debug.log' );
define( 'WP_DEBUG_DISPLAY', false );
@ini_set( 'display_errors', 0 );
WP_DEBUG_DISPLAY auf false ist auf einer Live-Website Pflicht. Sonst sehen Besucher Warnungen mitten im Seiteninhalt. Dauerhaft eingeschaltet protokolliert WP_DEBUG auch harmlose Hinweise, die Datei wächst schneller. Gezieltes Debuggen zeigt die Anleitung WordPress Debug-Modus aktivieren und Error-Logs analysieren.
Können Sie auf Ihrem Hosting keinen Ordner außerhalb des Webverzeichnisses anlegen, sperren Sie die Datei wenigstens. Unter Apache genügt eine .htaccess im Ordner wp-content, sofern der Hoster AllowOverride erlaubt:
<Files "debug.log">
Require all denied
</Files>
Unter nginx gehört eine entsprechende Regel in den Server-Block:
location = /wp-content/debug.log {
deny all;
}
Verifizieren: Rufen Sie eine Seite der Website auf und prüfen Sie mit sudo ls -la /var/log/wordpress/, ob die Datei nach der ersten Meldung entsteht. Mit curl -I https://ihre-domain.de/wp-content/debug.log sollten Sie keinen Status 200 mehr erhalten. Im Test lieferte die Sperre per .htaccess den Status 403.
Schritt 3: Das Zugriffsprotokoll lesen
Eine Zeile im Format „combined“ sieht so aus:
203.0.113.7 - - [30/Sep/2026:20:36:37 +0000] "POST /wp-login.php HTTP/1.1" 200 10053 "-" "curl/8.14.1"
Von links nach rechts stehen dort IP-Adresse, zwei meist leere Felder, Zeitpunkt, Anfrage mit Methode und Pfad, Statuscode, Antwortgröße in Bytes, die verweisende Seite und die Kennung des Browsers. An Leerzeichen getrennt liegt die IP-Adresse im ersten Feld, die Methode im sechsten, der Pfad im siebten und der Statuscode im neunten.
Wie viele Anfragen endeten mit welchem Status? Die Befehle für IP-Adressen und Serverfehler folgen demselben Muster und stehen im Skript in Schritt 6.
awk '{print $9}' /var/log/apache2/access.log | sort | uniq -c | sort -rn
Ältere, bereits komprimierte Dateien lesen Sie mit zcat -f, das unkomprimierte und gepackte Dateien gleichermaßen verarbeitet:
zcat -f /var/log/apache2/access.log* | grep -c "POST /wp-login.php"
Steht ein Reverse Proxy oder CDN davor, sehen oft alle Besucher gleich aus. Die echte Adresse übernehmen mod_remoteip (Apache) bzw. das realip-Modul (nginx), die nur eigenen Proxys vertrauen dürfen. Das Apache-Format „vhost_combined“ verschiebt alle Felder um eine Position. Prüfen Sie deshalb eine echte Zeile, bevor Sie Feldnummern übernehmen.
Verifizieren: Rufen Sie Ihre Startseite einmal im Browser auf und suchen Sie mit grep "IHRE-IP" /var/log/apache2/access.log | tail -3 nach Ihrer eigenen Adresse. Die letzte Zeile sollte Ihren Aufruf mit Status 200 zeigen.
Schritt 4: Angriffsmuster erkennen
Automatisierte Angriffe hinterlassen deutliche Spuren im Zugriffsprotokoll.
Fehlgeschlagene Anmeldungen: WordPress beantwortet eine falsche Anmeldung auf wp-login.php mit Status 200, weil es das Formular samt Fehlermeldung erneut ausliefert. Eine erfolgreiche Anmeldung leitet mit Status 302 ins Backend weiter. Viele POST-Anfragen mit Status 200 von derselben Adresse deuten daher auf einen Passwort-Angriff hin:
awk '$6 == "\"POST" && $7 ~ /^\/wp-login\.php/ && $9 == 200 {print $1}' /var/log/apache2/access.log | sort | uniq -c | sort -rn | head
XML-RPC: Die Schnittstelle xmlrpc.php antwortet auch bei falschen Zugangsdaten mit Status 200, weil der Fehler im Inhalt der Antwort steht. Im Test kam so die Meldung „Der Benutzername oder das Passwort ist falsch.“ zurück. Nutzen Sie keine XML-RPC-Dienste wie die Jetpack-App, ist jede POST-Anfrage darauf verdächtig. Der Tagesbericht zählt sie.
Suche nach vergessenen Dateien: Scanner fragen nach Pfaden wie /.env, /wp-config.php.bak, /phpmyadmin/ oder /wp-content/debug.log:
grep -E '\.env|\.bak|\.sql|phpmyadmin|debug\.log' /var/log/apache2/access.log | awk '{print $1, $7, $9}'
Verlassen Sie sich dabei nicht allein auf den Statuscode. Im Test antwortete WordPress auf nicht vorhandene Pfade mit Weiterleitung (301) oder sogar mit 200 und der Startseite. Entspricht die Antwortgröße Ihrer Startseite, hat der Scanner nichts bekommen.
Benutzernamen ausspähen: Anfragen wie /?author=1 oder /wp-json/wp/v2/users sammeln Anmeldenamen.
Wiederkehrende Angreifer sperren Sie automatisch, wie die Anleitung fail2ban für wp-login und XML-RPC zeigt.
Verifizieren: Melden Sie sich einmal absichtlich mit einem falschen Passwort an. Der Befehl für fehlgeschlagene Anmeldungen sollte Ihre IP-Adresse mit mindestens einem Treffer zeigen.
Schritt 5: PHP-Fehler bündeln und einordnen
Dieselbe Meldung steht oft hunderte Male im Protokoll. Ohne Zeitstempel gezählt, sehen Sie sofort den Hauptverursacher:
grep -E 'PHP (Fatal error|Warning|Parse error)' /var/log/wordpress/debug.log | sed -E 's/^\[[^]]+\] //' | sort | uniq -c | sort -rn | head
Eine typische Ausgabe aus dem Test sah so aus:
1 PHP Fatal error: Uncaught Error: Call to undefined function nicht_vorhanden() in /var/www/html/wp-content/mu-plugins/logtest2.php:1
1 PHP Warning: Undefined variable $undefiniert in /var/www/html/wp-content/mu-plugins/logtest.php on line 1
Der Pfad hinter „in“ verrät den Verursacher. Liegt er unter wp-content/plugins/NAME/, ist es das Plugin NAME, unter wp-content/themes/ das Theme. Ein „Fatal error“ bricht die Seite ab, im Zugriffsprotokoll steht zur selben Minute ein Status 500. So ordnen Sie die Meldung „Es gab einen kritischen Fehler auf dieser Website“ einer Ursache zu. Warnungen und „Deprecated“-Hinweise stören meist nicht, kündigen aber Probleme beim nächsten PHP-Update an.
Verifizieren: Der Befehl sollte eine nach Häufigkeit sortierte Liste liefern. Bleibt sie trotz Fehlern leer, siehe „Typische Fehler“.
Schritt 6: Einen Tagesbericht erzeugen
Fassen Sie die Befehle in /usr/local/bin/wp-logbericht zusammen:
#!/bin/sh
# wp-logbericht: Kurzbericht aus Apache-Zugriffslog und WordPress-debug.log
ACCESS=${ACCESS:-/var/log/apache2/access.log}
DEBUG=${DEBUG:-/var/log/wordpress/debug.log}
echo "== Anfragen je Statuscode"
awk '{print $9}' "$ACCESS" | sort | uniq -c | sort -rn
echo "== Top 10 IP-Adressen"
awk '{print $1}' "$ACCESS" | sort | uniq -c | sort -rn | head -10
echo "== Fehlgeschlagene Anmeldungen (POST wp-login.php mit Status 200)"
awk '$6 == "\"POST" && $7 ~ /^\/wp-login\.php/ && $9 == 200 {print $1}' "$ACCESS" | sort | uniq -c | sort -rn | head -10
echo "== POST auf xmlrpc.php"
grep -c 'POST /xmlrpc.php' "$ACCESS"
echo "== Serverfehler (5xx)"
awk '$9 ~ /^5/ {print $4, $7}' "$ACCESS" | tail -10
echo "== Häufigste PHP-Meldungen"
grep -E 'PHP (Fatal error|Warning|Parse error)' "$DEBUG" | sed -E 's/^\[[^]]+\] //' | sort | uniq -c | sort -rn | head -10
Ausführbar machen und testen, bei nginx mit anderem Pfad:
sudo chmod +x /usr/local/bin/wp-logbericht
sudo wp-logbericht
sudo ACCESS=/var/log/nginx/access.log wp-logbericht
Täglich per Cron in /etc/cron.d/wp-logbericht:
55 23 * * * root /usr/local/bin/wp-logbericht > /var/log/wordpress/bericht-$(date +\%F).txt 2>&1
Das Prozentzeichen muss in Cron maskiert sein, sonst bricht die Zeile ab. Planen Sie für die Durchsicht einen festen Termin ein. Wer diese Durchsicht zusammen mit Updates und Sicherungen nicht selbst im Kalender halten möchte, kann die laufende Pflege abgeben: Die WordPress-Wartung von wordpressupdate.de spielt Updates von WordPress, Plugins und Themes mit Kompatibilitätsprüfung ein, sichert die Website wöchentlich auf externen Speicher und richtet eine Firewall ein, die viele der hier sichtbaren Angriffe abfängt.
Verifizieren: sudo wp-logbericht sollte alle sechs Abschnitte ausgeben. Am Tag nach dem Eintrag in Cron liegt eine Datei bericht-JJJJ-MM-TT.txt in /var/log/wordpress/.
Schritt 7: Rotation und Aufbewahrung festlegen
Die Webserver-Pakete von Debian und Ubuntu bringen bereits eine Regel für logrotate mit. Im Test rotierte die Apache-Vorlage täglich, bewahrte 14 Dateien auf und komprimierte ältere Stände. Das eigene debug.log kennt logrotate dagegen nicht, es wächst ohne Grenze. Legen Sie dafür /etc/logrotate.d/wordpress an:
/var/log/wordpress/*.log {
weekly
rotate 4
compress
missingok
notifempty
copytruncate
}
copytruncate kopiert die Datei und leert das Original, statt sie zu verschieben. So schreibt PHP ohne Neustart weiter. Alte Berichte räumt find /var/log/wordpress -name 'bericht-*.txt' -mtime +30 -delete per Cron auf.
Die Aufbewahrungsdauer ist auch eine Datenschutzfrage. Dynamische IP-Adressen können laut EuGH (Urteil C-582/14 vom 19. Oktober 2016) personenbezogene Daten sein. Speichern Sie Zugriffsprotokolle nur so lange, wie Sie sie für Sicherheit und Fehlersuche brauchen, und nennen Sie diese Dauer in der Datenschutzerklärung. Mehr dazu in der Anleitung DSGVO-Löschpflichten für Backups und Logfiles.
Verifizieren: sudo logrotate -d /etc/logrotate.d/wordpress führt einen Probelauf ohne Änderungen aus und zeigt, welche Dateien rotiert würden.
Typische Fehler
- Die Datei
debug.logentsteht nicht:WP_DEBUGsteht auffalse, oder der PHP-Benutzer darf nicht in den Zielordner schreiben. Prüfen Sie mitls -ld /var/log/wordpress, dass der Ordnerwww-datagehört. debug.logist öffentlich abrufbar: Das passiert beiWP_DEBUG_LOGauftrueohne Sperre. Eigenen Pfad außerhalb des Webverzeichnisses wählen oder die Sperre aus Schritt 2 setzen.- Alle Zugriffe kommen von derselben IP-Adresse: Ein Proxy oder CDN steht davor, und die echte Adresse wird nicht übernommen.
mod_remoteipbzw. das realip-Modul von nginx einrichten. - Protokoll im Docker-Container leer: Im offiziellen Image zeigen die Dateien auf die Standardausgabe, lesen Sie mit
docker compose logs. - Permission denied beim Lesen: Die Dateien gehören
rootund der Gruppeadm. Befehle mitsudoausführen oder den eigenen Benutzer der Gruppeadmhinzufügen.
Häufige Fragen
Brauche ich dafür ein Log-Plugin in WordPress?
Nein. Die Protokolle des Webservers entstehen ohnehin, und WordPress schreibt Fehler mit einer Konstante in der wp-config.php. Plugins lohnen sich für das Aktivitätsprotokoll im Backend.
Mein Hoster bietet keinen SSH-Zugang. Was nun?
Viele Hoster stellen die Zugriffs- und Fehlerprotokolle im Kundenmenü zum Download bereit. Die Befehle laufen dann auf Ihrem Rechner, unter Windows etwa im Windows-Subsystem für Linux.
Wann brauche ich ein zentrales Log-System wie Graylog oder OpenObserve?
Sobald Sie mehrere Websites oder Server betreuen und Protokolle über Wochen durchsuchen wollen. Für eine einzelne Website reicht der Tagesbericht.
Testumfang
Wir haben die Anleitung auf einer Testinstallation mit WordPress 7.1.2 unter Apache durchgespielt und das Skript gegen die dabei entstandenen Protokolle laufen lassen. Auffällig war, dass WordPress auf nicht vorhandene Pfade je nach Permalink-Einstellung mit einer Weiterleitung oder der Startseite antwortet, deshalb verweisen wir zusätzlich auf die Antwortgröße.
Die nginx-Regeln sowie Logrotation und Cron-Eintrag haben wir nicht auf einem echten Server ausgeführt. Prüfen Sie diese Teile deshalb nach dem Einrichten mit den genannten Probeläufen.
Fazit
Mit einem geschützten Fehlerprotokoll, einer Handvoll Standardbefehlen und einem kurzen Tagesbericht wissen Sie, was auf Ihrer Website passiert, ohne zusätzliche Software zu installieren. Wichtig sind regelmäßige Durchsicht und kurze Aufbewahrung. Soll sich jemand anderes um Updates, Sicherungen und Firewall kümmern, übernimmt das die WordPress-Wartung von Marcel Schönfelder.
Weiterführende Anleitungen und Quellen
- WordPress Debug-Modus aktivieren: Error-Logs analysieren und Fehler selbst beheben
- WordPress-Firewall auf Serverebene: fail2ban für wp-login und XML-RPC
- Aktivitätsprotokoll in WordPress: Änderungen von Benutzern nachvollziehen
- DSGVO-Löschpflichten und Backups: Praxis-Leitfaden für Admins
- WordPress Developer Resources: Debugging in WordPress
- Apache HTTP Server 2.4: Log Files
- nginx: Module ngx_http_log_module


