- fail2ban-digest-mode-fleet: recidive-only email model, sshd now silent, defaults-debian.conf gotcha added - netdata-docker-health-alarm-tuning: 30m/10m config, tuning history table - New: wp-fail2ban-logpath-debian-ubuntu, lora-adapter-gguf-conversion-fails, tailscale-status-json-hostname-localhost-ios - Various article updates and nav index refreshes Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
5.2 KiB
| title | domain | category | tags | status | created | updated | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| wp-fail2ban Plugin Logpath on Debian/Ubuntu (auth.log, not syslog) | selfhosting | security |
|
published | 2026-04-30 | 2026-04-30 |
wp-fail2ban Plugin Logpath on Debian/Ubuntu (auth.log, not syslog)
The Problem
You install the WP fail2ban WordPress plugin, configure the fleet-standard wordpress-hard, wordpress-soft, and wordpress-extra jails, and… nothing. Weeks pass. fail2ban-client status wordpress-hard reports Total failed: 0, Total banned: 0. Your site is being attacked, but the jails are dead.
Meanwhile the wordpress-login jail (which reads Apache access logs for POST /wp-login.php directly) is happily catching brute-forcers. So the problem isn't fail2ban itself — it's specifically the wp-fail2ban-plugin-derived jails.
The Cause
The wp-fail2ban plugin emits events via PHP's syslog() call with facility LOG_AUTH. On Debian/Ubuntu, rsyslog routes the auth facility to /var/log/auth.log, NOT /var/log/syslog. On RHEL/Fedora it's /var/log/secure.
A lot of tutorials, ansible-galaxy roles, and copy-paste config snippets specify:
logpath = /var/log/syslog
That's wrong on Debian/Ubuntu. The events never land there, so the filter regex has nothing to match, so the jail catches zero events forever. Silently.
Diagnostic Steps
If a wordpress-{hard,soft,extra} jail shows Total failed: 0 over a long window despite the plugin being active and the site getting attacked:
1. Check what the jail thinks it's watching:
sudo fail2ban-client status wordpress-hard | grep "File list"
2. Check where wp-fail2ban events actually land:
sudo grep -c "wordpress(" /var/log/auth.log /var/log/syslog /var/log/secure 2>/dev/null
You'll see something like:
/var/log/auth.log:314
/var/log/syslog:0
3. If the jail's File list ≠ the file with events, fix the logpath.
A real event line on Debian/Ubuntu looks like:
2026-04-18T23:28:21.027004-04:00 hostname wordpress(example.com)[719989]: XML-RPC authentication failure for someone from 1.2.3.4
The wordpress(domain)[pid] syslog tag is the giveaway — those are wp-fail2ban events.
The Fix
Edit the jail blocks in /etc/fail2ban/jail.local (or your Ansible source for the jail) and set:
[wordpress-hard]
enabled = true
port = http,https
filter = wordpress-hard
logpath = /var/log/auth.log
maxretry = 1
findtime = 60
bantime = 30d
backend = polling
[wordpress-soft]
enabled = true
port = http,https
filter = wordpress-soft
logpath = /var/log/auth.log
maxretry = 5
findtime = 60
bantime = 30d
backend = polling
[wordpress-extra]
enabled = true
port = http,https
filter = wordpress-extra
logpath = /var/log/auth.log
maxretry = 5
findtime = 60
bantime = 30d
backend = polling
Then:
sudo fail2ban-client -t # validate
sudo fail2ban-client reload
sudo fail2ban-client status wordpress-hard | grep "File list"
# should now show /var/log/auth.log
Verification
You can prove the filter regex actually matches your real events without waiting for an attack — run fail2ban-regex against the rotated log:
sudo fail2ban-regex /var/log/auth.log.1 /etc/fail2ban/filter.d/wordpress-hard.conf | grep -E "Failregex:|Lines:"
Healthy output looks like:
Failregex: 81 total
Lines: 13008 lines, 0 ignored, 81 matched, 12927 missed
If you see Failregex: 0 total, the filter regex doesn't match what the plugin actually emits — which is a different bug (filter version skew vs. plugin version), not the logpath gotcha. Investigate /etc/fail2ban/filter.d/wordpress-{hard,soft}.conf against actual event lines.
Note: On a freshly-fixed jail, counters will sit at
Total failed: 0for a while — thepollingbackend starts at the file's current EOF, so old events aren't retroactively counted. New events from the moment ofreloadonward will accumulate. Allow a few days of normal attack traffic before declaring the fix broken.
Distribution Cheat Sheet
| Distro family | wp-fail2ban events land in |
|---|---|
| Debian / Ubuntu | /var/log/auth.log |
| RHEL / CentOS / Fedora | /var/log/secure |
| systemd-journal-only systems | journalctl SYSLOG_FACILITY=4 (use backend = systemd + journalmatch = SYSLOG_FACILITY=4) |
If you have a mixed fleet, parameterize the path:
# Ansible vars
wp_fail2ban_log_path: "{{ '/var/log/auth.log' if ansible_os_family == 'Debian' else '/var/log/secure' }}"
Why wordpress-login Is Unaffected
The wordpress-login jail is a different beast — it reads /var/log/apache2/access.log directly and matches ^<HOST> -.*"POST /wp-login.php via the wordpress-login filter. No plugin involved, no syslog facility involved. So a host can have wordpress-login working perfectly while wordpress-{hard,soft,extra} are silently dead. Don't let a healthy wordpress-login reassure you that the rest of the wp-fail2ban stack is also fine.
Related
- fail2ban-wordpress-login-jail — the access-log layer that catches WP brute force without any plugin dependency
- fail2ban-apache-bad-request-jail
- fail2ban-apache-php-probe-jail
- clamav-fleet-deployment