fail2ban is installed for SSH and left there, but the same brute force runs against every HTTP login on the box — a WordPress admin, a staging basic-auth prompt, an API token endpoint. The filters ship with the package; the jails are simply not enabled.
# /etc/fail2ban/jail.local
[nginx-http-auth]
enabled = true
filter = nginx-http-auth
logpath = /var/log/nginx/error.log
maxretry = 5
findtime = 600
bantime = 3600
Put changes in jail.local, never jail.conf — the package overwrites the latter on upgrade. findtime is the window the retries must fall inside, and it is the parameter people forget: five attempts in ten minutes is a brute force, five over a week is someone who forgot their password. Behind a proxy or CDN, the log must contain the real client address or the jail will ban the proxy.